@terreno/rtk 0.13.3 → 0.14.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.
Files changed (163) hide show
  1. package/dist/authSlice.d.ts +4 -4
  2. package/dist/authSlice.d.ts.map +1 -1
  3. package/dist/authSlice.js +7 -7
  4. package/dist/authSlice.js.map +1 -1
  5. package/dist/authSlice.test.js +2 -10
  6. package/dist/authSlice.test.js.map +1 -1
  7. package/dist/authSliceNative.test.js +11 -3
  8. package/dist/authSliceNative.test.js.map +1 -1
  9. package/dist/betterAuthSlice.d.ts.map +1 -1
  10. package/dist/betterAuthSlice.js +3 -2
  11. package/dist/betterAuthSlice.js.map +1 -1
  12. package/dist/betterAuthSlice.test.js +1 -25
  13. package/dist/betterAuthSlice.test.js.map +1 -1
  14. package/dist/constants.d.ts +3 -0
  15. package/dist/constants.d.ts.map +1 -1
  16. package/dist/constants.js +11 -3
  17. package/dist/constants.js.map +1 -1
  18. package/dist/constants.test.js +85 -2
  19. package/dist/constants.test.js.map +1 -1
  20. package/dist/emptyApi.d.ts +3 -1
  21. package/dist/emptyApi.d.ts.map +1 -1
  22. package/dist/emptyApi.js +7 -2
  23. package/dist/emptyApi.js.map +1 -1
  24. package/dist/index.d.ts +8 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +8 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/isolated/constants.isolated.js +7 -1
  29. package/dist/isolated/constants.isolated.js.map +1 -1
  30. package/dist/isolated/offlineMiddleware.isolated.d.ts +2 -0
  31. package/dist/isolated/offlineMiddleware.isolated.d.ts.map +1 -0
  32. package/dist/isolated/offlineMiddleware.isolated.js +516 -0
  33. package/dist/isolated/offlineMiddleware.isolated.js.map +1 -0
  34. package/dist/isolated/offlineMiddleware.native.isolated.d.ts +2 -0
  35. package/dist/isolated/offlineMiddleware.native.isolated.d.ts.map +1 -0
  36. package/dist/isolated/offlineMiddleware.native.isolated.js +70 -0
  37. package/dist/isolated/offlineMiddleware.native.isolated.js.map +1 -0
  38. package/dist/isolated/useUpgradeCheck.mobile.isolated.d.ts +2 -0
  39. package/dist/isolated/useUpgradeCheck.mobile.isolated.d.ts.map +1 -0
  40. package/dist/{useUpgradeCheck.mobile.test.js → isolated/useUpgradeCheck.mobile.isolated.js} +13 -5
  41. package/dist/isolated/useUpgradeCheck.mobile.isolated.js.map +1 -0
  42. package/dist/isolated/useUpgradeCheck.web.isolated.d.ts +2 -0
  43. package/dist/isolated/useUpgradeCheck.web.isolated.d.ts.map +1 -0
  44. package/dist/{useUpgradeCheck.test.js → isolated/useUpgradeCheck.web.isolated.js} +37 -7
  45. package/dist/isolated/useUpgradeCheck.web.isolated.js.map +1 -0
  46. package/dist/mongooseSlice.d.ts +3 -2
  47. package/dist/mongooseSlice.d.ts.map +1 -1
  48. package/dist/mongooseSlice.js +3 -4
  49. package/dist/mongooseSlice.js.map +1 -1
  50. package/dist/mongooseSlice.test.js +1 -1
  51. package/dist/mongooseSlice.test.js.map +1 -1
  52. package/dist/offlineGate.d.ts +8 -0
  53. package/dist/offlineGate.d.ts.map +1 -0
  54. package/dist/offlineGate.js +20 -0
  55. package/dist/offlineGate.js.map +1 -0
  56. package/dist/offlineGate.test.d.ts +2 -0
  57. package/dist/offlineGate.test.d.ts.map +1 -0
  58. package/dist/offlineGate.test.js +46 -0
  59. package/dist/offlineGate.test.js.map +1 -0
  60. package/dist/offlineMiddleware.d.ts +46 -0
  61. package/dist/offlineMiddleware.d.ts.map +1 -0
  62. package/dist/offlineMiddleware.js +589 -0
  63. package/dist/offlineMiddleware.js.map +1 -0
  64. package/dist/offlineMiddleware.test.d.ts +2 -0
  65. package/dist/offlineMiddleware.test.d.ts.map +1 -0
  66. package/dist/offlineMiddleware.test.js +145 -0
  67. package/dist/offlineMiddleware.test.js.map +1 -0
  68. package/dist/offlineSlice.d.ts +232 -0
  69. package/dist/offlineSlice.d.ts.map +1 -0
  70. package/dist/offlineSlice.js +65 -0
  71. package/dist/offlineSlice.js.map +1 -0
  72. package/dist/offlineSlice.test.d.ts +2 -0
  73. package/dist/offlineSlice.test.d.ts.map +1 -0
  74. package/dist/offlineSlice.test.js +153 -0
  75. package/dist/offlineSlice.test.js.map +1 -0
  76. package/dist/realtime.d.ts +123 -0
  77. package/dist/realtime.d.ts.map +1 -0
  78. package/dist/realtime.js +299 -0
  79. package/dist/realtime.js.map +1 -0
  80. package/dist/realtime.test.d.ts +2 -0
  81. package/dist/realtime.test.d.ts.map +1 -0
  82. package/dist/realtime.test.js +339 -0
  83. package/dist/realtime.test.js.map +1 -0
  84. package/dist/socket.d.ts.map +1 -1
  85. package/dist/socket.js +29 -28
  86. package/dist/socket.js.map +1 -1
  87. package/dist/sync.d.ts +35 -0
  88. package/dist/sync.d.ts.map +1 -0
  89. package/dist/sync.js +205 -0
  90. package/dist/sync.js.map +1 -0
  91. package/dist/tagGenerator.d.ts +20 -1
  92. package/dist/tagGenerator.d.ts.map +1 -1
  93. package/dist/tagGenerator.js +4 -12
  94. package/dist/tagGenerator.js.map +1 -1
  95. package/dist/useFeatureFlags.d.ts +4 -2
  96. package/dist/useFeatureFlags.d.ts.map +1 -1
  97. package/dist/useFeatureFlags.js +3 -5
  98. package/dist/useFeatureFlags.js.map +1 -1
  99. package/dist/useOfflineStatus.d.ts +33 -0
  100. package/dist/useOfflineStatus.d.ts.map +1 -0
  101. package/dist/useOfflineStatus.js +43 -0
  102. package/dist/useOfflineStatus.js.map +1 -0
  103. package/dist/useOfflineStatus.test.d.ts +2 -0
  104. package/dist/useOfflineStatus.test.d.ts.map +1 -0
  105. package/dist/useOfflineStatus.test.js +119 -0
  106. package/dist/useOfflineStatus.test.js.map +1 -0
  107. package/dist/useRealtimeDebug.d.ts +6 -0
  108. package/dist/useRealtimeDebug.d.ts.map +1 -0
  109. package/dist/useRealtimeDebug.js +41 -0
  110. package/dist/useRealtimeDebug.js.map +1 -0
  111. package/dist/useServerStatus.d.ts +29 -0
  112. package/dist/useServerStatus.d.ts.map +1 -0
  113. package/dist/useServerStatus.js +89 -0
  114. package/dist/useServerStatus.js.map +1 -0
  115. package/dist/useUpgradeCheck.d.ts +7 -3
  116. package/dist/useUpgradeCheck.d.ts.map +1 -1
  117. package/dist/useUpgradeCheck.js +27 -13
  118. package/dist/useUpgradeCheck.js.map +1 -1
  119. package/package.json +2 -2
  120. package/src/authSlice.test.ts +2 -11
  121. package/src/authSlice.ts +9 -9
  122. package/src/authSliceNative.test.ts +11 -4
  123. package/src/betterAuthSlice.test.ts +1 -25
  124. package/src/betterAuthSlice.ts +3 -2
  125. package/src/constants.test.ts +99 -1
  126. package/src/constants.ts +14 -3
  127. package/src/emptyApi.ts +11 -3
  128. package/src/index.ts +8 -0
  129. package/src/isolated/constants.isolated.ts +7 -3
  130. package/src/isolated/offlineMiddleware.isolated.ts +696 -0
  131. package/src/isolated/offlineMiddleware.native.isolated.ts +80 -0
  132. package/src/{useUpgradeCheck.mobile.test.ts → isolated/useUpgradeCheck.mobile.isolated.ts} +13 -4
  133. package/src/{useUpgradeCheck.test.ts → isolated/useUpgradeCheck.web.isolated.ts} +48 -6
  134. package/src/mongooseSlice.test.ts +1 -1
  135. package/src/mongooseSlice.ts +4 -5
  136. package/src/offlineGate.test.ts +55 -0
  137. package/src/offlineGate.ts +25 -0
  138. package/src/offlineMiddleware.test.ts +187 -0
  139. package/src/offlineMiddleware.ts +716 -0
  140. package/src/offlineSlice.test.ts +204 -0
  141. package/src/offlineSlice.ts +130 -0
  142. package/src/realtime.test.ts +404 -0
  143. package/src/realtime.ts +408 -0
  144. package/src/socket.ts +33 -32
  145. package/src/sync.ts +310 -0
  146. package/src/tagGenerator.ts +30 -18
  147. package/src/useFeatureFlags.ts +6 -6
  148. package/src/useOfflineStatus.test.ts +157 -0
  149. package/src/useOfflineStatus.ts +82 -0
  150. package/src/useRealtimeDebug.ts +51 -0
  151. package/src/useServerStatus.ts +122 -0
  152. package/src/useUpgradeCheck.ts +35 -13
  153. package/dist/isolated/useUpgradeCheck.isolated.d.ts +0 -2
  154. package/dist/isolated/useUpgradeCheck.isolated.d.ts.map +0 -1
  155. package/dist/isolated/useUpgradeCheck.isolated.js +0 -153
  156. package/dist/isolated/useUpgradeCheck.isolated.js.map +0 -1
  157. package/dist/useUpgradeCheck.mobile.test.d.ts +0 -2
  158. package/dist/useUpgradeCheck.mobile.test.d.ts.map +0 -1
  159. package/dist/useUpgradeCheck.mobile.test.js.map +0 -1
  160. package/dist/useUpgradeCheck.test.d.ts +0 -2
  161. package/dist/useUpgradeCheck.test.d.ts.map +0 -1
  162. package/dist/useUpgradeCheck.test.js.map +0 -1
  163. package/src/isolated/useUpgradeCheck.isolated.ts +0 -201
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import {createListenerMiddleware, createSlice, type PayloadAction} from "@reduxjs/toolkit";
9
+ import {DateTime} from "luxon";
9
10
 
10
11
  import type {BetterAuthClientInterface, BetterAuthUser} from "./betterAuthTypes";
11
12
 
@@ -125,7 +126,7 @@ export const generateBetterAuthSlice = (config: GenerateBetterAuthSliceConfig) =
125
126
  state.user = null;
126
127
  state.isLoading = false;
127
128
  state.error = null;
128
- state.lastSyncTimestamp = Date.now();
129
+ state.lastSyncTimestamp = DateTime.now().toMillis();
129
130
  },
130
131
 
131
132
  /**
@@ -162,7 +163,7 @@ export const generateBetterAuthSlice = (config: GenerateBetterAuthSliceConfig) =
162
163
  state.user = action.payload.user;
163
164
  state.isLoading = false;
164
165
  state.error = null;
165
- state.lastSyncTimestamp = Date.now();
166
+ state.lastSyncTimestamp = DateTime.now().toMillis();
166
167
  },
167
168
  },
168
169
  });
@@ -5,9 +5,11 @@ import {
5
5
  baseTasksUrl,
6
6
  baseUrl,
7
7
  baseWebsocketsUrl,
8
+ isWebsocketsDebugEnabled,
8
9
  logAuth,
9
10
  logSocket,
10
11
  resolveBaseUrls,
12
+ setRealtimeDebug,
11
13
  } from "./constants";
12
14
 
13
15
  describe("resolveBaseUrls", () => {
@@ -140,6 +142,51 @@ describe("resolveBaseUrls", () => {
140
142
  });
141
143
  expect(urls.baseUrl).toBe("http://localhost:4000");
142
144
  });
145
+
146
+ it("ignores BASE_URL from extra in dev mode and uses hostUri instead", () => {
147
+ const urls = resolveBaseUrls({
148
+ expoConstants: {
149
+ expoConfig: {extra: {BASE_URL: "https://api.prod.com"}, hostUri: "192.168.0.10:8081"},
150
+ },
151
+ isDev: true,
152
+ });
153
+ expect(urls.baseUrl).toBe("http://192.168.0.10:4000");
154
+ expect(urls.baseWebsocketsUrl).toBe("ws://192.168.0.10:4000/");
155
+ expect(urls.baseTasksUrl).toBe("http://192.168.0.10:4000/tasks");
156
+ });
157
+
158
+ it("falls back to experienceUrl when hostUri is empty string", () => {
159
+ const urls = resolveBaseUrls({
160
+ expoConstants: {
161
+ experienceUrl: "exp://10.0.0.5:19000",
162
+ expoConfig: {extra: {}, hostUri: ""},
163
+ },
164
+ isDev: true,
165
+ });
166
+ expect(urls.baseUrl).toBe("http://10.0.0.5:4000");
167
+ });
168
+
169
+ it("replaces 'api.' subdomain with 'tasks.' and 'ws.' for envApiUrl", () => {
170
+ const urls = resolveBaseUrls({
171
+ envApiUrl: "https://api.staging.example.io",
172
+ expoConstants: {expoConfig: {extra: {}}},
173
+ isDev: false,
174
+ });
175
+ expect(urls.baseUrl).toBe("https://api.staging.example.io");
176
+ expect(urls.baseWebsocketsUrl).toBe("https://ws.staging.example.io/");
177
+ expect(urls.baseTasksUrl).toBe("https://tasks.staging.example.io/tasks");
178
+ });
179
+
180
+ it("handles envApiUrl without 'api.' subdomain gracefully", () => {
181
+ const urls = resolveBaseUrls({
182
+ envApiUrl: "https://backend.example.com",
183
+ expoConstants: {expoConfig: {extra: {}}},
184
+ isDev: false,
185
+ });
186
+ expect(urls.baseUrl).toBe("https://backend.example.com");
187
+ expect(urls.baseWebsocketsUrl).toBe("https://backend.example.com/");
188
+ expect(urls.baseTasksUrl).toBe("https://backend.example.com/tasks");
189
+ });
143
190
  });
144
191
 
145
192
  describe("module-level exports", () => {
@@ -154,7 +201,7 @@ describe("module-level exports", () => {
154
201
  });
155
202
  });
156
203
 
157
- describe("logAuth / logSocket", () => {
204
+ describe("logAuth", () => {
158
205
  const originalDebug = console.debug;
159
206
  const calls: unknown[][] = [];
160
207
 
@@ -173,6 +220,22 @@ describe("logAuth / logSocket", () => {
173
220
  logAuth("auth message");
174
221
  expect(calls).toEqual([]);
175
222
  });
223
+ });
224
+
225
+ describe("logSocket", () => {
226
+ const originalInfo = console.info;
227
+ const calls: unknown[][] = [];
228
+
229
+ beforeEach(() => {
230
+ calls.length = 0;
231
+ console.info = (...args: unknown[]): void => {
232
+ calls.push(args);
233
+ };
234
+ });
235
+
236
+ afterEach(() => {
237
+ console.info = originalInfo;
238
+ });
176
239
 
177
240
  it("logSocket logs when passed boolean true", () => {
178
241
  logSocket(true, "socket message");
@@ -200,5 +263,40 @@ describe("logAuth / logSocket", () => {
200
263
  });
201
264
  });
202
265
 
266
+ describe("setRealtimeDebug / isWebsocketsDebugEnabled", () => {
267
+ const originalInfo = console.info;
268
+ afterEach(() => {
269
+ console.info = originalInfo;
270
+ setRealtimeDebug(false);
271
+ });
272
+
273
+ it("isWebsocketsDebugEnabled returns false by default", () => {
274
+ expect(isWebsocketsDebugEnabled()).toBe(false);
275
+ });
276
+
277
+ it("setRealtimeDebug(true) makes isWebsocketsDebugEnabled return true", () => {
278
+ setRealtimeDebug(true);
279
+ expect(isWebsocketsDebugEnabled()).toBe(true);
280
+ });
281
+
282
+ it("setRealtimeDebug(false) disables runtime debug", () => {
283
+ setRealtimeDebug(true);
284
+ expect(isWebsocketsDebugEnabled()).toBe(true);
285
+ setRealtimeDebug(false);
286
+ expect(isWebsocketsDebugEnabled()).toBe(false);
287
+ });
288
+
289
+ it("logSocket logs when runtime websocket debug is enabled via setRealtimeDebug", () => {
290
+ const calls: unknown[][] = [];
291
+ console.info = (...args: unknown[]): void => {
292
+ calls.push(args);
293
+ };
294
+
295
+ setRealtimeDebug(true);
296
+ logSocket(undefined, "runtime debug message");
297
+ expect(calls).toEqual([["[websocket]", "runtime debug message"]]);
298
+ });
299
+ });
300
+
203
301
  // Mock.module tests (expo tunnel warning, AUTH_DEBUG) moved to
204
302
  // src/isolated/constants.isolated.ts to avoid coverage tracking interference.
package/src/constants.ts CHANGED
@@ -17,12 +17,23 @@ export const logAuth = (...args: string[]): void => {
17
17
  };
18
18
 
19
19
  // Handy debug logging socket events, but not enabled by default.
20
- // Can also be enabled by user feature flag.
20
+ // Can also be enabled by user feature flag or runtime via setRealtimeDebug (admin config).
21
21
  const WEBSOCKETS_DEBUG = Constants.expoConfig?.extra?.WEBSOCKETS_DEBUG === "true";
22
22
  if (WEBSOCKETS_DEBUG) {
23
23
  console.debug("WEBSOCKETS_DEBUG is enabled");
24
24
  }
25
25
 
26
+ let runtimeWebsocketsDebug = false;
27
+
28
+ /** Enable websocket debug logging at runtime (e.g. from admin debug.websocketsDebug). */
29
+ export const setRealtimeDebug = (enabled: boolean): void => {
30
+ runtimeWebsocketsDebug = enabled;
31
+ };
32
+
33
+ export const isWebsocketsDebugEnabled = (): boolean => {
34
+ return WEBSOCKETS_DEBUG || runtimeWebsocketsDebug;
35
+ };
36
+
26
37
  // Handy debug logging for websockets, enabled by user.featureFlags.debugWebsockets.enabled or passing in true.
27
38
  export const logSocket = (
28
39
  user?: {featureFlags?: {debugWebsockets?: {enabled?: boolean}}} | boolean,
@@ -31,9 +42,9 @@ export const logSocket = (
31
42
  if (
32
43
  typeof user === "boolean"
33
44
  ? user
34
- : user?.featureFlags?.debugWebsockets?.enabled || WEBSOCKETS_DEBUG
45
+ : user?.featureFlags?.debugWebsockets?.enabled || isWebsocketsDebugEnabled()
35
46
  ) {
36
- console.debug(`[websocket]`, ...args);
47
+ console.info("[websocket]", ...args);
37
48
  }
38
49
  };
39
50
 
package/src/emptyApi.ts CHANGED
@@ -18,6 +18,7 @@ import {DateTime} from "luxon";
18
18
  import qs from "qs";
19
19
  import {generateProfileEndpoints, getAuthToken} from "./authSlice";
20
20
  import {AUTH_DEBUG, baseUrl, LOGOUT_ACTION_TYPE, TOKEN_REFRESHED_SUCCESS} from "./constants";
21
+ import {shouldDeferOfflineMutation} from "./offlineGate";
21
22
  import {IsWeb} from "./platform";
22
23
 
23
24
  const log = AUTH_DEBUG ? (s: string): void => console.debug(`[auth] ${s}`) : (): void => {};
@@ -25,6 +26,8 @@ const log = AUTH_DEBUG ? (s: string): void => console.debug(`[auth] ${s}`) : ():
25
26
  /** Response from Terreno `GET /version-check` (VersionCheckPlugin). */
26
27
  export interface VersionCheckResponse {
27
28
  message?: string;
29
+ /** How often the client should poll for updates, in milliseconds. */
30
+ pollingIntervalMs?: number;
28
31
  requiredVersion?: number;
29
32
  status: "ok" | "warning" | "required";
30
33
  updateUrl?: string;
@@ -39,10 +42,10 @@ interface TokenPayload {
39
42
  exp: number;
40
43
  }
41
44
 
42
- export async function getTokenExpirationTimes(): Promise<{
45
+ export const getTokenExpirationTimes = async (): Promise<{
43
46
  refreshRemainingSecs?: number;
44
47
  authRemainingSecs?: number;
45
- }> {
48
+ }> => {
46
49
  let refreshToken: string | null;
47
50
  let authToken: string | null;
48
51
  if (!IsWeb) {
@@ -78,7 +81,7 @@ export async function getTokenExpirationTimes(): Promise<{
78
81
  }
79
82
 
80
83
  return {authRemainingSecs: authTimeRemaining, refreshRemainingSecs: refreshTimeRemaining};
81
- }
84
+ };
82
85
 
83
86
  // Helper function to decode token and get expiration info
84
87
  export const getFriendlyExpirationInfo = async (): Promise<string> => {
@@ -210,6 +213,11 @@ export const getBaseQuery = (
210
213
 
211
214
  export const staggeredBaseQuery = retry(
212
215
  async (args: string | FetchArgs, api, extraOptions) => {
216
+ // Short-circuit immediately when offline for configured mutation endpoints
217
+ if (api.type === "mutation" && shouldDeferOfflineMutation(api.endpoint, api.getState)) {
218
+ retry.fail({error: "Network unavailable", status: "FETCH_ERROR"});
219
+ }
220
+
213
221
  // wait until the mutex is available without locking it
214
222
  await mutex.waitForUnlock();
215
223
  let token = await getAuthToken();
package/src/index.ts CHANGED
@@ -5,8 +5,16 @@ export * from "./betterAuthTypes";
5
5
  export * from "./constants";
6
6
  export * from "./emptyApi";
7
7
  export * from "./mongooseSlice";
8
+ export * from "./offlineGate";
9
+ export * from "./offlineMiddleware";
10
+ export * from "./offlineSlice";
8
11
  export * from "./platform";
12
+ export * from "./realtime";
9
13
  export * from "./socket";
14
+ export * from "./sync";
10
15
  export * from "./tagGenerator";
11
16
  export * from "./useFeatureFlags";
17
+ export * from "./useOfflineStatus";
18
+ export * from "./useRealtimeDebug";
19
+ export * from "./useServerStatus";
12
20
  export * from "./useUpgradeCheck";
@@ -36,10 +36,15 @@ describe("expo tunnel warning", () => {
36
36
  describe("AUTH_DEBUG enabled path", () => {
37
37
  it("logs debug messages from logAuth when AUTH_DEBUG is true on module load", async () => {
38
38
  const debugCalls: unknown[][] = [];
39
+ const infoCalls: unknown[][] = [];
39
40
  const originalDebug = console.debug;
41
+ const originalInfo = console.info;
40
42
  console.debug = (...args: unknown[]): void => {
41
43
  debugCalls.push(args);
42
44
  };
45
+ console.info = (...args: unknown[]): void => {
46
+ infoCalls.push(args);
47
+ };
43
48
  mock.module("expo-constants", () => ({
44
49
  default: {expoConfig: {extra: {AUTH_DEBUG: "true", WEBSOCKETS_DEBUG: "true"}}},
45
50
  }));
@@ -51,11 +56,10 @@ describe("AUTH_DEBUG enabled path", () => {
51
56
  loaded.logAuth("hello");
52
57
  expect(debugCalls.length).toBe(preLength + 1);
53
58
  loaded.logSocket(undefined, "ws on");
54
- expect(debugCalls.some((args) => args[0] === "[websocket]" && args[1] === "ws on")).toBe(
55
- true
56
- );
59
+ expect(infoCalls.some((args) => args[0] === "[websocket]" && args[1] === "ws on")).toBe(true);
57
60
  } finally {
58
61
  console.debug = originalDebug;
62
+ console.info = originalInfo;
59
63
  mock.module("expo-constants", () => ({default: {expoConfig: {extra: {}}}}));
60
64
  }
61
65
  });