@ethlete/query 5.24.0 → 5.25.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.
@@ -55,6 +55,16 @@ export type BearerAuthProviderCookieConfig<TTokenRefreshArgs extends QueryArgs>
55
55
  * @default (token) => ({ token })
56
56
  */
57
57
  refreshArgsTransformer?: (token: string) => RequestArgs<TTokenRefreshArgs>;
58
+ /**
59
+ * An array of routes where the auto login via cookie should not be triggered.
60
+ *
61
+ * This checks the current route against the array of routes using the `startsWith` method.
62
+ * Make sure to start each route with a `/`.
63
+ *
64
+ * @default []
65
+ * @example ['/login', '/register']
66
+ */
67
+ autoLoginExcludeRoutes?: string[];
58
68
  };
59
69
  export type CreateBearerAuthProviderConfigOptions<TLoginArgs extends QueryArgs, TTokenLoginArgs extends QueryArgs, TTokenRefreshArgs extends QueryArgs, TSelectRoleArgs extends QueryArgs> = {
60
70
  /**
@@ -9,7 +9,7 @@ export declare const ggLikePaginationAdapter: <T>(response: GgLikePaginated<T>)
9
9
  export declare const dynLikePaginationAdapter: <T>(response: DynLikePaginated<T>) => NormalizedPagination<T>;
10
10
  export declare const contentfulGqlLikePaginationAdapter: <T>(response: ContentfulGqlLikePaginated<T>) => NormalizedPagination<T>;
11
11
  export declare const fakePaginationAdapter: (totalHits?: number) => <T>(response: T) => NormalizedPagination<T>;
12
- export type CreatePagedQueryStackOptions<TArgs extends QueryArgs> = {
12
+ export type CreatePagedQueryStackOptions<TArgs extends QueryArgs, TNormPagination extends NormalizedPagination<unknown>> = {
13
13
  /**
14
14
  * The normalizer function that will be used to normalize the response to a format that the paged query can understand.
15
15
  *
@@ -20,7 +20,7 @@ export type CreatePagedQueryStackOptions<TArgs extends QueryArgs> = {
20
20
  * - `contentfulGqlLikePaginationAdapter`
21
21
  * - `fakePaginationAdapter` (for testing purposes)
22
22
  */
23
- responseNormalizer: (response: ResponseType<TArgs>) => NormalizedPagination<ResponseType<TArgs>>;
23
+ responseNormalizer: (response: ResponseType<TArgs>) => TNormPagination;
24
24
  /**
25
25
  * The query creator function that will be used to create the paged query.
26
26
  */
@@ -62,7 +62,7 @@ export type PagedQueryStackResetOptions = {
62
62
  */
63
63
  initialPage?: number;
64
64
  };
65
- export type PagedQueryStackExecuteOptions<TArgs extends QueryArgs> = {
65
+ export type PagedQueryStackExecuteOptions<TNormPagination extends NormalizedPagination<unknown>> = {
66
66
  /**
67
67
  * If provided, only the queries that match the condition will be executed.
68
68
  * This will also execute the previous and next query to the one that matched the condition.
@@ -71,7 +71,7 @@ export type PagedQueryStackExecuteOptions<TArgs extends QueryArgs> = {
71
71
  * @example
72
72
  * myPagedQuery.execute({ where: (item) => item.id === 4 });
73
73
  */
74
- where?: (item: ResponseType<TArgs>, index: number, array: ResponseType<TArgs>[]) => boolean;
74
+ where?: (item: TNormPagination['items'][number], index: number, array: TNormPagination['items']) => boolean;
75
75
  /**
76
76
  * If true, the cache will be used (if not expired) and the request will not be made.
77
77
  * @default false
@@ -79,12 +79,12 @@ export type PagedQueryStackExecuteOptions<TArgs extends QueryArgs> = {
79
79
  allowCache?: boolean;
80
80
  };
81
81
  export type PagedQueryStackDirection = 'next' | 'previous';
82
- export type AnyPagedQueryStack = PagedQueryStack<AnyQuery>;
83
- export type PagedQueryStack<TQuery extends AnyQuery> = {
82
+ export type AnyPagedQueryStack = PagedQueryStack<AnyQuery, NormalizedPagination<unknown>>;
83
+ export type PagedQueryStack<TQuery extends AnyQuery, TNormPagination extends NormalizedPagination<unknown>> = {
84
84
  /**
85
85
  * The current pagination state of the paged query.
86
86
  */
87
- pagination: Signal<NormalizedPagination<ResponseType<QueryArgsOf<TQuery>>> | null>;
87
+ pagination: Signal<TNormPagination | null>;
88
88
  /**
89
89
  * Fetches the previous page of the paged query.
90
90
  *
@@ -112,7 +112,7 @@ export type PagedQueryStack<TQuery extends AnyQuery> = {
112
112
  /**
113
113
  * The items of the paged query.
114
114
  */
115
- items: Signal<ResponseType<QueryArgsOf<TQuery>>[]>;
115
+ items: Signal<TNormPagination['items']>;
116
116
  /**
117
117
  * Whether the paged query is loading or not.
118
118
  */
@@ -140,10 +140,10 @@ export type PagedQueryStack<TQuery extends AnyQuery> = {
140
140
  /**
141
141
  * Executes the paged query.
142
142
  */
143
- execute: (options?: PagedQueryStackExecuteOptions<QueryArgsOf<TQuery>>) => void;
143
+ execute: (options?: PagedQueryStackExecuteOptions<TNormPagination>) => void;
144
144
  /**
145
145
  * The current direction of the paged query.
146
146
  */
147
147
  direction: Signal<PagedQueryStackDirection>;
148
148
  };
149
- export declare const createPagedQueryStack: <TCreator extends AnyQueryCreator, TArgs extends QueryArgsOf<TCreator>>(options: CreatePagedQueryStackOptions<TArgs>) => PagedQueryStack<Query<TArgs>>;
149
+ export declare const createPagedQueryStack: <TCreator extends AnyQueryCreator, TArgs extends QueryArgsOf<TCreator>, TNormPagination extends NormalizedPagination<unknown>>(options: CreatePagedQueryStackOptions<TArgs, TNormPagination>) => PagedQueryStack<Query<TArgs>, TNormPagination>;
@@ -23,7 +23,8 @@ export declare const enum QueryRuntimeErrorCode {
23
23
  PAGED_QUERY_STACK_PAGE_BIGGER_THAN_TOTAL_PAGES = 400,
24
24
  PAGED_QUERY_STACK_NEXT_PAGE_CALLED_WITHOUT_PREVIOUS_PAGE = 401,
25
25
  PAGED_QUERY_STACK_PREVIOUS_PAGE_CALLED_BUT_ALREADY_AT_FIRST_PAGE = 402,
26
- QUERY_STACK_WITH_ARGS_USED = 500
26
+ QUERY_STACK_WITH_ARGS_USED = 500,
27
+ QUERY_STACK_WITH_RESPONSE_UPDATE_USED = 501
27
28
  }
28
29
  export declare const queryFeatureUsedMultipleTimes: (type: QueryFeatureType) => RuntimeError<QueryRuntimeErrorCode.QUERY_FEATURE_USED_MULTIPLE_TIMES>;
29
30
  export declare const withArgsQueryFeatureMissingButRouteIsFunction: () => RuntimeError<QueryRuntimeErrorCode.WITH_ARGS_QUERY_FEATURE_MISSING_BUT_ROUTE_IS_FUNCTION>;
@@ -48,3 +49,4 @@ export declare const pagedQueryStackPageBiggerThanTotalPages: (page: number, tot
48
49
  export declare const pagedQueryStackNextPageCalledWithoutPreviousPage: () => RuntimeError<QueryRuntimeErrorCode.PAGED_QUERY_STACK_NEXT_PAGE_CALLED_WITHOUT_PREVIOUS_PAGE>;
49
50
  export declare const pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage: () => RuntimeError<QueryRuntimeErrorCode.PAGED_QUERY_STACK_PREVIOUS_PAGE_CALLED_BUT_ALREADY_AT_FIRST_PAGE>;
50
51
  export declare const queryStackWithArgsUsed: () => RuntimeError<QueryRuntimeErrorCode.QUERY_STACK_WITH_ARGS_USED>;
52
+ export declare const queryStackWithResponseUpdateUsed: () => RuntimeError<QueryRuntimeErrorCode.QUERY_STACK_WITH_RESPONSE_UPDATE_USED>;
@@ -11,7 +11,8 @@ export declare const enum QueryFeatureType {
11
11
  WithErrorHandling = "withErrorHandling",
12
12
  WithSuccessHandling = "withSuccessHandling",
13
13
  WithPolling = "withPolling",
14
- WithAutoRefresh = "withAutoRefresh"
14
+ WithAutoRefresh = "withAutoRefresh",
15
+ WithResponseUpdate = "withResponseUpdate"
15
16
  }
16
17
  export type QueryFeatureContext<TArgs extends QueryArgs> = {
17
18
  state: QueryState<TArgs>;
@@ -82,4 +83,38 @@ export type WithAutoRefreshFeatureOptions = {
82
83
  * @throws If the query has the `onlyManualExecution` query config flag set and `ignoreOnlyManualExecution` is not set
83
84
  */
84
85
  export declare const withAutoRefresh: <TArgs extends QueryArgs>(options: WithAutoRefreshFeatureOptions) => QueryFeature<TArgs>;
86
+ export type WithResponseUpdateFeatureFnData<TArgs extends QueryArgs> = {
87
+ /** The current response of the query */
88
+ currentResponse: ResponseType<TArgs> | null;
89
+ };
90
+ export type WithResponseUpdateFeatureOptions<TArgs extends QueryArgs> = {
91
+ /**
92
+ * A function that will be called with the latest response
93
+ * If the function returns `null`, the response will not be updated.
94
+ * Otherwise, the response will be updated with the returned value.
95
+ * The function will be called in a reactive signal context.
96
+ * If the query get's executed after the response was updated, the response will be set the the fresh data received from the server.
97
+ *
98
+ * This feature is most useful in combination with web sockets where the data received from the socket might be more up-to-date than the data received previously.
99
+ *
100
+ * @example
101
+ * const matchEvents = mySocket.joinRoom('match-events');
102
+ *
103
+ * const myMatchQuery = getMatch(
104
+ * withArgs(() => ({ matchId: 1 })),
105
+ * withResponseUpdate(({ currentResponse }) => {
106
+ * const matchEvent = matchEvents();
107
+ *
108
+ * if (!matchEvent) return null;
109
+ *
110
+ * // Do some checks here. This is just a very simple example.
111
+ * // To apply partial updates, you can use the spread operator in combination with the current response.
112
+ *
113
+ * return matchEvent;
114
+ * })
115
+ * )
116
+ */
117
+ updater: (data: WithResponseUpdateFeatureFnData<TArgs>) => ResponseType<TArgs> | null;
118
+ };
119
+ export declare const withResponseUpdate: <TArgs extends QueryArgs>(options: WithResponseUpdateFeatureOptions<TArgs>) => QueryFeature<TArgs>;
85
120
  export {};
@@ -1,8 +1,11 @@
1
1
  import { HttpErrorResponse, HttpEvent } from '@angular/common/http';
2
2
  import { WritableSignal } from '@angular/core';
3
- import { HttpRequestLoadingState } from './http-request';
3
+ import { HttpRequest, HttpRequestLoadingState } from './http-request';
4
4
  import { QueryArgs, RequestArgs, ResponseType } from './query';
5
5
  export type SetupQueryStateOptions = {};
6
+ export type QueryStateSubtle<TArgs extends QueryArgs> = {
7
+ request: WritableSignal<HttpRequest<TArgs> | null>;
8
+ };
6
9
  export type QueryState<TArgs extends QueryArgs> = {
7
10
  response: WritableSignal<ResponseType<TArgs> | null>;
8
11
  args: WritableSignal<RequestArgs<TArgs> | null>;
@@ -10,5 +13,6 @@ export type QueryState<TArgs extends QueryArgs> = {
10
13
  loading: WritableSignal<HttpRequestLoadingState | null>;
11
14
  error: WritableSignal<HttpErrorResponse | null>;
12
15
  lastTimeExecutedAt: WritableSignal<number | null>;
16
+ subtle: QueryStateSubtle<TArgs>;
13
17
  };
14
18
  export declare const setupQueryState: <TArgs extends QueryArgs>(options: SetupQueryStateOptions) => QueryState<TArgs>;
@@ -49,9 +49,11 @@ export type QuerySnapshot<TArgs extends QueryArgs> = QueryBase<TArgs> & {
49
49
  };
50
50
  export type AnyQuerySnapshot = QuerySnapshot<any>;
51
51
  export type AnyQuery = Query<any>;
52
- export type QuerySubtle = {
52
+ export type QuerySubtle<TArgs extends QueryArgs> = {
53
53
  /** Destroys the query and cleans up all resources. The query should not be used after this method is called. */
54
54
  destroy: () => void;
55
+ /** Manually sets the response of the query. This will not trigger a new execution of the query. */
56
+ setResponse: (response: ResponseType<TArgs>) => void;
55
57
  };
56
58
  export type Query<TArgs extends QueryArgs> = QueryBase<TArgs> & {
57
59
  /** Executes the query */
@@ -61,6 +63,6 @@ export type Query<TArgs extends QueryArgs> = QueryBase<TArgs> & {
61
63
  /** Resets the query state to its initial state */
62
64
  reset: () => void;
63
65
  /** Advanced query features. **WARNING!** Incorrectly using these features will likely **BREAK** your application. You have been warned! */
64
- subtle: QuerySubtle;
66
+ subtle: QuerySubtle<TArgs>;
65
67
  };
66
68
  export declare const createQuery: <TArgs extends QueryArgs>(options: CreateQueryOptions<TArgs>) => Query<TArgs>;
@@ -1,10 +1,12 @@
1
1
  import { InjectionToken } from '@angular/core';
2
2
  import { SocketMessageView, WebSocketClient } from './web-socket-client';
3
3
  export type CreateWebSocketClientConfig = {
4
+ /** A unique name for the client */
4
5
  name: string;
6
+ /** The URL of the socket io server */
5
7
  url: string;
6
8
  };
7
- export type WebSocketClientRef<T extends SocketMessageView = SocketMessageView> = InjectionToken<WebSocketClient<T>>;
9
+ export type WebSocketClientRef<TMessageData extends SocketMessageView = SocketMessageView> = InjectionToken<WebSocketClient<TMessageData>>;
8
10
  export type WebSocketClientConfig = CreateWebSocketClientConfig & {
9
11
  /** A generated token for dependency injection */
10
12
  token: WebSocketClientRef;
@@ -1,20 +1,37 @@
1
- import { Signal } from '@angular/core';
1
+ import { Signal, WritableSignal } from '@angular/core';
2
2
  import { WebSocketClientConfig } from './web-socket-client-config';
3
- export type SocketMessageView = {
3
+ /** A default socket io message view */
4
+ export type SocketMessageView<TMessageData = unknown> = {
4
5
  room: string;
5
6
  event: string;
6
- data: unknown | null;
7
+ data: TMessageData;
7
8
  };
8
- export type WebSocketClient<T extends SocketMessageView> = {
9
- joinRoom: (room: string) => void;
10
- joinComputedRoom: (room: () => string | null) => void;
9
+ export type WebSocketClientSubtle = {
10
+ /** Leave a socket io room */
11
11
  leaveRoom: (room: string) => void;
12
- leaveAllRooms: () => void;
13
- currentEvent: Signal<T | null>;
12
+ };
13
+ export type WebSocketClient<TMessageData extends SocketMessageView> = {
14
+ /**
15
+ * Join a socket io room
16
+ * If a function is passed, it will be evaluated in a reactive signal context.
17
+ * If the function returns null, no room will be joined.
18
+ * If the function returns a string, the previous room will be left and the new room will be joined.
19
+ */
20
+ joinRoom: (room: string | (() => string | null)) => Signal<WebSocketRoom<TMessageData> | null>;
21
+ /** Whether the client is connected to the server */
14
22
  isConnected: Signal<boolean>;
23
+ /** Advanced web socket features. **WARNING!** Incorrectly using these features will likely **BREAK** your application. You have been warned! */
24
+ subtle: WebSocketClientSubtle;
25
+ };
26
+ export type InternalWebSocketRoom<TMessageData extends SocketMessageView> = {
27
+ latestMessage: WritableSignal<TMessageData | null>;
28
+ };
29
+ export type WebSocketRoom<TMessageData extends SocketMessageView> = {
30
+ /** The latest message received in the room */
31
+ latestMessage: Signal<TMessageData | null>;
15
32
  };
16
- export declare const createWebSocketClient: <T extends SocketMessageView>(config: WebSocketClientConfig) => WebSocketClient<T>;
33
+ export declare const createWebSocketClient: <TMessageData extends SocketMessageView>(config: WebSocketClientConfig) => WebSocketClient<TMessageData>;
17
34
  export declare const provideWebSocketClient: (config: WebSocketClientConfig) => {
18
35
  provide: import("./web-socket-client-config").WebSocketClientRef<SocketMessageView>;
19
- useFactory: () => WebSocketClient<SocketMessageView>;
36
+ useFactory: () => WebSocketClient<SocketMessageView<unknown>>;
20
37
  };
@@ -1,9 +1,7 @@
1
1
  import { RuntimeError } from '@ethlete/core';
2
- export declare const enum QueryRuntimeErrorCode {
3
- ROOM_ALREADY_JOINED = 1000,
4
- ROOM_NOT_JOINED = 1001,
5
- MESSAGE_MALFORMED = 1002
2
+ export declare const enum WebSocketRuntimeErrorCode {
3
+ ROOM_NOT_JOINED = 1000,
4
+ MESSAGE_MALFORMED = 1001
6
5
  }
7
- export declare const roomAlreadyJoined: (room: string) => RuntimeError<QueryRuntimeErrorCode.ROOM_ALREADY_JOINED>;
8
- export declare const roomNotJoined: (room: string) => RuntimeError<QueryRuntimeErrorCode.ROOM_NOT_JOINED>;
9
- export declare const messageMalformed: () => RuntimeError<QueryRuntimeErrorCode.MESSAGE_MALFORMED>;
6
+ export declare const roomNotJoined: (room: string) => RuntimeError<WebSocketRuntimeErrorCode.ROOM_NOT_JOINED>;
7
+ export declare const messageMalformed: () => RuntimeError<WebSocketRuntimeErrorCode.MESSAGE_MALFORMED>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/query",
3
- "version": "5.24.0",
3
+ "version": "5.25.1",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "@angular/common": "19.1.4",