@ethlete/query 6.0.0-next.24 → 6.0.0-next.26
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/CHANGELOG.md +29 -0
- package/fesm2022/ethlete-query-testing.mjs +46 -1
- package/fesm2022/ethlete-query-testing.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +427 -47
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/package.json +1 -5
- package/types/ethlete-query-testing.d.ts +42 -3
- package/types/ethlete-query.d.ts +236 -29
|
@@ -10,7 +10,6 @@ import { validateAsync, form } from '@angular/forms/signals';
|
|
|
10
10
|
import * as i1 from '@angular/forms';
|
|
11
11
|
import { FormControl, ReactiveFormsModule, FormGroup } from '@angular/forms';
|
|
12
12
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
13
|
-
import { io } from 'socket.io-client';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Turns the features applied at creation into their devtools representation.
|
|
@@ -104,6 +103,20 @@ const setQueryDevtoolsFormLinksFactory = (fn) => {
|
|
|
104
103
|
* @internal
|
|
105
104
|
*/
|
|
106
105
|
const createQueryDevtoolsFormLinksRecorder = () => formLinksFactory?.() ?? null;
|
|
106
|
+
let overridesFactory = null;
|
|
107
|
+
/**
|
|
108
|
+
* Installs the overrides recorder factory. Called by `provideQueryDevtools()`; nothing else may call it.
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
const setQueryDevtoolsOverridesFactory = (fn) => {
|
|
112
|
+
overridesFactory = fn;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* An overrides recorder for one query, or `null` unless {@link provideQueryDevtools} has been called.
|
|
116
|
+
* Reached only from the provider for the same reason {@link createQueryDevtoolsStatsRecorder} is.
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
const createQueryDevtoolsOverridesRecorder = () => overridesFactory?.() ?? null;
|
|
107
120
|
/** The ids of the query forms read by the args build currently running, or `null` outside of one. */
|
|
108
121
|
let formLinkSink = null;
|
|
109
122
|
/**
|
|
@@ -277,6 +290,10 @@ const QueryRuntimeErrorCode = {
|
|
|
277
290
|
QUERY_SEQUENCE_ALREADY_RUNNING: 900,
|
|
278
291
|
// Legacy interop
|
|
279
292
|
LEGACY_PREPARE_WITHOUT_INJECTION_CONTEXT: 950,
|
|
293
|
+
LEGACY_QUERY_STATE_ALREADY_HAS_KEY: 951,
|
|
294
|
+
LEGACY_QUERY_STATE_DOES_NOT_CONTAIN_KEY: 952,
|
|
295
|
+
LEGACY_QUERY_STATE_CANNOT_TRANSFORM: 953,
|
|
296
|
+
LEGACY_INVALID_BODY: 954,
|
|
280
297
|
};
|
|
281
298
|
const queryFeatureUsedMultipleTimes = (type) => {
|
|
282
299
|
return new RuntimeError(QueryRuntimeErrorCode.QUERY_FEATURE_USED_MULTIPLE_TIMES, `The query feature "${type}()" was used multiple times.`);
|
|
@@ -708,7 +725,10 @@ const withPageResetOnError = (options) => {
|
|
|
708
725
|
const setupQueryState = (options) => {
|
|
709
726
|
const request = signal(null, /* @ts-ignore */
|
|
710
727
|
...(ngDevMode ? [{ debugName: "request" }] : /* istanbul ignore next */ []));
|
|
711
|
-
const rawResponse = linkedSignal(() =>
|
|
728
|
+
const rawResponse = linkedSignal(() => {
|
|
729
|
+
const raw = request()?.response() ?? null;
|
|
730
|
+
return options.devtoolsOverrides ? options.devtoolsOverrides.apply(raw) : raw;
|
|
731
|
+
}, /* @ts-ignore */
|
|
712
732
|
...(ngDevMode ? [{ debugName: "rawResponse" }] : /* istanbul ignore next */ []));
|
|
713
733
|
const response = computed(() => {
|
|
714
734
|
const raw = rawResponse();
|
|
@@ -974,10 +994,12 @@ const createBaseQuery = (options) => {
|
|
|
974
994
|
return runInInjectionContext(deps.injector, () => {
|
|
975
995
|
const devtoolsStats = createQueryDevtoolsStatsRecorder();
|
|
976
996
|
const devtoolsFormLinks = createQueryDevtoolsFormLinksRecorder();
|
|
997
|
+
const devtoolsOverrides = createQueryDevtoolsOverridesRecorder();
|
|
977
998
|
const state = setupQueryState({
|
|
978
999
|
transformResponse: options.creator?.transformResponse,
|
|
979
1000
|
devtoolsStats,
|
|
980
1001
|
devtoolsFormLinks,
|
|
1002
|
+
devtoolsOverrides,
|
|
981
1003
|
});
|
|
982
1004
|
const flags = getQueryFeatureUsage(options);
|
|
983
1005
|
const execute = options.executeFactory({
|
|
@@ -1001,7 +1023,7 @@ const createBaseQuery = (options) => {
|
|
|
1001
1023
|
if (devtoolsStats) {
|
|
1002
1024
|
const statsSubscription = state.events$.subscribe((event) => {
|
|
1003
1025
|
if (event.type === 'error') {
|
|
1004
|
-
devtoolsStats.recordError();
|
|
1026
|
+
devtoolsStats.recordError({ faulted: event.faulted });
|
|
1005
1027
|
}
|
|
1006
1028
|
else if (event.type === HttpEventType.Response) {
|
|
1007
1029
|
devtoolsStats.recordResponse({ headers: event.headers, body: event.body });
|
|
@@ -1022,6 +1044,7 @@ const createBaseQuery = (options) => {
|
|
|
1022
1044
|
clientRef: client,
|
|
1023
1045
|
stats: devtoolsStats,
|
|
1024
1046
|
formLinks: devtoolsFormLinks ?? undefined,
|
|
1047
|
+
overrides: devtoolsOverrides ?? undefined,
|
|
1025
1048
|
route: options.creatorInternals.route ??
|
|
1026
1049
|
options.creator?.route ??
|
|
1027
1050
|
null,
|
|
@@ -1195,17 +1218,15 @@ const createBaseQueryCreator = (config) => {
|
|
|
1195
1218
|
* Route building, query-string serialization and the token clock - shared by the current generation and
|
|
1196
1219
|
* the legacy V2 client, which re-exports them under their original names.
|
|
1197
1220
|
*/
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
const
|
|
1207
|
-
const invalidRouteError = (data) => new QueryError('002', 'The route must start with a slash', data);
|
|
1208
|
-
const pathParamsMissingInRouteFunctionError = (data) => new QueryError('003', 'The route is a function but pathParams are missing', data);
|
|
1221
|
+
// codes 1-99 of the shared 0-999 `@ethlete/query` range - see `query-errors.ts` for the rest
|
|
1222
|
+
const RouteRuntimeErrorCode = {
|
|
1223
|
+
INVALID_BASE_ROUTE: 1,
|
|
1224
|
+
INVALID_ROUTE: 2,
|
|
1225
|
+
PATH_PARAMS_MISSING_IN_ROUTE_FUNCTION: 3,
|
|
1226
|
+
};
|
|
1227
|
+
const invalidBaseRouteError = (data) => new RuntimeError(RouteRuntimeErrorCode.INVALID_BASE_ROUTE, 'The baseRoute must not end with a slash', data);
|
|
1228
|
+
const invalidRouteError = (data) => new RuntimeError(RouteRuntimeErrorCode.INVALID_ROUTE, 'The route must start with a slash', data);
|
|
1229
|
+
const pathParamsMissingInRouteFunctionError = (data) => new RuntimeError(RouteRuntimeErrorCode.PATH_PARAMS_MISSING_IN_ROUTE_FUNCTION, 'The route is a function but pathParams are missing', data);
|
|
1209
1230
|
const isNaN$1 = (value) => typeof value === 'number' && Number.isNaN(value);
|
|
1210
1231
|
const isEmptyString = (value) => typeof value === 'string' && value.trim() === '';
|
|
1211
1232
|
const buildQueryString = (params, config) => {
|
|
@@ -1524,6 +1545,11 @@ const createHttpRequest = (options) => {
|
|
|
1524
1545
|
...(ngDevMode ? [{ debugName: "attempts" }] : /* istanbul ignore next */ []));
|
|
1525
1546
|
const retryState = signal(null, /* @ts-ignore */
|
|
1526
1547
|
...(ngDevMode ? [{ debugName: "retryState" }] : /* istanbul ignore next */ []));
|
|
1548
|
+
const lastDurationMs = signal(null, /* @ts-ignore */
|
|
1549
|
+
...(ngDevMode ? [{ debugName: "lastDurationMs" }] : /* istanbul ignore next */ []));
|
|
1550
|
+
// Set at the top of every `sendWithFaults` attempt (including unfaulted ones), so it always reflects
|
|
1551
|
+
// whichever attempt most recently settled - not just the first one, or a stale earlier attempt's fault.
|
|
1552
|
+
let lastAttemptFaulted = false;
|
|
1527
1553
|
// NOTE: This must be a plain function, not a `computed`. The freshness check compares against
|
|
1528
1554
|
// `Date.now()`, which is not reactive, so a memoized computed would only ever recompute when
|
|
1529
1555
|
// `expiresIn` changes - once it evaluated to `false` (fresh) it would stay `false` forever, even
|
|
@@ -1572,6 +1598,7 @@ const createHttpRequest = (options) => {
|
|
|
1572
1598
|
method: options.method,
|
|
1573
1599
|
url: options.fullPath,
|
|
1574
1600
|
});
|
|
1601
|
+
lastAttemptFaulted = !!fault && fault.status !== null;
|
|
1575
1602
|
if (!fault)
|
|
1576
1603
|
return send(headers);
|
|
1577
1604
|
const { status } = fault;
|
|
@@ -1621,6 +1648,7 @@ const createHttpRequest = (options) => {
|
|
|
1621
1648
|
currentStreamSubscription.unsubscribe();
|
|
1622
1649
|
lastExecuteTime.set(Date.now());
|
|
1623
1650
|
lastLoadEventTime.set(lastExecuteTime());
|
|
1651
|
+
lastLoadEventAmount.set(0);
|
|
1624
1652
|
loading.set({
|
|
1625
1653
|
executeTime: lastExecuteTime(),
|
|
1626
1654
|
progress: null,
|
|
@@ -1653,6 +1681,7 @@ const createHttpRequest = (options) => {
|
|
|
1653
1681
|
{
|
|
1654
1682
|
loading.set(null);
|
|
1655
1683
|
response.set(event.body);
|
|
1684
|
+
lastDurationMs.set(Date.now() - lastExecuteTime());
|
|
1656
1685
|
const expiresInSeconds = options.cacheAdapter
|
|
1657
1686
|
? options.cacheAdapter(event.headers)
|
|
1658
1687
|
: extractExpiresInSeconds(event.headers);
|
|
@@ -1681,7 +1710,8 @@ const createHttpRequest = (options) => {
|
|
|
1681
1710
|
const errorRes = createQueryErrorResponse(errorResponse);
|
|
1682
1711
|
error.set(errorRes);
|
|
1683
1712
|
loading.set(null);
|
|
1684
|
-
|
|
1713
|
+
lastDurationMs.set(Date.now() - lastExecuteTime());
|
|
1714
|
+
const errorEvent = { type: 'error', error: errorRes, faulted: lastAttemptFaulted };
|
|
1685
1715
|
currentEvent.set(errorEvent);
|
|
1686
1716
|
event$.next(errorEvent);
|
|
1687
1717
|
options.dependencies.ngErrorHandler.handleError(errorRes.raw);
|
|
@@ -1705,15 +1735,21 @@ const createHttpRequest = (options) => {
|
|
|
1705
1735
|
const elapsedTimeSinceLastEvent = currentTime - lastLoadEventTime();
|
|
1706
1736
|
const elapsedTimeSinceLastExecute = currentTime - lastExecuteTime();
|
|
1707
1737
|
const loadedAmount = event.loaded - lastLoadEventAmount();
|
|
1738
|
+
// An event in the same millisecond as the last one, or one that carries no new bytes, has no rate
|
|
1739
|
+
// to report - dividing by either zero yields Infinity or NaN. Such an event also keeps the
|
|
1740
|
+
// baseline where it is, so the next one measures across the wider window instead of restarting.
|
|
1741
|
+
const isMeasurable = elapsedTimeSinceLastEvent > 0 && loadedAmount > 0;
|
|
1708
1742
|
// We only want to calculate speed and remaining time after 2 seconds of the execution
|
|
1709
1743
|
// This is to avoid showing incorrect speed and remaining time when the request is very fast
|
|
1710
|
-
if (elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
1711
|
-
const
|
|
1712
|
-
progress.speed =
|
|
1713
|
-
progress.remainingTime = Math.round((event.total - event.loaded) /
|
|
1744
|
+
if (isMeasurable && elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
1745
|
+
const bytesPerSecond = (loadedAmount / elapsedTimeSinceLastEvent) * 1000;
|
|
1746
|
+
progress.speed = bytesPerSecond;
|
|
1747
|
+
progress.remainingTime = Math.round((event.total - event.loaded) / bytesPerSecond) * 1000;
|
|
1748
|
+
}
|
|
1749
|
+
if (isMeasurable) {
|
|
1750
|
+
lastLoadEventTime.set(currentTime);
|
|
1751
|
+
lastLoadEventAmount.set(event.loaded);
|
|
1714
1752
|
}
|
|
1715
|
-
lastLoadEventTime.set(currentTime);
|
|
1716
|
-
lastLoadEventAmount.set(event.loaded);
|
|
1717
1753
|
loading.set(state);
|
|
1718
1754
|
};
|
|
1719
1755
|
const lastExternalResponseAt = signal(null, /* @ts-ignore */
|
|
@@ -1752,6 +1788,7 @@ const createHttpRequest = (options) => {
|
|
|
1752
1788
|
resolveHeaders,
|
|
1753
1789
|
attempts: attempts.asReadonly(),
|
|
1754
1790
|
retryState: retryState.asReadonly(),
|
|
1791
|
+
lastDurationMs: lastDurationMs.asReadonly(),
|
|
1755
1792
|
},
|
|
1756
1793
|
};
|
|
1757
1794
|
return httpRequest;
|
|
@@ -4219,7 +4256,7 @@ const deriveExecutionStateType = (builder, triggeredBy) => {
|
|
|
4219
4256
|
return 'revocation';
|
|
4220
4257
|
return builder.key;
|
|
4221
4258
|
};
|
|
4222
|
-
const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, latestNonInternalQuery,
|
|
4259
|
+
const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, latestNonInternalQuery, applyTokens, executionState) => {
|
|
4223
4260
|
const queries = {};
|
|
4224
4261
|
const querySnapshots = new Map();
|
|
4225
4262
|
for (const builder of builders) {
|
|
@@ -4237,7 +4274,7 @@ const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, lates
|
|
|
4237
4274
|
if (response && !loading && !error) {
|
|
4238
4275
|
try {
|
|
4239
4276
|
const tokens = extractTokens(response);
|
|
4240
|
-
|
|
4277
|
+
applyTokens(tokens.accessToken, tokens.refreshToken);
|
|
4241
4278
|
}
|
|
4242
4279
|
catch (extractError) {
|
|
4243
4280
|
if (isDevMode()) {
|
|
@@ -4370,12 +4407,19 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
4370
4407
|
...(ngDevMode ? [{ debugName: "latestNonInternalQuery" }] : /* istanbul ignore next */ []));
|
|
4371
4408
|
const executionState = signal(null, /* @ts-ignore */
|
|
4372
4409
|
...(ngDevMode ? [{ debugName: "executionState" }] : /* istanbul ignore next */ []));
|
|
4373
|
-
const
|
|
4410
|
+
const applyTokens = (access, refresh) => {
|
|
4374
4411
|
accessToken.set(access);
|
|
4375
4412
|
refreshToken.set(refresh);
|
|
4376
4413
|
afterTokenRefresh$.next();
|
|
4377
4414
|
};
|
|
4378
|
-
|
|
4415
|
+
// Public entry point only - a query-driven login already reports its own, more specific
|
|
4416
|
+
// executionState (e.g. `{ type: 'login', state: 'success' }`) via setupBearerQueryRegistry's
|
|
4417
|
+
// execute(), so that internal path calls applyTokens directly to avoid stomping it with this.
|
|
4418
|
+
const setTokens = (access, refresh) => {
|
|
4419
|
+
applyTokens(access, refresh);
|
|
4420
|
+
executionState.set({ type: 'tokenSeed', state: 'success' });
|
|
4421
|
+
};
|
|
4422
|
+
const { queries } = setupBearerQueryRegistry(config.queries, injector, latestExecutedQuery, latestNonInternalQuery, applyTokens, executionState);
|
|
4379
4423
|
const logout = () => {
|
|
4380
4424
|
accessToken.set(null);
|
|
4381
4425
|
refreshToken.set(null);
|
|
@@ -5404,6 +5448,325 @@ const createQueryDevtoolsFormLinks = () => {
|
|
|
5404
5448
|
};
|
|
5405
5449
|
};
|
|
5406
5450
|
|
|
5451
|
+
const pathsEqual = (a, b) => a.length === b.length && a.every((step, index) => step === b[index]);
|
|
5452
|
+
/**
|
|
5453
|
+
* Walks `path` into `root`, stopping as soon as a step's container doesn't exist. An empty path
|
|
5454
|
+
* resolves to `root` itself, which is how an op targets the response's top-level value.
|
|
5455
|
+
*/
|
|
5456
|
+
const resolvePath = (root, path) => {
|
|
5457
|
+
if (path.length === 0)
|
|
5458
|
+
return { ok: true, exists: true, value: root };
|
|
5459
|
+
let current = root;
|
|
5460
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
5461
|
+
if (current === null || typeof current !== 'object')
|
|
5462
|
+
return { ok: false };
|
|
5463
|
+
const step = path[index];
|
|
5464
|
+
const container = current;
|
|
5465
|
+
if (!(step in container))
|
|
5466
|
+
return { ok: false };
|
|
5467
|
+
current = container[step];
|
|
5468
|
+
}
|
|
5469
|
+
if (current === null || typeof current !== 'object')
|
|
5470
|
+
return { ok: false };
|
|
5471
|
+
const key = path[path.length - 1];
|
|
5472
|
+
const container = current;
|
|
5473
|
+
const exists = key in container;
|
|
5474
|
+
return { ok: true, exists, value: exists ? container[key] : undefined };
|
|
5475
|
+
};
|
|
5476
|
+
/**
|
|
5477
|
+
* Returns a copy of `root` with `value` written at `path`, cloning only the containers along the way -
|
|
5478
|
+
* every sibling branch keeps its original reference. The final path segment does not need to already
|
|
5479
|
+
* exist (a `set` can add a new key); every segment before it does.
|
|
5480
|
+
*/
|
|
5481
|
+
const withValueAtPath = (root, path, value) => {
|
|
5482
|
+
if (path.length === 0)
|
|
5483
|
+
return value;
|
|
5484
|
+
const [head, ...rest] = path;
|
|
5485
|
+
if (Array.isArray(root)) {
|
|
5486
|
+
const next = [...root];
|
|
5487
|
+
next[head] = withValueAtPath(root[head], rest, value);
|
|
5488
|
+
return next;
|
|
5489
|
+
}
|
|
5490
|
+
const container = root && typeof root === 'object' ? root : {};
|
|
5491
|
+
return { ...container, [head]: withValueAtPath(container[head], rest, value) };
|
|
5492
|
+
};
|
|
5493
|
+
const IDENTITY_KEY_PATTERNS = [/^id$/i, /(^|[a-z])Id$/, /^uuid$/i, /^key$/i];
|
|
5494
|
+
const isIdentityKey = (key) => IDENTITY_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
|
5495
|
+
/** Whether every sibling in `array` that has `key` holds a distinct string/number value for it. */
|
|
5496
|
+
const isSiblingUniqueKey = (array, key) => {
|
|
5497
|
+
const seen = new Set();
|
|
5498
|
+
for (const item of array) {
|
|
5499
|
+
const value = item?.[key];
|
|
5500
|
+
if (value === undefined)
|
|
5501
|
+
continue;
|
|
5502
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
5503
|
+
return false;
|
|
5504
|
+
if (seen.has(value))
|
|
5505
|
+
return false;
|
|
5506
|
+
seen.add(value);
|
|
5507
|
+
}
|
|
5508
|
+
return seen.size > 0;
|
|
5509
|
+
};
|
|
5510
|
+
const nextNumericId = (array, key) => {
|
|
5511
|
+
let max = -Infinity;
|
|
5512
|
+
for (const item of array) {
|
|
5513
|
+
const value = item?.[key];
|
|
5514
|
+
if (typeof value === 'number' && value > max)
|
|
5515
|
+
max = value;
|
|
5516
|
+
}
|
|
5517
|
+
return Number.isFinite(max) ? max + 1 : 1;
|
|
5518
|
+
};
|
|
5519
|
+
const nextStringId = (array, key, base) => {
|
|
5520
|
+
const existing = new Set(array.map((item) => item?.[key]));
|
|
5521
|
+
let suffix = 1;
|
|
5522
|
+
while (existing.has(`${base}-copy-${suffix}`))
|
|
5523
|
+
suffix++;
|
|
5524
|
+
return `${base}-copy-${suffix}`;
|
|
5525
|
+
};
|
|
5526
|
+
/**
|
|
5527
|
+
* Clones `item` (a plain object array element) with every identity-shaped field replaced by a fresh
|
|
5528
|
+
* value, so a duplicated row never collides with the one it was copied from. A field counts as identity
|
|
5529
|
+
* when its key looks like one (`id`, `fooId`, `uuid`, `key`) or every sibling in `siblings` holds a
|
|
5530
|
+
* distinct value for it - without this, `track` bindings and detail-by-id lookups can't tell the copy
|
|
5531
|
+
* from the original.
|
|
5532
|
+
*/
|
|
5533
|
+
const smartDuplicateArrayItem = (item, siblings) => {
|
|
5534
|
+
if (!item || typeof item !== 'object' || Array.isArray(item))
|
|
5535
|
+
return item;
|
|
5536
|
+
const source = item;
|
|
5537
|
+
const result = { ...source };
|
|
5538
|
+
for (const key of Object.keys(source)) {
|
|
5539
|
+
const value = source[key];
|
|
5540
|
+
if (!isIdentityKey(key) && !isSiblingUniqueKey(siblings, key))
|
|
5541
|
+
continue;
|
|
5542
|
+
if (typeof value === 'number')
|
|
5543
|
+
result[key] = nextNumericId(siblings, key);
|
|
5544
|
+
else if (typeof value === 'string')
|
|
5545
|
+
result[key] = nextStringId(siblings, key, value);
|
|
5546
|
+
}
|
|
5547
|
+
return result;
|
|
5548
|
+
};
|
|
5549
|
+
const duplicateOneArrayItem = (array, index) => {
|
|
5550
|
+
const copy = smartDuplicateArrayItem(array[index], array);
|
|
5551
|
+
const next = [...array];
|
|
5552
|
+
next.splice(index + 1, 0, copy);
|
|
5553
|
+
return next;
|
|
5554
|
+
};
|
|
5555
|
+
const duplicateWholeArray = (array) => {
|
|
5556
|
+
let result = [...array];
|
|
5557
|
+
for (const item of array)
|
|
5558
|
+
result = [...result, smartDuplicateArrayItem(item, result)];
|
|
5559
|
+
return result;
|
|
5560
|
+
};
|
|
5561
|
+
/**
|
|
5562
|
+
* Whether `value` structurally matches one of the pagination shapes shrink/extend know how to resize -
|
|
5563
|
+
* an `items` array plus a recognized combination of total/page/limit counters. Exported so the panel's
|
|
5564
|
+
* menu can offer shrink/extend only where it would actually apply.
|
|
5565
|
+
*/
|
|
5566
|
+
const detectPaginationShape = (value) => {
|
|
5567
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
5568
|
+
return null;
|
|
5569
|
+
const obj = value;
|
|
5570
|
+
if (!Array.isArray(obj['items']))
|
|
5571
|
+
return null;
|
|
5572
|
+
const hasNumbers = (...keys) => keys.every((key) => typeof obj[key] === 'number');
|
|
5573
|
+
if (hasNumbers('totalHits', 'currentPage', 'totalPageCount', 'itemsPerPage'))
|
|
5574
|
+
return 'gg-like';
|
|
5575
|
+
if (hasNumbers('totalHits', 'currentPage', 'totalPages', 'limit'))
|
|
5576
|
+
return 'dyn-like';
|
|
5577
|
+
if (hasNumbers('totalPages', 'totalHits', 'currentPage', 'itemsPerPage'))
|
|
5578
|
+
return 'normalized';
|
|
5579
|
+
if (hasNumbers('limit', 'skip', 'total'))
|
|
5580
|
+
return 'contentful-gql-like';
|
|
5581
|
+
return null;
|
|
5582
|
+
};
|
|
5583
|
+
const DATE_KEY_PATTERN = /date|At$|Timestamp/i;
|
|
5584
|
+
const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
5585
|
+
/**
|
|
5586
|
+
* Whether a leaf is offered date presets instead of string presets: its key looks date-shaped
|
|
5587
|
+
* (`date`, `fooAt`, `fooTimestamp`) and its value round-trips through `Date.parse`, or the value
|
|
5588
|
+
* itself matches an ISO-8601 date/datetime pattern regardless of what its key is called. Exported so
|
|
5589
|
+
* the panel's menu can decide which preset list to show without duplicating the check.
|
|
5590
|
+
*/
|
|
5591
|
+
const isDateShapedLeaf = (key, value) => {
|
|
5592
|
+
if (typeof value !== 'string')
|
|
5593
|
+
return false;
|
|
5594
|
+
if (typeof key === 'string' && DATE_KEY_PATTERN.test(key) && !Number.isNaN(Date.parse(value)))
|
|
5595
|
+
return true;
|
|
5596
|
+
return ISO_DATE_PATTERN.test(value);
|
|
5597
|
+
};
|
|
5598
|
+
/**
|
|
5599
|
+
* Every path under `value` (relative to it, not absolute) whose leaf is of `kind` - the paths a "fill
|
|
5600
|
+
* recursively" menu action turns into one `set`-family op each. Exported so the panel's menu builds the
|
|
5601
|
+
* op list with the exact same walk the docs describe, rather than a second, possibly-drifted one.
|
|
5602
|
+
*/
|
|
5603
|
+
const collectLeafPaths = (value, kind) => {
|
|
5604
|
+
const paths = [];
|
|
5605
|
+
const walk = (node, path) => {
|
|
5606
|
+
if (Array.isArray(node)) {
|
|
5607
|
+
node.forEach((item, index) => walk(item, [...path, index]));
|
|
5608
|
+
return;
|
|
5609
|
+
}
|
|
5610
|
+
if (node && typeof node === 'object') {
|
|
5611
|
+
for (const [key, child] of Object.entries(node))
|
|
5612
|
+
walk(child, [...path, key]);
|
|
5613
|
+
return;
|
|
5614
|
+
}
|
|
5615
|
+
if (typeof node === kind)
|
|
5616
|
+
paths.push(path);
|
|
5617
|
+
};
|
|
5618
|
+
walk(value, []);
|
|
5619
|
+
return paths;
|
|
5620
|
+
};
|
|
5621
|
+
const resizePagination = (value, shape, mode, amount) => {
|
|
5622
|
+
const items = value['items'];
|
|
5623
|
+
let nextItems;
|
|
5624
|
+
if (mode === 'shrink') {
|
|
5625
|
+
nextItems = items.slice(0, Math.max(0, items.length - amount));
|
|
5626
|
+
}
|
|
5627
|
+
else if (items.length === 0) {
|
|
5628
|
+
// Nothing to clone a new item from - degrade to a no-op rather than inventing data out of thin air.
|
|
5629
|
+
nextItems = items;
|
|
5630
|
+
}
|
|
5631
|
+
else {
|
|
5632
|
+
nextItems = items;
|
|
5633
|
+
for (let i = 0; i < amount; i++) {
|
|
5634
|
+
nextItems = [...nextItems, smartDuplicateArrayItem(items[i % items.length], nextItems)];
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5637
|
+
const delta = nextItems.length - items.length;
|
|
5638
|
+
const result = { ...value, items: nextItems };
|
|
5639
|
+
if (shape === 'gg-like') {
|
|
5640
|
+
result['totalHits'] = value['totalHits'] + delta;
|
|
5641
|
+
result['totalPageCount'] = Math.max(1, Math.ceil(result['totalHits'] / (value['itemsPerPage'] || 1)));
|
|
5642
|
+
}
|
|
5643
|
+
else if (shape === 'dyn-like') {
|
|
5644
|
+
result['totalHits'] = value['totalHits'] + delta;
|
|
5645
|
+
result['totalPages'] = Math.max(1, Math.ceil(result['totalHits'] / (value['limit'] || 1)));
|
|
5646
|
+
}
|
|
5647
|
+
else if (shape === 'normalized') {
|
|
5648
|
+
result['totalHits'] = value['totalHits'] + delta;
|
|
5649
|
+
result['totalPages'] = Math.max(1, Math.ceil(result['totalHits'] / (value['itemsPerPage'] || 1)));
|
|
5650
|
+
}
|
|
5651
|
+
else {
|
|
5652
|
+
result['total'] = value['total'] + delta;
|
|
5653
|
+
}
|
|
5654
|
+
return result;
|
|
5655
|
+
};
|
|
5656
|
+
const STRING_PRESETS = {
|
|
5657
|
+
short: 'Ab',
|
|
5658
|
+
long: /* @__PURE__ */ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt. '.repeat(4),
|
|
5659
|
+
unicode: 'مرحبا بالعالم 👋 日本語テスト 🎉 Ñoño',
|
|
5660
|
+
};
|
|
5661
|
+
const stringPresetValue = (preset, custom) => preset === 'custom' ? (custom ?? '') : STRING_PRESETS[preset];
|
|
5662
|
+
const NUMBER_PRESETS = {
|
|
5663
|
+
zero: 0,
|
|
5664
|
+
negative: -1,
|
|
5665
|
+
huge: Number.MAX_SAFE_INTEGER,
|
|
5666
|
+
};
|
|
5667
|
+
const numberPresetValue = (preset, custom) => preset === 'custom' ? (custom ?? 0) : NUMBER_PRESETS[preset];
|
|
5668
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
5669
|
+
/** `invalid` is deliberately unparseable - "the API sent a date my code can't parse" is a real bug class. */
|
|
5670
|
+
const datePresetValue = (preset) => {
|
|
5671
|
+
switch (preset) {
|
|
5672
|
+
case 'now':
|
|
5673
|
+
return new Date().toISOString();
|
|
5674
|
+
case 'plusDay':
|
|
5675
|
+
return new Date(Date.now() + DAY_MS).toISOString();
|
|
5676
|
+
case 'minusDay':
|
|
5677
|
+
return new Date(Date.now() - DAY_MS).toISOString();
|
|
5678
|
+
case 'farFuture':
|
|
5679
|
+
return new Date('2099-01-01T00:00:00.000Z').toISOString();
|
|
5680
|
+
case 'farPast':
|
|
5681
|
+
return new Date(0).toISOString();
|
|
5682
|
+
case 'invalid':
|
|
5683
|
+
return 'not-a-date';
|
|
5684
|
+
}
|
|
5685
|
+
};
|
|
5686
|
+
const applyOp = (root, op) => {
|
|
5687
|
+
if (op.type === 'reset')
|
|
5688
|
+
return { root, ok: true };
|
|
5689
|
+
const resolution = resolvePath(root, op.path);
|
|
5690
|
+
if (!resolution.ok)
|
|
5691
|
+
return { root, ok: false };
|
|
5692
|
+
switch (op.type) {
|
|
5693
|
+
case 'set':
|
|
5694
|
+
return { root: withValueAtPath(root, op.path, op.value), ok: true };
|
|
5695
|
+
case 'booleanFlip':
|
|
5696
|
+
if (!resolution.exists || typeof resolution.value !== 'boolean')
|
|
5697
|
+
return { root, ok: false };
|
|
5698
|
+
return { root: withValueAtPath(root, op.path, !resolution.value), ok: true };
|
|
5699
|
+
case 'stringPreset':
|
|
5700
|
+
if (!resolution.exists)
|
|
5701
|
+
return { root, ok: false };
|
|
5702
|
+
return { root: withValueAtPath(root, op.path, stringPresetValue(op.preset, op.custom)), ok: true };
|
|
5703
|
+
case 'numberPreset':
|
|
5704
|
+
if (!resolution.exists)
|
|
5705
|
+
return { root, ok: false };
|
|
5706
|
+
return { root: withValueAtPath(root, op.path, numberPresetValue(op.preset, op.custom)), ok: true };
|
|
5707
|
+
case 'datePreset':
|
|
5708
|
+
if (!resolution.exists)
|
|
5709
|
+
return { root, ok: false };
|
|
5710
|
+
return { root: withValueAtPath(root, op.path, datePresetValue(op.preset)), ok: true };
|
|
5711
|
+
case 'duplicateArrayItem':
|
|
5712
|
+
if (!Array.isArray(resolution.value) || op.index < 0 || op.index >= resolution.value.length) {
|
|
5713
|
+
return { root, ok: false };
|
|
5714
|
+
}
|
|
5715
|
+
return { root: withValueAtPath(root, op.path, duplicateOneArrayItem(resolution.value, op.index)), ok: true };
|
|
5716
|
+
case 'duplicateArray':
|
|
5717
|
+
if (!Array.isArray(resolution.value))
|
|
5718
|
+
return { root, ok: false };
|
|
5719
|
+
return { root: withValueAtPath(root, op.path, duplicateWholeArray(resolution.value)), ok: true };
|
|
5720
|
+
case 'paginationResize': {
|
|
5721
|
+
const shape = detectPaginationShape(resolution.value);
|
|
5722
|
+
if (!shape)
|
|
5723
|
+
return { root, ok: false };
|
|
5724
|
+
return {
|
|
5725
|
+
root: withValueAtPath(root, op.path, resizePagination(resolution.value, shape, op.mode, op.amount)),
|
|
5726
|
+
ok: true,
|
|
5727
|
+
};
|
|
5728
|
+
}
|
|
5729
|
+
}
|
|
5730
|
+
};
|
|
5731
|
+
/**
|
|
5732
|
+
* Replays `entries` against `raw`, in order, and reports which ones no longer resolve. Shared by the
|
|
5733
|
+
* pipeline (which only needs {@link value}) and the panel's menu (which previews a value and marks stale
|
|
5734
|
+
* ops before arming a new one) - one implementation, so the two cannot drift.
|
|
5735
|
+
*/
|
|
5736
|
+
const applyQueryDevtoolsOverrides = (entries, raw) => {
|
|
5737
|
+
let root = raw;
|
|
5738
|
+
const staleIds = [];
|
|
5739
|
+
for (const entry of entries) {
|
|
5740
|
+
const applied = applyOp(root, entry.op);
|
|
5741
|
+
root = applied.root;
|
|
5742
|
+
if (!applied.ok)
|
|
5743
|
+
staleIds.push(entry.id);
|
|
5744
|
+
}
|
|
5745
|
+
return { value: root, staleIds };
|
|
5746
|
+
};
|
|
5747
|
+
/**
|
|
5748
|
+
* Accumulates the response overrides armed on one query, for the devtools panel. Only ever created
|
|
5749
|
+
* while {@link provideQueryDevtools} is installed - like {@link createQueryDevtoolsStats}, an app
|
|
5750
|
+
* without devtools pays nothing for it.
|
|
5751
|
+
* @internal
|
|
5752
|
+
*/
|
|
5753
|
+
const createQueryDevtoolsOverrides = () => {
|
|
5754
|
+
const list = signal([], /* @ts-ignore */
|
|
5755
|
+
...(ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []));
|
|
5756
|
+
let counter = 0;
|
|
5757
|
+
const arm = (op) => {
|
|
5758
|
+
if (op.type === 'reset') {
|
|
5759
|
+
list.update((current) => current.filter((entry) => !pathsEqual(entry.op.path, op.path)));
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
list.update((current) => [...current, { id: `override-${++counter}`, op }]);
|
|
5763
|
+
};
|
|
5764
|
+
const clear = (id) => list.update((current) => current.filter((entry) => entry.id !== id));
|
|
5765
|
+
const clearAll = () => list.set([]);
|
|
5766
|
+
const apply = (raw) => applyQueryDevtoolsOverrides(list(), raw).value;
|
|
5767
|
+
return { list: list.asReadonly(), arm, clear, clearAll, apply };
|
|
5768
|
+
};
|
|
5769
|
+
|
|
5407
5770
|
const EMPTY_STATS = {
|
|
5408
5771
|
executions: 0,
|
|
5409
5772
|
requests: 0,
|
|
@@ -5417,6 +5780,7 @@ const EMPTY_STATS = {
|
|
|
5417
5780
|
lastResponseAt: null,
|
|
5418
5781
|
lastDurationMs: null,
|
|
5419
5782
|
totalDurationMs: 0,
|
|
5783
|
+
lastResponseWasFaulted: false,
|
|
5420
5784
|
};
|
|
5421
5785
|
const textEncoder = typeof TextEncoder === 'function' ? /* @__PURE__ */ new TextEncoder() : null;
|
|
5422
5786
|
const byteLengthOf = (text) => textEncoder?.encode(text).length ?? text.length;
|
|
@@ -5474,7 +5838,9 @@ const trimRetainedResponses = (runs) => {
|
|
|
5474
5838
|
/**
|
|
5475
5839
|
* The size of a payload in bytes, and whether that size is the one that went over the wire. Only a
|
|
5476
5840
|
* `content-length` header is exact; everything else is measured by serializing the body.
|
|
5477
|
-
*
|
|
5841
|
+
*
|
|
5842
|
+
* Part of the devtools contract - the panel measures the cache and the event log with it. **Not part of
|
|
5843
|
+
* the general public contract.**
|
|
5478
5844
|
*/
|
|
5479
5845
|
const measureQueryDevtoolsPayload = (payload) => {
|
|
5480
5846
|
const contentLength = Number(payload.headers?.get('content-length'));
|
|
@@ -5559,6 +5925,7 @@ const createQueryDevtoolsStats = () => {
|
|
|
5559
5925
|
lastResponseAt: now,
|
|
5560
5926
|
lastDurationMs: duration,
|
|
5561
5927
|
totalDurationMs: current.totalDurationMs + (duration ?? 0),
|
|
5928
|
+
lastResponseWasFaulted: false,
|
|
5562
5929
|
}));
|
|
5563
5930
|
endRun({
|
|
5564
5931
|
endedAt: now,
|
|
@@ -5568,8 +5935,12 @@ const createQueryDevtoolsStats = () => {
|
|
|
5568
5935
|
hasResponse: true,
|
|
5569
5936
|
});
|
|
5570
5937
|
};
|
|
5571
|
-
const recordError = () => {
|
|
5572
|
-
stats.update((current) => ({
|
|
5938
|
+
const recordError = (options) => {
|
|
5939
|
+
stats.update((current) => ({
|
|
5940
|
+
...current,
|
|
5941
|
+
errors: current.errors + 1,
|
|
5942
|
+
lastResponseWasFaulted: options?.faulted ?? false,
|
|
5943
|
+
}));
|
|
5573
5944
|
endRun({ endedAt: Date.now(), status: 'error', receivedBytes: 0, response: null, hasResponse: false });
|
|
5574
5945
|
};
|
|
5575
5946
|
const recordRetry = ({ attempt }) => {
|
|
@@ -5749,6 +6120,7 @@ const registerEntry = (registration) => {
|
|
|
5749
6120
|
createdAt: Date.now(),
|
|
5750
6121
|
stats: registration.stats,
|
|
5751
6122
|
formLinks: registration.formLinks,
|
|
6123
|
+
overrides: registration.overrides,
|
|
5752
6124
|
};
|
|
5753
6125
|
entries.update((list) => [...list, fullEntry]);
|
|
5754
6126
|
return () => entries.update((list) => list.filter((e) => e.id !== fullEntry.id));
|
|
@@ -5772,6 +6144,7 @@ const provideQueryDevtools = () => {
|
|
|
5772
6144
|
setQueryDevtoolsRegistrar(registerEntry);
|
|
5773
6145
|
setQueryDevtoolsStatsFactory(createQueryDevtoolsStats);
|
|
5774
6146
|
setQueryDevtoolsFormLinksFactory(createQueryDevtoolsFormLinks);
|
|
6147
|
+
setQueryDevtoolsOverridesFactory(createQueryDevtoolsOverrides);
|
|
5775
6148
|
setQueryDevtoolsFaultResolver(resolveQueryDevtoolsFaultForAttempt);
|
|
5776
6149
|
if (!isDevMode()) {
|
|
5777
6150
|
console.warn('You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.');
|
|
@@ -9523,19 +9896,19 @@ const removeFrom = (store, { where, id }) => {
|
|
|
9523
9896
|
/**
|
|
9524
9897
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
9525
9898
|
*/
|
|
9526
|
-
const queryStateAlreadyHasKeyError = (data) => new
|
|
9899
|
+
const queryStateAlreadyHasKeyError = (data) => new RuntimeError(QueryRuntimeErrorCode.LEGACY_QUERY_STATE_ALREADY_HAS_KEY, 'The query state already contains the provided key', data);
|
|
9527
9900
|
/**
|
|
9528
9901
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
9529
9902
|
*/
|
|
9530
|
-
const queryStateDoesNotContainKeyError = (data) => new
|
|
9903
|
+
const queryStateDoesNotContainKeyError = (data) => new RuntimeError(QueryRuntimeErrorCode.LEGACY_QUERY_STATE_DOES_NOT_CONTAIN_KEY, 'The query state does not contain the provided key', data);
|
|
9531
9904
|
/**
|
|
9532
9905
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
9533
9906
|
*/
|
|
9534
|
-
const queryStateCannotTransformError = (data) => new
|
|
9907
|
+
const queryStateCannotTransformError = (data) => new RuntimeError(QueryRuntimeErrorCode.LEGACY_QUERY_STATE_CANNOT_TRANSFORM, 'The query state cannot be transformed because it is not loading', data);
|
|
9535
9908
|
/**
|
|
9536
9909
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
9537
9910
|
*/
|
|
9538
|
-
const invalidBodyError = (data) => new
|
|
9911
|
+
const invalidBodyError = (data) => new RuntimeError(QueryRuntimeErrorCode.LEGACY_INVALID_BODY, 'The body is not valid or upsupported', data);
|
|
9539
9912
|
|
|
9540
9913
|
/**
|
|
9541
9914
|
* Binds a query-backed async validator to a signal-forms field, adapting a **legacy v2**
|
|
@@ -11145,7 +11518,7 @@ const messageMalformed = () => {
|
|
|
11145
11518
|
const MAX_DEVTOOLS_MESSAGES = 100;
|
|
11146
11519
|
const createWebSocketClient = (options) => {
|
|
11147
11520
|
return defineRootProvider(() => {
|
|
11148
|
-
const socket = io(options.url, {
|
|
11521
|
+
const socket = options.io(options.url, {
|
|
11149
11522
|
withCredentials: true,
|
|
11150
11523
|
autoConnect: false,
|
|
11151
11524
|
transports: options.transports,
|
|
@@ -11164,13 +11537,28 @@ const createWebSocketClient = (options) => {
|
|
|
11164
11537
|
if (devtoolsEnabled)
|
|
11165
11538
|
devtoolsRooms.set([...rooms.keys()]);
|
|
11166
11539
|
};
|
|
11540
|
+
const recordDevtoolsMessage = (message) => {
|
|
11541
|
+
if (!devtoolsEnabled)
|
|
11542
|
+
return;
|
|
11543
|
+
devtoolsMessages.update((log) => [{ ...message, id: devtoolsMessageId++, timestamp: Date.now() }, ...log].slice(0, MAX_DEVTOOLS_MESSAGES));
|
|
11544
|
+
};
|
|
11545
|
+
/** Every outgoing message goes through here, so the devtools log covers both directions. */
|
|
11546
|
+
const emit = (message) => {
|
|
11547
|
+
socket.emit(message.event, message.data);
|
|
11548
|
+
recordDevtoolsMessage({
|
|
11549
|
+
room: message.room ?? '',
|
|
11550
|
+
event: message.event,
|
|
11551
|
+
data: message.data,
|
|
11552
|
+
direction: 'out',
|
|
11553
|
+
});
|
|
11554
|
+
};
|
|
11167
11555
|
const joinRoom = (room) => {
|
|
11168
11556
|
const roomFn = typeof room === 'function' ? room : () => room;
|
|
11169
11557
|
const pre = previousSignalValue(computed(() => roomFn()));
|
|
11170
11558
|
const roomData = signal(null, /* @ts-ignore */
|
|
11171
11559
|
...(ngDevMode ? [{ debugName: "roomData" }] : /* istanbul ignore next */ []));
|
|
11172
11560
|
const join = (name) => {
|
|
11173
|
-
|
|
11561
|
+
emit({ event: 'join-room', data: name, room: name });
|
|
11174
11562
|
const existingRoom = rooms.get(name);
|
|
11175
11563
|
if (existingRoom)
|
|
11176
11564
|
return existingRoom;
|
|
@@ -11215,7 +11603,7 @@ const createWebSocketClient = (options) => {
|
|
|
11215
11603
|
if (isDevMode())
|
|
11216
11604
|
throw roomNotJoined(room);
|
|
11217
11605
|
}
|
|
11218
|
-
|
|
11606
|
+
emit({ event: 'leave-room', data: room, room });
|
|
11219
11607
|
rooms.delete(room);
|
|
11220
11608
|
syncDevtoolsRooms();
|
|
11221
11609
|
};
|
|
@@ -11223,7 +11611,7 @@ const createWebSocketClient = (options) => {
|
|
|
11223
11611
|
socket.on('connect', () => {
|
|
11224
11612
|
isConnected.set(true);
|
|
11225
11613
|
for (const room of rooms.keys()) {
|
|
11226
|
-
|
|
11614
|
+
emit({ event: 'join-room', data: room, room });
|
|
11227
11615
|
}
|
|
11228
11616
|
});
|
|
11229
11617
|
socket.on('disconnect', () => isConnected.set(false));
|
|
@@ -11232,16 +11620,7 @@ const createWebSocketClient = (options) => {
|
|
|
11232
11620
|
socket.onAny((data) => {
|
|
11233
11621
|
try {
|
|
11234
11622
|
const json = JSON.parse(data);
|
|
11235
|
-
|
|
11236
|
-
const message = {
|
|
11237
|
-
id: devtoolsMessageId++,
|
|
11238
|
-
timestamp: Date.now(),
|
|
11239
|
-
room: json.room,
|
|
11240
|
-
event: json.event,
|
|
11241
|
-
data: json.data,
|
|
11242
|
-
};
|
|
11243
|
-
devtoolsMessages.update((log) => [message, ...log].slice(0, MAX_DEVTOOLS_MESSAGES));
|
|
11244
|
-
}
|
|
11623
|
+
recordDevtoolsMessage({ room: json.room, event: json.event, data: json.data, direction: 'in' });
|
|
11245
11624
|
const room = rooms.get(json.room);
|
|
11246
11625
|
if (room)
|
|
11247
11626
|
room.latestMessage.set(json);
|
|
@@ -11269,6 +11648,7 @@ const createWebSocketClient = (options) => {
|
|
|
11269
11648
|
connected: isConnected.asReadonly(),
|
|
11270
11649
|
rooms: devtoolsRooms.asReadonly(),
|
|
11271
11650
|
messages: devtoolsMessages.asReadonly(),
|
|
11651
|
+
emit,
|
|
11272
11652
|
};
|
|
11273
11653
|
const unregister = registerQueryDevtoolsEntry({
|
|
11274
11654
|
kind: 'ws-client',
|
|
@@ -11287,5 +11667,5 @@ const createWebSocketClient = (options) => {
|
|
|
11287
11667
|
* Generated bundle index. Do not edit.
|
|
11288
11668
|
*/
|
|
11289
11669
|
|
|
11290
|
-
export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective,
|
|
11670
|
+
export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryFormSignals, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsFaults, collectLeafPaths, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryDevtoolsFormLinks, createQueryDevtoolsFormLinksRecorder, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, createQueryForm, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isDateShapedLeaf, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsFaultInjectionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, mapToPaginated, mapViolationsToFormErrors, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryRoute, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFnDetail, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, runDefaultQueryRetry, runQueryErrorParsers, searchQueryField, serializeBody, setDefaultQueryRetryFn, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsOverridesFactory, setQueryDevtoolsRegistrar, setQueryDevtoolsStatsFactory, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, unwrapQuerySyncMessage, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withBearerAuthMultiTabSync, withDefaultRetry, withErrorHandling, withEthleteApiErrors, withHtmlErrorParsing, withInactivityLogout, withLogging, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage };
|
|
11291
11671
|
//# sourceMappingURL=ethlete-query.mjs.map
|