@ethlete/query 5.24.0 → 5.25.0

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
  /**
@@ -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.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "@angular/common": "19.1.4",