@terreno/rtk 0.13.3 → 0.14.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.
Files changed (144) hide show
  1. package/dist/authSlice.test.js +2 -10
  2. package/dist/authSlice.test.js.map +1 -1
  3. package/dist/authSliceNative.test.js +11 -3
  4. package/dist/authSliceNative.test.js.map +1 -1
  5. package/dist/betterAuthSlice.test.js +1 -25
  6. package/dist/betterAuthSlice.test.js.map +1 -1
  7. package/dist/constants.d.ts +3 -0
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/constants.js +11 -3
  10. package/dist/constants.js.map +1 -1
  11. package/dist/constants.test.js +44 -2
  12. package/dist/constants.test.js.map +1 -1
  13. package/dist/emptyApi.d.ts +2 -0
  14. package/dist/emptyApi.d.ts.map +1 -1
  15. package/dist/emptyApi.js +5 -0
  16. package/dist/emptyApi.js.map +1 -1
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +8 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/isolated/constants.isolated.js +7 -1
  22. package/dist/isolated/constants.isolated.js.map +1 -1
  23. package/dist/isolated/offlineMiddleware.isolated.d.ts +2 -0
  24. package/dist/isolated/offlineMiddleware.isolated.d.ts.map +1 -0
  25. package/dist/isolated/offlineMiddleware.isolated.js +516 -0
  26. package/dist/isolated/offlineMiddleware.isolated.js.map +1 -0
  27. package/dist/isolated/offlineMiddleware.native.isolated.d.ts +2 -0
  28. package/dist/isolated/offlineMiddleware.native.isolated.d.ts.map +1 -0
  29. package/dist/isolated/offlineMiddleware.native.isolated.js +70 -0
  30. package/dist/isolated/offlineMiddleware.native.isolated.js.map +1 -0
  31. package/dist/isolated/useUpgradeCheck.mobile.isolated.d.ts +2 -0
  32. package/dist/isolated/useUpgradeCheck.mobile.isolated.d.ts.map +1 -0
  33. package/dist/{useUpgradeCheck.mobile.test.js → isolated/useUpgradeCheck.mobile.isolated.js} +13 -5
  34. package/dist/isolated/useUpgradeCheck.mobile.isolated.js.map +1 -0
  35. package/dist/isolated/useUpgradeCheck.web.isolated.d.ts +2 -0
  36. package/dist/isolated/useUpgradeCheck.web.isolated.d.ts.map +1 -0
  37. package/dist/{useUpgradeCheck.test.js → isolated/useUpgradeCheck.web.isolated.js} +37 -7
  38. package/dist/isolated/useUpgradeCheck.web.isolated.js.map +1 -0
  39. package/dist/mongooseSlice.test.js +1 -1
  40. package/dist/mongooseSlice.test.js.map +1 -1
  41. package/dist/offlineGate.d.ts +8 -0
  42. package/dist/offlineGate.d.ts.map +1 -0
  43. package/dist/offlineGate.js +20 -0
  44. package/dist/offlineGate.js.map +1 -0
  45. package/dist/offlineGate.test.d.ts +2 -0
  46. package/dist/offlineGate.test.d.ts.map +1 -0
  47. package/dist/offlineGate.test.js +46 -0
  48. package/dist/offlineGate.test.js.map +1 -0
  49. package/dist/offlineMiddleware.d.ts +46 -0
  50. package/dist/offlineMiddleware.d.ts.map +1 -0
  51. package/dist/offlineMiddleware.js +591 -0
  52. package/dist/offlineMiddleware.js.map +1 -0
  53. package/dist/offlineMiddleware.test.d.ts +2 -0
  54. package/dist/offlineMiddleware.test.d.ts.map +1 -0
  55. package/dist/offlineMiddleware.test.js +145 -0
  56. package/dist/offlineMiddleware.test.js.map +1 -0
  57. package/dist/offlineSlice.d.ts +232 -0
  58. package/dist/offlineSlice.d.ts.map +1 -0
  59. package/dist/offlineSlice.js +65 -0
  60. package/dist/offlineSlice.js.map +1 -0
  61. package/dist/offlineSlice.test.d.ts +2 -0
  62. package/dist/offlineSlice.test.d.ts.map +1 -0
  63. package/dist/offlineSlice.test.js +153 -0
  64. package/dist/offlineSlice.test.js.map +1 -0
  65. package/dist/realtime.d.ts +123 -0
  66. package/dist/realtime.d.ts.map +1 -0
  67. package/dist/realtime.js +299 -0
  68. package/dist/realtime.js.map +1 -0
  69. package/dist/realtime.test.d.ts +2 -0
  70. package/dist/realtime.test.d.ts.map +1 -0
  71. package/dist/realtime.test.js +339 -0
  72. package/dist/realtime.test.js.map +1 -0
  73. package/dist/socket.d.ts.map +1 -1
  74. package/dist/socket.js +29 -28
  75. package/dist/socket.js.map +1 -1
  76. package/dist/sync.d.ts +35 -0
  77. package/dist/sync.d.ts.map +1 -0
  78. package/dist/sync.js +205 -0
  79. package/dist/sync.js.map +1 -0
  80. package/dist/tagGenerator.d.ts +20 -1
  81. package/dist/tagGenerator.d.ts.map +1 -1
  82. package/dist/tagGenerator.js +1 -2
  83. package/dist/tagGenerator.js.map +1 -1
  84. package/dist/useOfflineStatus.d.ts +33 -0
  85. package/dist/useOfflineStatus.d.ts.map +1 -0
  86. package/dist/useOfflineStatus.js +43 -0
  87. package/dist/useOfflineStatus.js.map +1 -0
  88. package/dist/useOfflineStatus.test.d.ts +2 -0
  89. package/dist/useOfflineStatus.test.d.ts.map +1 -0
  90. package/dist/useOfflineStatus.test.js +119 -0
  91. package/dist/useOfflineStatus.test.js.map +1 -0
  92. package/dist/useRealtimeDebug.d.ts +6 -0
  93. package/dist/useRealtimeDebug.d.ts.map +1 -0
  94. package/dist/useRealtimeDebug.js +41 -0
  95. package/dist/useRealtimeDebug.js.map +1 -0
  96. package/dist/useServerStatus.d.ts +29 -0
  97. package/dist/useServerStatus.d.ts.map +1 -0
  98. package/dist/useServerStatus.js +89 -0
  99. package/dist/useServerStatus.js.map +1 -0
  100. package/dist/useUpgradeCheck.d.ts +7 -3
  101. package/dist/useUpgradeCheck.d.ts.map +1 -1
  102. package/dist/useUpgradeCheck.js +27 -13
  103. package/dist/useUpgradeCheck.js.map +1 -1
  104. package/package.json +2 -2
  105. package/src/authSlice.test.ts +2 -11
  106. package/src/authSliceNative.test.ts +11 -4
  107. package/src/betterAuthSlice.test.ts +1 -25
  108. package/src/constants.test.ts +54 -1
  109. package/src/constants.ts +14 -3
  110. package/src/emptyApi.ts +8 -0
  111. package/src/index.ts +8 -0
  112. package/src/isolated/constants.isolated.ts +7 -3
  113. package/src/isolated/offlineMiddleware.isolated.ts +696 -0
  114. package/src/isolated/offlineMiddleware.native.isolated.ts +80 -0
  115. package/src/{useUpgradeCheck.mobile.test.ts → isolated/useUpgradeCheck.mobile.isolated.ts} +13 -4
  116. package/src/{useUpgradeCheck.test.ts → isolated/useUpgradeCheck.web.isolated.ts} +48 -6
  117. package/src/mongooseSlice.test.ts +1 -1
  118. package/src/offlineGate.test.ts +55 -0
  119. package/src/offlineGate.ts +25 -0
  120. package/src/offlineMiddleware.test.ts +187 -0
  121. package/src/offlineMiddleware.ts +718 -0
  122. package/src/offlineSlice.test.ts +204 -0
  123. package/src/offlineSlice.ts +130 -0
  124. package/src/realtime.test.ts +404 -0
  125. package/src/realtime.ts +408 -0
  126. package/src/socket.ts +33 -32
  127. package/src/sync.ts +310 -0
  128. package/src/tagGenerator.ts +29 -11
  129. package/src/useOfflineStatus.test.ts +157 -0
  130. package/src/useOfflineStatus.ts +82 -0
  131. package/src/useRealtimeDebug.ts +51 -0
  132. package/src/useServerStatus.ts +122 -0
  133. package/src/useUpgradeCheck.ts +35 -13
  134. package/dist/isolated/useUpgradeCheck.isolated.d.ts +0 -2
  135. package/dist/isolated/useUpgradeCheck.isolated.d.ts.map +0 -1
  136. package/dist/isolated/useUpgradeCheck.isolated.js +0 -153
  137. package/dist/isolated/useUpgradeCheck.isolated.js.map +0 -1
  138. package/dist/useUpgradeCheck.mobile.test.d.ts +0 -2
  139. package/dist/useUpgradeCheck.mobile.test.d.ts.map +0 -1
  140. package/dist/useUpgradeCheck.mobile.test.js.map +0 -1
  141. package/dist/useUpgradeCheck.test.d.ts +0 -2
  142. package/dist/useUpgradeCheck.test.d.ts.map +0 -1
  143. package/dist/useUpgradeCheck.test.js.map +0 -1
  144. package/src/isolated/useUpgradeCheck.isolated.ts +0 -201
@@ -0,0 +1,145 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { configureStore } from "@reduxjs/toolkit";
3
+ import { buildOptimisticCreateItem, createOfflineMiddleware, isNetworkFetchError, shouldReplayQueuedMutation, } from "./offlineMiddleware";
4
+ import { selectOfflineQueue } from "./offlineSlice";
5
+ const LIST_QUERY_ARGS = {};
6
+ const LIST_UPDATED_AT = "2026-05-23T21:00:00.123Z";
7
+ const initialTestApiState = {
8
+ queries: {
9
+ "getTodos({})": {
10
+ data: {
11
+ data: [
12
+ {
13
+ _id: "todo-1",
14
+ title: "Original",
15
+ updated: LIST_UPDATED_AT,
16
+ },
17
+ ],
18
+ },
19
+ originalArgs: LIST_QUERY_ARGS,
20
+ },
21
+ },
22
+ };
23
+ const testApiReducer = (state = initialTestApiState) => state;
24
+ // biome-ignore lint/suspicious/noExplicitAny: Test double covers only fields used by offline middleware.
25
+ const createTestApi = () => {
26
+ return {
27
+ endpoints: {
28
+ getTodos: {
29
+ select: (queryArg) => {
30
+ return (state) => {
31
+ return Object.values(state.testApi.queries).find((entry) => entry.originalArgs === queryArg);
32
+ };
33
+ },
34
+ },
35
+ },
36
+ reducerPath: "testApi",
37
+ util: {
38
+ invalidateTags: () => ({ type: "testApi/invalidateTags" }),
39
+ updateQueryData: () => ({ type: "testApi/updateQueryData" }),
40
+ },
41
+ // biome-ignore lint/suspicious/noExplicitAny: Test double covers only fields used by offline middleware.
42
+ };
43
+ };
44
+ describe("isNetworkFetchError", () => {
45
+ it("returns true for TypeError error name", () => {
46
+ expect(isNetworkFetchError({ error: { name: "TypeError" } })).toBe(true);
47
+ });
48
+ it("returns true for network error messages", () => {
49
+ expect(isNetworkFetchError({ error: { message: "Failed to fetch" } })).toBe(true);
50
+ expect(isNetworkFetchError({ error: { message: "fetch failed" } })).toBe(true);
51
+ expect(isNetworkFetchError({ error: { message: "Network Error" } })).toBe(true);
52
+ expect(isNetworkFetchError({ error: { message: "Network unavailable" } })).toBe(true);
53
+ expect(isNetworkFetchError({ error: { message: "Load failed" } })).toBe(true);
54
+ });
55
+ it("returns true for string error fields", () => {
56
+ expect(isNetworkFetchError({ error: "fetch failed" })).toBe(true);
57
+ expect(isNetworkFetchError({ payload: { error: "network error" } })).toBe(true);
58
+ expect(isNetworkFetchError({ error: "Failed to fetch", status: "FETCH_ERROR" })).toBe(true);
59
+ });
60
+ it("returns false for non-network errors", () => {
61
+ expect(isNetworkFetchError({ error: "Unauthorized", status: "FETCH_ERROR" })).toBe(false);
62
+ expect(isNetworkFetchError({ error: { message: "Unauthorized" } })).toBe(false);
63
+ expect(isNetworkFetchError(null)).toBe(false);
64
+ expect(isNetworkFetchError(undefined)).toBe(false);
65
+ expect(isNetworkFetchError({})).toBe(false);
66
+ });
67
+ });
68
+ describe("shouldReplayQueuedMutation", () => {
69
+ const baseMutation = {
70
+ args: { body: { title: "Test" } },
71
+ endpointName: "postTodos",
72
+ id: "m1",
73
+ timestamp: "2026-04-15T10:00:00.000Z",
74
+ type: "create",
75
+ userId: "user-a",
76
+ };
77
+ it("replays only mutations owned by the current user", () => {
78
+ expect(shouldReplayQueuedMutation(baseMutation, "user-a")).toBe(true);
79
+ expect(shouldReplayQueuedMutation(baseMutation, "user-b")).toBe(false);
80
+ expect(shouldReplayQueuedMutation(baseMutation, undefined)).toBe(false);
81
+ });
82
+ it("does not replay legacy mutations without userId", () => {
83
+ const legacy = { ...baseMutation, userId: undefined };
84
+ expect(shouldReplayQueuedMutation(legacy, "user-a")).toBe(false);
85
+ });
86
+ });
87
+ describe("buildOptimisticCreateItem", () => {
88
+ const mutation = {
89
+ args: { body: { title: "New" } },
90
+ endpointName: "postTodos",
91
+ id: "queue-1",
92
+ timestamp: "2026-04-15T10:00:00.000Z",
93
+ type: "create",
94
+ };
95
+ it("applies temp ids after body spread so client ids cannot win", () => {
96
+ const item = buildOptimisticCreateItem(mutation, {
97
+ _id: "client-id",
98
+ id: "client-id",
99
+ title: "New",
100
+ });
101
+ expect(item._id).toBe("temp-queue-1");
102
+ expect(item.id).toBe("temp-queue-1");
103
+ expect(item.title).toBe("New");
104
+ expect(item.created).toBe(mutation.timestamp);
105
+ expect(item.updated).toBe(mutation.timestamp);
106
+ });
107
+ });
108
+ describe("offlineMiddleware", () => {
109
+ it("uses list-cache updated timestamp for queued update conflict headers", async () => {
110
+ const api = createTestApi();
111
+ const offline = createOfflineMiddleware({
112
+ api,
113
+ endpoints: ["patchTodosById"],
114
+ });
115
+ const store = configureStore({
116
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }).concat(offline.middleware),
117
+ reducer: {
118
+ auth: (state = { userId: "user-a" }) => state,
119
+ offline: offline.offlineReducer,
120
+ testApi: testApiReducer,
121
+ },
122
+ });
123
+ const rejectedMutation = {
124
+ error: { message: "Network unavailable" },
125
+ meta: {
126
+ arg: {
127
+ endpointName: "patchTodosById",
128
+ originalArgs: {
129
+ body: { title: "Queued title" },
130
+ id: "todo-1",
131
+ },
132
+ },
133
+ },
134
+ type: "testApi/executeMutation/rejected",
135
+ };
136
+ store.dispatch(rejectedMutation);
137
+ await new Promise((resolve) => setTimeout(resolve, 0));
138
+ const queue = selectOfflineQueue(store.getState());
139
+ expect(queue).toHaveLength(1);
140
+ expect(queue[0].baseUpdatedAt).toBe(LIST_UPDATED_AT);
141
+ expect(queue[0].timestamp).toBe(LIST_UPDATED_AT);
142
+ expect(queue[0].userId).toBe("user-a");
143
+ });
144
+ });
145
+ //# sourceMappingURL=offlineMiddleware.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offlineMiddleware.test.js","sourceRoot":"","sources":["../src/offlineMiddleware.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,232 @@
1
+ import { type PayloadAction } from "@reduxjs/toolkit";
2
+ export interface QueuedMutation {
3
+ /** Unique identifier for this queued mutation */
4
+ id: string;
5
+ /** RTK Query endpoint name, e.g. "patchTodosById" */
6
+ endpointName: string;
7
+ /** Original mutation arguments */
8
+ args: unknown;
9
+ /** ISO timestamp of when the mutation was queued */
10
+ timestamp: string;
11
+ /** Document `_updatedAt` at queue time (used for If-Unmodified-Since on replay) */
12
+ baseUpdatedAt?: string;
13
+ /** The type of CRUD operation */
14
+ type: "create" | "update" | "delete";
15
+ /** Auth user ID when the mutation was queued; replay is skipped if it does not match the current user */
16
+ userId?: string;
17
+ }
18
+ export interface ConflictRecord {
19
+ /** Unique identifier for this conflict */
20
+ id: string;
21
+ /** RTK Query endpoint name that caused the conflict */
22
+ endpointName: string;
23
+ /** Original mutation arguments that were rejected */
24
+ args: unknown;
25
+ /** The current server version of the document */
26
+ serverDocument: unknown;
27
+ /** ISO timestamp of when the conflict was detected */
28
+ timestamp: string;
29
+ /** Whether the user has dismissed this conflict notification */
30
+ dismissed: boolean;
31
+ }
32
+ export interface OfflineState {
33
+ isOnline: boolean;
34
+ queue: QueuedMutation[];
35
+ conflicts: ConflictRecord[];
36
+ isSyncing: boolean;
37
+ }
38
+ export declare const offlineSlice: import("@reduxjs/toolkit").Slice<OfflineState, {
39
+ addConflict(state: {
40
+ isOnline: boolean;
41
+ queue: {
42
+ id: string;
43
+ endpointName: string;
44
+ args: unknown;
45
+ timestamp: string;
46
+ baseUpdatedAt?: string | undefined;
47
+ type: "create" | "update" | "delete";
48
+ userId?: string | undefined;
49
+ }[];
50
+ conflicts: {
51
+ id: string;
52
+ endpointName: string;
53
+ args: unknown;
54
+ serverDocument: unknown;
55
+ timestamp: string;
56
+ dismissed: boolean;
57
+ }[];
58
+ isSyncing: boolean;
59
+ }, action: PayloadAction<ConflictRecord>): void;
60
+ clearConflicts(state: {
61
+ isOnline: boolean;
62
+ queue: {
63
+ id: string;
64
+ endpointName: string;
65
+ args: unknown;
66
+ timestamp: string;
67
+ baseUpdatedAt?: string | undefined;
68
+ type: "create" | "update" | "delete";
69
+ userId?: string | undefined;
70
+ }[];
71
+ conflicts: {
72
+ id: string;
73
+ endpointName: string;
74
+ args: unknown;
75
+ serverDocument: unknown;
76
+ timestamp: string;
77
+ dismissed: boolean;
78
+ }[];
79
+ isSyncing: boolean;
80
+ }): void;
81
+ clearQueue(state: {
82
+ isOnline: boolean;
83
+ queue: {
84
+ id: string;
85
+ endpointName: string;
86
+ args: unknown;
87
+ timestamp: string;
88
+ baseUpdatedAt?: string | undefined;
89
+ type: "create" | "update" | "delete";
90
+ userId?: string | undefined;
91
+ }[];
92
+ conflicts: {
93
+ id: string;
94
+ endpointName: string;
95
+ args: unknown;
96
+ serverDocument: unknown;
97
+ timestamp: string;
98
+ dismissed: boolean;
99
+ }[];
100
+ isSyncing: boolean;
101
+ }): void;
102
+ dequeue(state: {
103
+ isOnline: boolean;
104
+ queue: {
105
+ id: string;
106
+ endpointName: string;
107
+ args: unknown;
108
+ timestamp: string;
109
+ baseUpdatedAt?: string | undefined;
110
+ type: "create" | "update" | "delete";
111
+ userId?: string | undefined;
112
+ }[];
113
+ conflicts: {
114
+ id: string;
115
+ endpointName: string;
116
+ args: unknown;
117
+ serverDocument: unknown;
118
+ timestamp: string;
119
+ dismissed: boolean;
120
+ }[];
121
+ isSyncing: boolean;
122
+ }, action: PayloadAction<string>): void;
123
+ dismissConflict(state: {
124
+ isOnline: boolean;
125
+ queue: {
126
+ id: string;
127
+ endpointName: string;
128
+ args: unknown;
129
+ timestamp: string;
130
+ baseUpdatedAt?: string | undefined;
131
+ type: "create" | "update" | "delete";
132
+ userId?: string | undefined;
133
+ }[];
134
+ conflicts: {
135
+ id: string;
136
+ endpointName: string;
137
+ args: unknown;
138
+ serverDocument: unknown;
139
+ timestamp: string;
140
+ dismissed: boolean;
141
+ }[];
142
+ isSyncing: boolean;
143
+ }, action: PayloadAction<string>): void;
144
+ enqueue(state: {
145
+ isOnline: boolean;
146
+ queue: {
147
+ id: string;
148
+ endpointName: string;
149
+ args: unknown;
150
+ timestamp: string;
151
+ baseUpdatedAt?: string | undefined;
152
+ type: "create" | "update" | "delete";
153
+ userId?: string | undefined;
154
+ }[];
155
+ conflicts: {
156
+ id: string;
157
+ endpointName: string;
158
+ args: unknown;
159
+ serverDocument: unknown;
160
+ timestamp: string;
161
+ dismissed: boolean;
162
+ }[];
163
+ isSyncing: boolean;
164
+ }, action: PayloadAction<QueuedMutation>): void;
165
+ setOnlineStatus(state: {
166
+ isOnline: boolean;
167
+ queue: {
168
+ id: string;
169
+ endpointName: string;
170
+ args: unknown;
171
+ timestamp: string;
172
+ baseUpdatedAt?: string | undefined;
173
+ type: "create" | "update" | "delete";
174
+ userId?: string | undefined;
175
+ }[];
176
+ conflicts: {
177
+ id: string;
178
+ endpointName: string;
179
+ args: unknown;
180
+ serverDocument: unknown;
181
+ timestamp: string;
182
+ dismissed: boolean;
183
+ }[];
184
+ isSyncing: boolean;
185
+ }, action: PayloadAction<boolean>): void;
186
+ setSyncing(state: {
187
+ isOnline: boolean;
188
+ queue: {
189
+ id: string;
190
+ endpointName: string;
191
+ args: unknown;
192
+ timestamp: string;
193
+ baseUpdatedAt?: string | undefined;
194
+ type: "create" | "update" | "delete";
195
+ userId?: string | undefined;
196
+ }[];
197
+ conflicts: {
198
+ id: string;
199
+ endpointName: string;
200
+ args: unknown;
201
+ serverDocument: unknown;
202
+ timestamp: string;
203
+ dismissed: boolean;
204
+ }[];
205
+ isSyncing: boolean;
206
+ }, action: PayloadAction<boolean>): void;
207
+ }, "offline", "offline", import("@reduxjs/toolkit").SliceSelectors<OfflineState>>;
208
+ export declare const setOnlineStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<boolean, "offline/setOnlineStatus">, enqueue: import("@reduxjs/toolkit").ActionCreatorWithPayload<QueuedMutation, "offline/enqueue">, dequeue: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "offline/dequeue">, clearQueue: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"offline/clearQueue">, addConflict: import("@reduxjs/toolkit").ActionCreatorWithPayload<ConflictRecord, "offline/addConflict">, dismissConflict: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "offline/dismissConflict">, clearConflicts: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"offline/clearConflicts">, setSyncing: import("@reduxjs/toolkit").ActionCreatorWithPayload<boolean, "offline/setSyncing">;
209
+ export declare const offlineReducer: import("@reduxjs/toolkit").Reducer<OfflineState>;
210
+ export declare const selectIsOnline: (state: {
211
+ offline: OfflineState;
212
+ }) => boolean;
213
+ /** Safe online check when the offline reducer may not be mounted (defaults to online). */
214
+ export declare const selectIsOnlineSafe: (state: {
215
+ offline?: OfflineState;
216
+ }) => boolean;
217
+ export declare const selectOfflineQueue: (state: {
218
+ offline: OfflineState;
219
+ }) => QueuedMutation[];
220
+ export declare const selectQueueLength: (state: {
221
+ offline: OfflineState;
222
+ }) => number;
223
+ export declare const selectConflicts: (state: {
224
+ offline: OfflineState;
225
+ }) => ConflictRecord[];
226
+ export declare const selectUndismissedConflicts: (state: {
227
+ offline: OfflineState;
228
+ }) => ConflictRecord[];
229
+ export declare const selectIsSyncing: (state: {
230
+ offline: OfflineState;
231
+ }) => boolean;
232
+ //# sourceMappingURL=offlineSlice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offlineSlice.d.ts","sourceRoot":"","sources":["../src/offlineSlice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAYjE,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,yGAAyG;IACzG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,IAAI,EAAE,OAAO,CAAC;IACd,iDAAiD;IACjD,cAAc,EAAE,OAAO,CAAC;IACxB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;CACpB;AASD,eAAO,MAAM,YAAY;;kBAbb,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eAmBW,aAAa,CAAC,cAAc,CAAC;;kBAtBhD,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;;;kBAHR,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;;;kBAHR,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eA4BO,aAAa,CAAC,MAAM,CAAC;;kBA/BpC,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eA+Be,aAAa,CAAC,MAAM,CAAC;;kBAlC5C,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eAqCO,aAAa,CAAC,cAAc,CAAC;;kBAxC5C,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eAwCe,aAAa,CAAC,OAAO,CAAC;;kBA3C7C,OAAO;;gBA/Bb,MAAM;0BAEI,MAAM;kBAEd,OAAO;uBAEF,MAAM;4BAED,MAAM;kBAEhB,QAAQ,GAAG,QAAQ,GAAG,QAAQ;qBAE3B,MAAM;;;gBAKX,MAAM;0BAEI,MAAM;kBAEd,OAAO;4BAEG,OAAO;uBAEZ,MAAM;uBAEN,OAAO;;mBAOP,OAAO;eA2CU,aAAa,CAAC,OAAO,CAAC;iFAIlD,CAAC;AAEH,eAAO,MACL,eAAe,2FACf,OAAO,0FACP,OAAO,kFACP,UAAU,gFACV,WAAW,8FACX,eAAe,0FACf,cAAc,oFACd,UAAU,oFACY,CAAC;AAEzB,eAAO,MAAM,cAAc,kDAAuB,CAAC;AAGnD,eAAO,MAAM,cAAc,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,OAAiC,CAAC;AAElG,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,GAAI,OAAO;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAC,KAAG,OACpC,CAAC;AAElC,eAAO,MAAM,kBAAkB,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,cAAc,EAC7D,CAAC;AAEtB,eAAO,MAAM,iBAAiB,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,MACvC,CAAC;AAE7B,eAAO,MAAM,eAAe,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,cAAc,EACtD,CAAC;AAE1B,eAAO,MAAM,0BAA0B,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,cAAc,EACrC,CAAC;AAEtD,eAAO,MAAM,eAAe,GAAI,OAAO;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,KAAG,OAAkC,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+ import { REHYDRATE } from "redux-persist";
3
+ import { IsWeb } from "./platform";
4
+ const getInitialOnlineStatus = () => {
5
+ if (IsWeb && typeof navigator !== "undefined" && typeof navigator.onLine === "boolean") {
6
+ return navigator.onLine;
7
+ }
8
+ return true;
9
+ };
10
+ const initialState = {
11
+ conflicts: [],
12
+ isOnline: getInitialOnlineStatus(),
13
+ isSyncing: false,
14
+ queue: [],
15
+ };
16
+ export const offlineSlice = createSlice({
17
+ extraReducers: (builder) => {
18
+ builder.addCase(REHYDRATE, (state) => {
19
+ state.isSyncing = false;
20
+ });
21
+ },
22
+ initialState,
23
+ name: "offline",
24
+ reducers: {
25
+ addConflict(state, action) {
26
+ state.conflicts.push(action.payload);
27
+ },
28
+ clearConflicts(state) {
29
+ state.conflicts = [];
30
+ },
31
+ clearQueue(state) {
32
+ state.queue = [];
33
+ },
34
+ dequeue(state, action) {
35
+ state.queue = state.queue.filter((m) => m.id !== action.payload);
36
+ },
37
+ dismissConflict(state, action) {
38
+ const conflict = state.conflicts.find((c) => c.id === action.payload);
39
+ if (conflict) {
40
+ conflict.dismissed = true;
41
+ }
42
+ },
43
+ enqueue(state, action) {
44
+ state.queue.push(action.payload);
45
+ },
46
+ setOnlineStatus(state, action) {
47
+ state.isOnline = action.payload;
48
+ },
49
+ setSyncing(state, action) {
50
+ state.isSyncing = action.payload;
51
+ },
52
+ },
53
+ });
54
+ export const { setOnlineStatus, enqueue, dequeue, clearQueue, addConflict, dismissConflict, clearConflicts, setSyncing, } = offlineSlice.actions;
55
+ export const offlineReducer = offlineSlice.reducer;
56
+ // Selectors
57
+ export const selectIsOnline = (state) => state.offline.isOnline;
58
+ /** Safe online check when the offline reducer may not be mounted (defaults to online). */
59
+ export const selectIsOnlineSafe = (state) => state.offline?.isOnline ?? true;
60
+ export const selectOfflineQueue = (state) => state.offline.queue;
61
+ export const selectQueueLength = (state) => state.offline.queue.length;
62
+ export const selectConflicts = (state) => state.offline.conflicts;
63
+ export const selectUndismissedConflicts = (state) => state.offline.conflicts.filter((c) => !c.dismissed);
64
+ export const selectIsSyncing = (state) => state.offline.isSyncing;
65
+ //# sourceMappingURL=offlineSlice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offlineSlice.js","sourceRoot":"","sources":["../src/offlineSlice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=offlineSlice.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offlineSlice.test.d.ts","sourceRoot":"","sources":["../src/offlineSlice.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,153 @@
1
+ import { beforeEach, describe, expect, it } from "bun:test";
2
+ import { configureStore } from "@reduxjs/toolkit";
3
+ import { REHYDRATE } from "redux-persist";
4
+ import { addConflict, clearConflicts, clearQueue, dequeue, dismissConflict, enqueue, offlineReducer, selectConflicts, selectIsOnline, selectIsOnlineSafe, selectIsSyncing, selectOfflineQueue, selectQueueLength, selectUndismissedConflicts, setOnlineStatus, setSyncing, } from "./offlineSlice";
5
+ const createTestStore = () => configureStore({
6
+ reducer: { offline: offlineReducer },
7
+ });
8
+ describe("offlineSlice", () => {
9
+ let store;
10
+ beforeEach(() => {
11
+ store = createTestStore();
12
+ });
13
+ describe("setOnlineStatus", () => {
14
+ it("sets online status to false", () => {
15
+ store.dispatch(setOnlineStatus(false));
16
+ expect(selectIsOnline(store.getState())).toBe(false);
17
+ });
18
+ it("sets online status to true", () => {
19
+ store.dispatch(setOnlineStatus(false));
20
+ store.dispatch(setOnlineStatus(true));
21
+ expect(selectIsOnline(store.getState())).toBe(true);
22
+ });
23
+ it("defaults to online", () => {
24
+ expect(selectIsOnline(store.getState())).toBe(true);
25
+ });
26
+ });
27
+ describe("mutation queue", () => {
28
+ const mutation1 = {
29
+ args: { body: { title: "Updated" }, id: "123" },
30
+ endpointName: "patchTodosById",
31
+ id: "m1",
32
+ timestamp: "2026-04-15T10:00:00.000Z",
33
+ type: "update",
34
+ };
35
+ const mutation2 = {
36
+ args: { body: { title: "New Todo" } },
37
+ endpointName: "postTodos",
38
+ id: "m2",
39
+ timestamp: "2026-04-15T10:01:00.000Z",
40
+ type: "create",
41
+ };
42
+ it("enqueues mutations in FIFO order", () => {
43
+ store.dispatch(enqueue(mutation1));
44
+ store.dispatch(enqueue(mutation2));
45
+ const queue = selectOfflineQueue(store.getState());
46
+ expect(queue).toHaveLength(2);
47
+ expect(queue[0].id).toBe("m1");
48
+ expect(queue[1].id).toBe("m2");
49
+ });
50
+ it("dequeues by id", () => {
51
+ store.dispatch(enqueue(mutation1));
52
+ store.dispatch(enqueue(mutation2));
53
+ store.dispatch(dequeue("m1"));
54
+ const queue = selectOfflineQueue(store.getState());
55
+ expect(queue).toHaveLength(1);
56
+ expect(queue[0].id).toBe("m2");
57
+ });
58
+ it("clears entire queue", () => {
59
+ store.dispatch(enqueue(mutation1));
60
+ store.dispatch(enqueue(mutation2));
61
+ store.dispatch(clearQueue());
62
+ expect(selectOfflineQueue(store.getState())).toHaveLength(0);
63
+ });
64
+ it("reports queue length", () => {
65
+ expect(selectQueueLength(store.getState())).toBe(0);
66
+ store.dispatch(enqueue(mutation1));
67
+ expect(selectQueueLength(store.getState())).toBe(1);
68
+ store.dispatch(enqueue(mutation2));
69
+ expect(selectQueueLength(store.getState())).toBe(2);
70
+ });
71
+ it("preserves mutation args", () => {
72
+ store.dispatch(enqueue(mutation1));
73
+ const queued = selectOfflineQueue(store.getState())[0];
74
+ expect(queued.args).toEqual({ body: { title: "Updated" }, id: "123" });
75
+ expect(queued.endpointName).toBe("patchTodosById");
76
+ expect(queued.type).toBe("update");
77
+ });
78
+ });
79
+ describe("conflicts", () => {
80
+ const conflict1 = {
81
+ args: { body: { title: "Offline" }, id: "123" },
82
+ dismissed: false,
83
+ endpointName: "patchTodosById",
84
+ id: "c1",
85
+ serverDocument: { _id: "123", title: "Server Version", updated: "2026-04-15T11:00:00.000Z" },
86
+ timestamp: "2026-04-15T10:30:00.000Z",
87
+ };
88
+ const conflict2 = {
89
+ args: { body: { completed: true }, id: "456" },
90
+ dismissed: false,
91
+ endpointName: "patchTodosById",
92
+ id: "c2",
93
+ serverDocument: { _id: "456", completed: false, title: "Other" },
94
+ timestamp: "2026-04-15T10:31:00.000Z",
95
+ };
96
+ it("adds conflict records", () => {
97
+ store.dispatch(addConflict(conflict1));
98
+ expect(selectConflicts(store.getState())).toHaveLength(1);
99
+ expect(selectConflicts(store.getState())[0].id).toBe("c1");
100
+ });
101
+ it("dismisses a conflict", () => {
102
+ store.dispatch(addConflict(conflict1));
103
+ store.dispatch(addConflict(conflict2));
104
+ store.dispatch(dismissConflict("c1"));
105
+ const conflicts = selectConflicts(store.getState());
106
+ expect(conflicts[0].dismissed).toBe(true);
107
+ expect(conflicts[1].dismissed).toBe(false);
108
+ });
109
+ it("filters undismissed conflicts", () => {
110
+ store.dispatch(addConflict(conflict1));
111
+ store.dispatch(addConflict(conflict2));
112
+ store.dispatch(dismissConflict("c1"));
113
+ const undismissed = selectUndismissedConflicts(store.getState());
114
+ expect(undismissed).toHaveLength(1);
115
+ expect(undismissed[0].id).toBe("c2");
116
+ });
117
+ it("clears all conflicts", () => {
118
+ store.dispatch(addConflict(conflict1));
119
+ store.dispatch(addConflict(conflict2));
120
+ store.dispatch(clearConflicts());
121
+ expect(selectConflicts(store.getState())).toHaveLength(0);
122
+ });
123
+ });
124
+ describe("selectIsOnlineSafe", () => {
125
+ it("defaults to online when offline reducer is absent", () => {
126
+ expect(selectIsOnlineSafe({})).toBe(true);
127
+ });
128
+ it("reflects offline state when reducer is mounted", () => {
129
+ store.dispatch(setOnlineStatus(false));
130
+ expect(selectIsOnlineSafe(store.getState())).toBe(false);
131
+ });
132
+ });
133
+ describe("syncing", () => {
134
+ it("defaults to not syncing", () => {
135
+ expect(selectIsSyncing(store.getState())).toBe(false);
136
+ });
137
+ it("sets syncing state", () => {
138
+ store.dispatch(setSyncing(true));
139
+ expect(selectIsSyncing(store.getState())).toBe(true);
140
+ });
141
+ it("clears syncing state", () => {
142
+ store.dispatch(setSyncing(true));
143
+ store.dispatch(setSyncing(false));
144
+ expect(selectIsSyncing(store.getState())).toBe(false);
145
+ });
146
+ it("resets syncing on redux-persist rehydrate", () => {
147
+ store.dispatch(setSyncing(true));
148
+ store.dispatch({ payload: undefined, type: REHYDRATE });
149
+ expect(selectIsSyncing(store.getState())).toBe(false);
150
+ });
151
+ });
152
+ });
153
+ //# sourceMappingURL=offlineSlice.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offlineSlice.test.js","sourceRoot":"","sources":["../src/offlineSlice.test.ts"],"names":[],"mappings":"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"}