stream-chat 9.50.3 → 10.0.0-rc.2
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/dist/cjs/index.browser.js +19798 -14472
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +19817 -14482
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +19795 -14469
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/ChannelManager.d.ts +221 -0
- package/dist/types/EventHandlerPipeline.d.ts +104 -0
- package/dist/types/api-client.d.ts +26 -0
- package/dist/types/campaign.d.ts +0 -44
- package/dist/types/channel.d.ts +454 -479
- package/dist/types/channel_batch_updater.d.ts +0 -93
- package/dist/types/channel_state.d.ts +53 -201
- package/dist/types/client.d.ts +451 -1920
- package/dist/types/client_state.d.ts +4 -4
- package/dist/types/configuration/InstanceConfigurationService.d.ts +26 -0
- package/dist/types/configuration/index.d.ts +1 -0
- package/dist/types/configuration/types.d.ts +53 -0
- package/dist/types/connection.d.ts +49 -41
- package/dist/types/connection_fallback.d.ts +6 -4
- package/dist/types/constants.d.ts +0 -4
- package/dist/types/custom_types.d.ts +2 -0
- package/dist/types/entityStore/EntityStore.d.ts +111 -0
- package/dist/types/entityStore/StoreBackedItemIndex.d.ts +60 -0
- package/dist/types/entityStore/applyReactionLocally.d.ts +26 -0
- package/dist/types/entityStore/index.d.ts +2 -0
- package/dist/types/errors.d.ts +10 -2
- package/dist/types/gen/chat/ChannelApi.d.ts +45 -0
- package/dist/types/gen/chat/ChatApi.d.ts +334 -0
- package/dist/types/gen/model-decoders/decoders.d.ts +3 -0
- package/dist/types/gen/model-decoders/event-decoder-mapping.d.ts +6 -0
- package/dist/types/gen/models/index.d.ts +8836 -0
- package/dist/types/gen/moderation/ModerationApi.d.ts +50 -0
- package/dist/types/gen-imports.d.ts +3 -0
- package/dist/types/index.d.ts +8 -7
- package/dist/types/insights.d.ts +9 -8
- package/dist/types/logger.d.ts +9 -0
- package/dist/types/messageComposer/LocationComposer.d.ts +7 -4
- package/dist/types/messageComposer/attachmentIdentity.d.ts +2 -2
- package/dist/types/messageComposer/attachmentManager.d.ts +8 -4
- package/dist/types/messageComposer/configuration/types.d.ts +11 -11
- package/dist/types/messageComposer/linkPreviewsManager.d.ts +25 -13
- package/dist/types/messageComposer/messageComposer.d.ts +10 -10
- package/dist/types/messageComposer/middleware/messageComposer/types.d.ts +3 -3
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +4 -7
- package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +3 -3
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +7 -7
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +218 -4
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +9 -4
- package/dist/types/messageComposer/pollComposer.d.ts +5 -4
- package/dist/types/messageComposer/textComposer.d.ts +8 -3
- package/dist/types/messageComposer/types.d.ts +6 -28
- package/dist/types/messageDelivery/MessageDeliveryReporter.d.ts +40 -25
- package/dist/types/messageDelivery/MessageReceiptsTracker.d.ts +53 -12
- package/dist/types/messageOperations/MessageOperationStatePolicy.d.ts +19 -0
- package/dist/types/messageOperations/MessageOperations.d.ts +17 -0
- package/dist/types/messageOperations/index.d.ts +3 -0
- package/dist/types/messageOperations/types.d.ts +49 -0
- package/dist/types/moderation.d.ts +21 -203
- package/dist/types/notifications/types.d.ts +8 -7
- package/dist/types/offline-support/offline_support_api.d.ts +111 -87
- package/dist/types/offline-support/offline_sync_manager.d.ts +0 -7
- package/dist/types/offline-support/types.d.ts +19 -23
- package/dist/types/offline-support/util.d.ts +4 -2
- package/dist/types/pagination/FilterBuilder.d.ts +1 -1
- package/dist/types/pagination/ItemIndex.d.ts +25 -0
- package/dist/types/pagination/cursorDerivation/createdAtAroundPaginationFlags.d.ts +9 -0
- package/dist/types/pagination/cursorDerivation/idAroundPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/cursorDerivation/index.d.ts +1 -0
- package/dist/types/pagination/cursorDerivation/linearPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/filterCompiler.d.ts +7 -0
- package/dist/types/pagination/index.d.ts +1 -3
- package/dist/types/pagination/paginators/BasePaginator.d.ts +848 -0
- package/dist/types/pagination/paginators/ChannelPaginator.d.ts +212 -0
- package/dist/types/pagination/paginators/MessageIntervalPaginator.d.ts +282 -0
- package/dist/types/pagination/paginators/MessagePaginator.d.ts +208 -0
- package/dist/types/pagination/paginators/PinnedMessagePaginator.d.ts +39 -0
- package/dist/types/pagination/paginators/ReminderPaginator.d.ts +19 -0
- package/dist/types/pagination/paginators/UserGroupPaginator.d.ts +24 -0
- package/dist/types/pagination/paginators/index.d.ts +7 -0
- package/dist/types/pagination/paginators/stateThrottling.d.ts +2 -0
- package/dist/types/pagination/sortCompiler.d.ts +49 -0
- package/dist/types/pagination/types.normalization.d.ts +11 -0
- package/dist/types/pagination/utility.normalization.d.ts +18 -0
- package/dist/types/pagination/utility.queryChannel.d.ts +26 -0
- package/dist/types/pagination/utility.search.d.ts +13 -0
- package/dist/types/permissions.d.ts +1 -1
- package/dist/types/poll.d.ts +29 -32
- package/dist/types/poll_manager.d.ts +2 -2
- package/dist/types/reminders/Reminder.d.ts +2 -5
- package/dist/types/reminders/ReminderManager.d.ts +2 -9
- package/dist/types/search/MessageSearchSource.d.ts +4 -4
- package/dist/types/search/UserSearchSource.d.ts +1 -1
- package/dist/types/search/types.d.ts +3 -3
- package/dist/types/segment.d.ts +0 -34
- package/dist/types/signing.d.ts +105 -65
- package/dist/types/store.d.ts +1 -0
- package/dist/types/thread.d.ts +70 -34
- package/dist/types/thread_manager.d.ts +3 -3
- package/dist/types/token_manager.d.ts +15 -10
- package/dist/types/types.d.ts +197 -3404
- package/dist/types/utils/FixedSizeQueueCache.d.ts +12 -6
- package/dist/types/utils/WithSubscriptions.d.ts +2 -1
- package/dist/types/utils/concurrency.d.ts +4 -4
- package/dist/types/utils/mergeWith/mergeWith.d.ts +3 -3
- package/dist/types/utils/mergeWith/mergeWithCore.d.ts +8 -3
- package/dist/types/utils/retryable.d.ts +34 -0
- package/dist/types/utils/throttling/throttle.d.ts +36 -0
- package/dist/types/utils.d.ts +100 -194
- package/package.json +7 -3
- package/src/ChannelManager.ts +724 -0
- package/src/CooldownTimer.ts +2 -2
- package/src/EventHandlerPipeline.ts +228 -0
- package/src/LiveLocationManager.ts +12 -11
- package/src/api-client.ts +275 -0
- package/src/campaign.ts +1 -77
- package/src/channel.ts +1344 -1282
- package/src/channel_batch_updater.ts +1 -211
- package/src/channel_state.ts +144 -1013
- package/src/client.ts +936 -3995
- package/src/client_state.ts +4 -4
- package/src/configuration/InstanceConfigurationService.ts +73 -0
- package/src/configuration/index.ts +1 -0
- package/src/configuration/types.ts +81 -0
- package/src/connection.ts +145 -94
- package/src/connection_fallback.ts +29 -27
- package/src/constants.ts +1 -5
- package/src/custom_types.ts +4 -1
- package/src/entityStore/EntityStore.ts +208 -0
- package/src/entityStore/StoreBackedItemIndex.ts +115 -0
- package/src/entityStore/applyReactionLocally.ts +113 -0
- package/src/entityStore/index.ts +2 -0
- package/src/errors.ts +14 -2
- package/src/gen/chat/ChannelApi.ts +275 -0
- package/src/gen/chat/ChatApi.ts +2554 -0
- package/src/gen/model-decoders/decoders.ts +2680 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +198 -0
- package/src/gen/models/index.ts +12673 -0
- package/src/gen/moderation/ModerationApi.ts +607 -0
- package/src/gen-imports.ts +3 -0
- package/src/index.ts +11 -12
- package/src/insights.ts +6 -5
- package/src/logger.ts +28 -0
- package/src/messageComposer/LocationComposer.ts +9 -5
- package/src/messageComposer/MessageComposerEffectHandlers.ts +1 -0
- package/src/messageComposer/attachmentIdentity.ts +16 -9
- package/src/messageComposer/attachmentManager.ts +13 -8
- package/src/messageComposer/configuration/types.ts +11 -11
- package/src/messageComposer/linkPreviewsManager.ts +9 -10
- package/src/messageComposer/messageComposer.ts +57 -53
- package/src/messageComposer/middleware/messageComposer/attachments.ts +1 -2
- package/src/messageComposer/middleware/messageComposer/cleanData.ts +1 -1
- package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/messageComposerState.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/sharedLocation.ts +4 -3
- package/src/messageComposer/middleware/messageComposer/textComposer.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/types.ts +3 -4
- package/src/messageComposer/middleware/messageComposer/userDataInjection.ts +9 -5
- package/src/messageComposer/middleware/pollComposer/state.ts +0 -2
- package/src/messageComposer/middleware/pollComposer/types.ts +4 -7
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -1
- package/src/messageComposer/middleware/textComposer/commandEffects.ts +4 -4
- package/src/messageComposer/middleware/textComposer/commandUtils.ts +3 -6
- package/src/messageComposer/middleware/textComposer/commands.ts +3 -3
- package/src/messageComposer/middleware/textComposer/mentionUtils.ts +1 -1
- package/src/messageComposer/middleware/textComposer/mentions.ts +31 -15
- package/src/messageComposer/middleware/textComposer/types.ts +9 -4
- package/src/messageComposer/pollComposer.ts +6 -8
- package/src/messageComposer/textComposer.ts +27 -2
- package/src/messageComposer/types.ts +6 -28
- package/src/messageDelivery/MessageDeliveryReporter.ts +101 -45
- package/src/messageDelivery/MessageReceiptsTracker.ts +294 -21
- package/src/messageOperations/MessageOperationStatePolicy.ts +77 -0
- package/src/messageOperations/MessageOperations.ts +212 -0
- package/src/messageOperations/index.ts +10 -0
- package/src/messageOperations/types.ts +64 -0
- package/src/moderation.ts +38 -431
- package/src/notifications/types.ts +8 -7
- package/src/offline-support/offline_support_api.ts +200 -133
- package/src/offline-support/offline_sync_manager.ts +23 -44
- package/src/offline-support/types.ts +23 -26
- package/src/offline-support/util.ts +5 -4
- package/src/pagination/FilterBuilder.ts +4 -1
- package/src/pagination/ItemIndex.ts +25 -0
- package/src/pagination/cursorDerivation/createdAtAroundPaginationFlags.ts +73 -0
- package/src/pagination/cursorDerivation/idAroundPaginationFlags.ts +53 -0
- package/src/pagination/cursorDerivation/index.ts +1 -0
- package/src/pagination/cursorDerivation/linearPaginationFlags.ts +86 -0
- package/src/pagination/filterCompiler.ts +196 -0
- package/src/pagination/index.ts +1 -3
- package/src/pagination/paginators/BasePaginator.ts +2859 -0
- package/src/pagination/paginators/ChannelPaginator.ts +729 -0
- package/src/pagination/paginators/MessageIntervalPaginator.ts +1116 -0
- package/src/pagination/paginators/MessagePaginator.ts +508 -0
- package/src/pagination/paginators/PinnedMessagePaginator.ts +108 -0
- package/src/pagination/paginators/ReminderPaginator.ts +107 -0
- package/src/pagination/paginators/UserGroupPaginator.ts +127 -0
- package/src/pagination/paginators/index.ts +7 -0
- package/src/pagination/paginators/stateThrottling.ts +31 -0
- package/src/pagination/sortCompiler.ts +193 -0
- package/src/pagination/types.normalization.ts +14 -0
- package/src/pagination/utility.normalization.ts +106 -0
- package/src/pagination/utility.queryChannel.ts +84 -0
- package/src/pagination/utility.search.ts +80 -0
- package/src/permissions.ts +7 -8
- package/src/poll.ts +101 -110
- package/src/poll_manager.ts +14 -8
- package/src/reminders/Reminder.ts +2 -5
- package/src/reminders/ReminderManager.ts +19 -21
- package/src/search/BaseSearchSource.ts +0 -3
- package/src/search/ChannelMemberSearchSource.ts +7 -1
- package/src/search/ChannelSearchSource.ts +10 -3
- package/src/search/MessageSearchSource.ts +29 -30
- package/src/search/UserSearchSource.ts +12 -8
- package/src/search/types.ts +3 -4
- package/src/segment.ts +1 -95
- package/src/signing.ts +107 -67
- package/src/store.ts +2 -1
- package/src/thread.ts +562 -238
- package/src/thread_manager.ts +37 -16
- package/src/token_manager.ts +21 -10
- package/src/types.ts +364 -4533
- package/src/uploadManager.ts +8 -0
- package/src/utils/FixedSizeQueueCache.ts +12 -6
- package/src/utils/WithSubscriptions.ts +2 -1
- package/src/utils/concurrency.ts +4 -4
- package/src/utils/mergeWith/mergeWith.ts +3 -3
- package/src/utils/mergeWith/mergeWithCore.ts +140 -164
- package/src/utils/mergeWith/mergeWithDiff.ts +3 -3
- package/src/utils/retryable.ts +117 -0
- package/src/utils/throttling/throttle.ts +130 -0
- package/src/utils.ts +208 -754
- package/dist/types/channel_manager.d.ts +0 -122
- package/dist/types/events.d.ts +0 -72
- package/dist/types/pagination/BasePaginator.d.ts +0 -69
- package/dist/types/pagination/ReminderPaginator.d.ts +0 -16
- package/dist/types/pagination/UserGroupPaginator.d.ts +0 -21
- package/src/channel_manager.ts +0 -830
- package/src/events.ts +0 -75
- package/src/pagination/BasePaginator.ts +0 -184
- package/src/pagination/ReminderPaginator.ts +0 -56
- package/src/pagination/UserGroupPaginator.ts +0 -93
package/src/uploadManager.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { StreamChat } from './client';
|
|
2
|
+
import { chatLoggerSystem } from './logger';
|
|
2
3
|
import type { UploadRequestOptions } from './messageComposer/configuration/types';
|
|
3
4
|
import { StateStore } from './store';
|
|
4
5
|
import type { AttachmentManager } from '.';
|
|
5
6
|
|
|
7
|
+
const logger = chatLoggerSystem.getLogger('upload-manager');
|
|
8
|
+
|
|
6
9
|
export type UploadRecord = {
|
|
7
10
|
id: string;
|
|
8
11
|
uploadProgress?: number;
|
|
@@ -150,6 +153,11 @@ export class UploadManager {
|
|
|
150
153
|
);
|
|
151
154
|
resolvePromise(response);
|
|
152
155
|
} catch (error) {
|
|
156
|
+
if (!abortController.signal.aborted) {
|
|
157
|
+
logger
|
|
158
|
+
.withExtraTags('upload', channelCid)
|
|
159
|
+
.error(`Upload "${id}" failed.`, { error });
|
|
160
|
+
}
|
|
153
161
|
rejectPromise(error);
|
|
154
162
|
} finally {
|
|
155
163
|
this.inFlightUploads.delete(id);
|
|
@@ -2,6 +2,7 @@ type Dispose<K, T> = (key: K, value: T) => void;
|
|
|
2
2
|
/**
|
|
3
3
|
* A cache that stores a fixed number of values in a queue.
|
|
4
4
|
* The most recently added or retrieved value is kept at the front of the queue.
|
|
5
|
+
*
|
|
5
6
|
* @template K - The type of the keys.
|
|
6
7
|
* @template T - The type of the values.
|
|
7
8
|
*/
|
|
@@ -20,9 +21,10 @@ export class FixedSizeQueueCache<K, T> {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* Adds a new or moves the existing reference to the front of the queue
|
|
24
|
-
*
|
|
25
|
-
* @param
|
|
24
|
+
* Adds a new entry or moves the existing reference to the front of the queue.
|
|
25
|
+
*
|
|
26
|
+
* @param key - The cache key.
|
|
27
|
+
* @param value - The value to associate with `key`.
|
|
26
28
|
*/
|
|
27
29
|
add(key: K, value: T) {
|
|
28
30
|
const index = this.keys.indexOf(key);
|
|
@@ -48,8 +50,10 @@ export class FixedSizeQueueCache<K, T> {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
|
-
* Retrieves the value by key.
|
|
52
|
-
*
|
|
53
|
+
* Retrieves the value by key without changing its position in the queue.
|
|
54
|
+
*
|
|
55
|
+
* @param key - The cache key.
|
|
56
|
+
* @returns The value, or `undefined` when the key is not cached.
|
|
53
57
|
*/
|
|
54
58
|
peek(key: K) {
|
|
55
59
|
const value = this.map.get(key);
|
|
@@ -59,7 +63,9 @@ export class FixedSizeQueueCache<K, T> {
|
|
|
59
63
|
|
|
60
64
|
/**
|
|
61
65
|
* Retrieves the value and moves it to the front of the queue.
|
|
62
|
-
*
|
|
66
|
+
*
|
|
67
|
+
* @param key - The cache key.
|
|
68
|
+
* @returns The value, or `undefined` when the key is not cached.
|
|
63
69
|
*/
|
|
64
70
|
get(key: K) {
|
|
65
71
|
const foundItem = this.peek(key);
|
package/src/utils/concurrency.ts
CHANGED
|
@@ -16,9 +16,9 @@ type AsyncWrapper<P extends unknown[], T> = (
|
|
|
16
16
|
* should never run simultaneously: if marked with the same tag, functions
|
|
17
17
|
* will run one after another.
|
|
18
18
|
*
|
|
19
|
-
* @param tag Async functions with the same tag will run serially. Async functions
|
|
19
|
+
* @param tag - Async functions with the same tag will run serially. Async functions
|
|
20
20
|
* with different tags can run in parallel.
|
|
21
|
-
* @param cb Async function to run.
|
|
21
|
+
* @param cb - Async function to run.
|
|
22
22
|
* @returns Promise that resolves when async functions returns.
|
|
23
23
|
*/
|
|
24
24
|
export const withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
@@ -32,9 +32,9 @@ export const withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
|
32
32
|
* If an async function is already running and was canceled, it will be notified
|
|
33
33
|
* via an abort signal passed as an argument.
|
|
34
34
|
*
|
|
35
|
-
* @param tag Async functions with the same tag will run serially and are canceled
|
|
35
|
+
* @param tag - Async functions with the same tag will run serially and are canceled
|
|
36
36
|
* when a new action with the same tag is scheduled.
|
|
37
|
-
* @param cb Async function to run. Receives AbortSignal as the only argument.
|
|
37
|
+
* @param cb - Async function to run. Receives AbortSignal as the only argument.
|
|
38
38
|
* @returns Promise that resolves when async functions returns. If the function didn't
|
|
39
39
|
* start and was canceled, will resolve with 'canceled'. If the function started to run,
|
|
40
40
|
* it's up to the function to decide how to react to cancelation.
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* (objValue, srcValue, key, object, source, stack).
|
|
7
7
|
*
|
|
8
8
|
* @category Object
|
|
9
|
-
* @param object The destination object.
|
|
10
|
-
* @param source A single source object or an array of objects to be merged into the .
|
|
11
|
-
* @param customizer The function to customize assigned values.
|
|
9
|
+
* @param object - The destination object.
|
|
10
|
+
* @param source - A single source object or an array of objects to be merged into the .
|
|
11
|
+
* @param customizer - The function to customize assigned values.
|
|
12
12
|
* @returns Returns `object`.
|
|
13
13
|
* @example
|
|
14
14
|
*
|
|
@@ -44,177 +44,162 @@ export const isClassInstance = (value: unknown): boolean => {
|
|
|
44
44
|
return value.constructor && value.constructor !== Object;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
type PairMemo = WeakMap<object, WeakSet<object>>;
|
|
48
|
+
|
|
49
|
+
function memoHasOrAdd(memo: PairMemo, a: object, b: object): boolean {
|
|
50
|
+
const set = memo.get(a);
|
|
51
|
+
if (set && set.has(b)) return true;
|
|
52
|
+
if (set) set.add(b);
|
|
53
|
+
else memo.set(a, new WeakSet([b]));
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
58
|
+
* Deep semantic equality with cycle safety and symbol-key support.
|
|
59
|
+
* Keeps your existing semantics:
|
|
60
|
+
* - Dates/RegExps compared by value
|
|
61
|
+
* - "Class instances" are treated atomically (unequal unless ===)
|
|
62
|
+
* - NaN equals NaN; -0 equals 0 (same as ===)
|
|
50
63
|
*/
|
|
51
64
|
export const isEqual = (
|
|
52
65
|
value1: unknown,
|
|
53
66
|
value2: unknown,
|
|
54
|
-
|
|
55
|
-
objectStack1 = new WeakSet<object>(),
|
|
56
|
-
objectStack2 = new WeakSet<object>(),
|
|
67
|
+
pairMemo: PairMemo = new WeakMap(),
|
|
57
68
|
): boolean => {
|
|
58
|
-
//
|
|
59
|
-
if (value1 === value2) return true;
|
|
60
|
-
|
|
61
|
-
// If either is null/undefined, they're not equal (already checked ===)
|
|
69
|
+
if (value1 === value2) return true; // includes -0 === 0
|
|
62
70
|
if (value1 == null || value2 == null) return false;
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
72
|
+
const t1 = typeof value1;
|
|
73
|
+
const t2 = typeof value2;
|
|
74
|
+
if (t1 !== t2) return false;
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// Handle non-object types that need special comparison
|
|
72
|
-
if (type1 !== 'object') {
|
|
73
|
-
// Special case for NaN
|
|
76
|
+
if (t1 !== 'object') {
|
|
77
|
+
// NaN handling
|
|
74
78
|
// eslint-disable-next-line no-self-compare
|
|
75
|
-
|
|
76
|
-
return value1 === value2;
|
|
79
|
+
return value1 !== value1 && value2 !== value2 ? true : value1 === value2;
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
//
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
// Check for circular references in each object
|
|
84
|
-
if (objectStack1.has(obj1) || objectStack2.has(obj2)) {
|
|
85
|
-
// If either object has been seen before, consider them equal
|
|
86
|
-
// if they're both in a circular reference
|
|
87
|
-
return objectStack1.has(obj1) && objectStack2.has(obj2);
|
|
88
|
-
}
|
|
82
|
+
// Objects
|
|
83
|
+
const o1 = value1 as object;
|
|
84
|
+
const o2 = value2 as object;
|
|
89
85
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
// Fast path for tag mismatch
|
|
87
|
+
const tag1 = Object.prototype.toString.call(o1);
|
|
88
|
+
const tag2 = Object.prototype.toString.call(o2);
|
|
89
|
+
if (tag1 !== tag2) return false;
|
|
93
90
|
|
|
94
|
-
//
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
objectStack2.delete(obj2);
|
|
98
|
-
return value1.getTime() === value2.getTime();
|
|
91
|
+
// Special cases before instance test
|
|
92
|
+
if (o1 instanceof Date && o2 instanceof Date) {
|
|
93
|
+
return (o1 as Date).getTime() === (o2 as Date).getTime();
|
|
99
94
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
objectStack2.delete(obj2);
|
|
105
|
-
return value1.toString() === value2.toString();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// If either is a class instance, use reference equality (already checked above)
|
|
109
|
-
if (isClassInstance(value1) || isClassInstance(value2)) {
|
|
110
|
-
// Clean up before returning
|
|
111
|
-
objectStack1.delete(obj1);
|
|
112
|
-
objectStack2.delete(obj2);
|
|
113
|
-
return false;
|
|
95
|
+
if (o1 instanceof RegExp && o2 instanceof RegExp) {
|
|
96
|
+
const r1 = o1 as RegExp,
|
|
97
|
+
r2 = o2 as RegExp;
|
|
98
|
+
return r1.source === r2.source && r1.flags === r2.flags;
|
|
114
99
|
}
|
|
115
100
|
|
|
116
|
-
// Handle
|
|
117
|
-
|
|
118
|
-
|
|
101
|
+
// Handle Set comparison
|
|
102
|
+
// Two sets are equal if they have the same size and
|
|
103
|
+
// every value in one has an equivalent value in the
|
|
104
|
+
// other (using deep equality).
|
|
105
|
+
// Cannot use the same item for multiple matches in another set.
|
|
106
|
+
if (value1 instanceof Set && value2 instanceof Set) {
|
|
107
|
+
if (value1.size !== value2.size) return false;
|
|
108
|
+
if (memoHasOrAdd(pairMemo, value1, value2)) return true;
|
|
109
|
+
|
|
110
|
+
const unmatched = new Set(value2);
|
|
111
|
+
|
|
112
|
+
for (const v1 of value1) {
|
|
113
|
+
let matched = false;
|
|
114
|
+
for (const v2 of unmatched) {
|
|
115
|
+
if (isEqual(v1, v2, pairMemo)) {
|
|
116
|
+
unmatched.delete(v2); // consume the match
|
|
117
|
+
matched = true;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!matched) return false;
|
|
122
|
+
}
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
// Clean up before returning
|
|
122
|
-
objectStack1.delete(obj1);
|
|
123
|
-
objectStack2.delete(obj2);
|
|
124
|
-
return false;
|
|
124
|
+
return unmatched.size === 0;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
// Handle Map comparison
|
|
128
|
+
if (value1 instanceof Map && value2 instanceof Map) {
|
|
129
|
+
if (value1.size !== value2.size) return false;
|
|
130
130
|
|
|
131
|
-
if (
|
|
132
|
-
// Clean up before returning
|
|
133
|
-
objectStack1.delete(obj1);
|
|
134
|
-
objectStack2.delete(obj2);
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
131
|
+
if (memoHasOrAdd(pairMemo, value1, value2)) return true;
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
const pairKey: [unknown, unknown] = [value1, value2];
|
|
140
|
-
if (compareStack.has(pairKey)) {
|
|
141
|
-
// Clean up before returning
|
|
142
|
-
objectStack1.delete(obj1);
|
|
143
|
-
objectStack2.delete(obj2);
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
compareStack.add(pairKey);
|
|
147
|
-
|
|
148
|
-
// Compare each element
|
|
149
|
-
for (let i = 0; i < arr1.length; i++) {
|
|
150
|
-
if (!isEqual(arr1[i], arr2[i], compareStack, objectStack1, objectStack2)) {
|
|
151
|
-
compareStack.delete(pairKey);
|
|
152
|
-
// Clean up before returning
|
|
153
|
-
objectStack1.delete(obj1);
|
|
154
|
-
objectStack2.delete(obj2);
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
133
|
+
const unmatched = new Set(value2); // tracks entries in map2 not yet matched
|
|
158
134
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
objectStack2.delete(obj2);
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
135
|
+
for (const [k1, v1] of value1) {
|
|
136
|
+
let matchedEntry: [unknown, unknown] | null = null;
|
|
164
137
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
138
|
+
for (const entry of unmatched) {
|
|
139
|
+
const [k2, v2] = entry as [unknown, unknown];
|
|
140
|
+
if (isEqual(k1, k2, pairMemo) && isEqual(v1, v2, pairMemo)) {
|
|
141
|
+
matchedEntry = entry;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
168
145
|
|
|
169
|
-
|
|
170
|
-
|
|
146
|
+
if (!matchedEntry) return false; // nothing matched this entry
|
|
147
|
+
unmatched.delete(matchedEntry); // consume it
|
|
148
|
+
}
|
|
171
149
|
|
|
172
|
-
|
|
173
|
-
if (keys1.length !== keys2.length) {
|
|
174
|
-
// Clean up before returning
|
|
175
|
-
objectStack1.delete(obj1);
|
|
176
|
-
objectStack2.delete(obj2);
|
|
177
|
-
return false;
|
|
150
|
+
return unmatched.size === 0;
|
|
178
151
|
}
|
|
179
152
|
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
153
|
+
// Treat non-plain instances atomically (your current rule)
|
|
154
|
+
if (isClassInstance(o1) || isClassInstance(o2)) return false;
|
|
155
|
+
|
|
156
|
+
// Cycle guard (pairwise)
|
|
157
|
+
if (memoHasOrAdd(pairMemo, o1, o2)) return true;
|
|
158
|
+
|
|
159
|
+
// Arrays (respect holes vs undefined)
|
|
160
|
+
if (Array.isArray(o1)) {
|
|
161
|
+
const a1 = value1 as unknown[],
|
|
162
|
+
a2 = value2 as unknown[];
|
|
163
|
+
if (a1.length !== a2.length) return false;
|
|
164
|
+
for (let i = 0; i < a1.length; i++) {
|
|
165
|
+
const has1 = i in a1,
|
|
166
|
+
has2 = i in a2;
|
|
167
|
+
if (has1 !== has2) return false;
|
|
168
|
+
if (has1 && !isEqual(a1[i], a2[i], pairMemo)) return false;
|
|
188
169
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// Compare each property's value
|
|
202
|
-
for (const key of keys1) {
|
|
203
|
-
if (
|
|
204
|
-
!isEqual(plainObj1[key], plainObj2[key], compareStack, objectStack1, objectStack2)
|
|
205
|
-
) {
|
|
206
|
-
compareStack.delete(pairKey);
|
|
207
|
-
// Clean up before returning
|
|
208
|
-
objectStack1.delete(obj1);
|
|
209
|
-
objectStack2.delete(obj2);
|
|
210
|
-
return false;
|
|
170
|
+
// Compare enumerable non-index props as well (to align with objects)
|
|
171
|
+
const extraKeys1 = Reflect.ownKeys(o1)
|
|
172
|
+
.filter((k) => typeof k !== 'string' || isNaN(+k))
|
|
173
|
+
.filter((k) => Object.prototype.propertyIsEnumerable.call(o1, k));
|
|
174
|
+
const extraKeys2 = Reflect.ownKeys(o2)
|
|
175
|
+
.filter((k) => typeof k !== 'string' || isNaN(+k))
|
|
176
|
+
.filter((k) => Object.prototype.propertyIsEnumerable.call(o2, k));
|
|
177
|
+
if (extraKeys1.length !== extraKeys2.length) return false;
|
|
178
|
+
for (const k of extraKeys1) {
|
|
179
|
+
if (!Object.prototype.hasOwnProperty.call(o2, k)) return false;
|
|
180
|
+
// @ts-expect-error index signature
|
|
181
|
+
if (!isEqual(o1[k], o2[k], pairMemo)) return false;
|
|
211
182
|
}
|
|
183
|
+
return true;
|
|
212
184
|
}
|
|
213
185
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
186
|
+
// Plain objects (string + symbol enumerable own keys)
|
|
187
|
+
const keys1 = Reflect.ownKeys(o1).filter((k) =>
|
|
188
|
+
Object.prototype.propertyIsEnumerable.call(o1, k),
|
|
189
|
+
);
|
|
190
|
+
const keys2 = Reflect.ownKeys(o2).filter((k) =>
|
|
191
|
+
Object.prototype.propertyIsEnumerable.call(o2, k),
|
|
192
|
+
);
|
|
193
|
+
if (keys1.length !== keys2.length) return false;
|
|
194
|
+
|
|
195
|
+
// enforce same prototype to avoid {} == Object.create(null, ...)
|
|
196
|
+
if (Object.getPrototypeOf(o1) !== Object.getPrototypeOf(o2)) return false;
|
|
197
|
+
|
|
198
|
+
for (const k of keys1) {
|
|
199
|
+
if (!Object.prototype.hasOwnProperty.call(o2, k)) return false;
|
|
200
|
+
// @ts-expect-error index signature
|
|
201
|
+
if (!isEqual(o1[k], o2[k], pairMemo)) return false;
|
|
202
|
+
}
|
|
218
203
|
return true;
|
|
219
204
|
};
|
|
220
205
|
|
|
@@ -241,13 +226,7 @@ function compareAndBuildDiff(
|
|
|
241
226
|
modified: unknown,
|
|
242
227
|
parentDiffNode: DiffNode,
|
|
243
228
|
key?: string | symbol,
|
|
244
|
-
|
|
245
|
-
* Tracks pairs of objects being compared
|
|
246
|
-
* - It stores pairs of values that are being compared `[original, modified]`
|
|
247
|
-
* - This helps detect when we're comparing the same pair of objects again
|
|
248
|
-
* - It prevents infinite recursion when comparing complex object structures
|
|
249
|
-
*/
|
|
250
|
-
compareStack = new Set<[unknown, unknown]>(),
|
|
229
|
+
pairMemo: PairMemo = new WeakMap(),
|
|
251
230
|
/**
|
|
252
231
|
* Tracks individual objects that are being processed in the current traversal path
|
|
253
232
|
* - It's used to detect when we encounter the same object multiple times in a single traversal path
|
|
@@ -257,9 +236,7 @@ function compareAndBuildDiff(
|
|
|
257
236
|
objectStack = new Set<unknown>(),
|
|
258
237
|
): void {
|
|
259
238
|
// If values are equal, no diff to record
|
|
260
|
-
if (isEqual(original, modified
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
239
|
+
if (isEqual(original, modified)) return;
|
|
263
240
|
|
|
264
241
|
// Handle additions (value in modified but not in original)
|
|
265
242
|
if (original === undefined || original === null) {
|
|
@@ -335,16 +312,20 @@ function compareAndBuildDiff(
|
|
|
335
312
|
parentDiffNode.children[String(key)] = currentDiffNode;
|
|
336
313
|
}
|
|
337
314
|
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
315
|
+
// Pairwise cycle check (prevents infinite recursion across the *pair*)
|
|
316
|
+
if (
|
|
317
|
+
typeof original === 'object' &&
|
|
318
|
+
original !== null &&
|
|
319
|
+
typeof modified === 'object' &&
|
|
320
|
+
modified !== null
|
|
321
|
+
) {
|
|
322
|
+
if (memoHasOrAdd(pairMemo, original as object, modified as object)) {
|
|
323
|
+
// already visited this exact pair in this diff traversal
|
|
324
|
+
// (prevents infinite recursion), so stop here
|
|
325
|
+
if (typeof original === 'object') objectStack.delete(original);
|
|
326
|
+
return;
|
|
344
327
|
}
|
|
345
|
-
return;
|
|
346
328
|
}
|
|
347
|
-
compareStack.add(pairKey);
|
|
348
329
|
|
|
349
330
|
// Process all keys from both objects
|
|
350
331
|
const allKeys = new Set([
|
|
@@ -380,17 +361,12 @@ function compareAndBuildDiff(
|
|
|
380
361
|
modifiedValue,
|
|
381
362
|
currentDiffNode,
|
|
382
363
|
childKey,
|
|
383
|
-
|
|
364
|
+
pairMemo,
|
|
384
365
|
objectStack,
|
|
385
366
|
);
|
|
386
367
|
}
|
|
387
368
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// Remove from object stack before returning
|
|
391
|
-
if (typeof original === 'object' && original !== null) {
|
|
392
|
-
objectStack.delete(original);
|
|
393
|
-
}
|
|
369
|
+
if (typeof original === 'object' && original !== null) objectStack.delete(original);
|
|
394
370
|
}
|
|
395
371
|
|
|
396
372
|
export function createMergeCore<T extends object>(options: { trackDiff?: boolean } = {}) {
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* which keys have been added or updated during the merge operation.
|
|
4
4
|
*
|
|
5
5
|
* @category Object
|
|
6
|
-
* @param object The destination object.
|
|
7
|
-
* @param source A single source object or an array of objects to be merged into the object.
|
|
8
|
-
* @param customizer The function to customize assigned values.
|
|
6
|
+
* @param object - The destination object.
|
|
7
|
+
* @param source - A single source object or an array of objects to be merged into the object.
|
|
8
|
+
* @param customizer - The function to customize assigned values.
|
|
9
9
|
* @returns Returns an object containing the merged result and a hierarchical diff object.
|
|
10
10
|
* @example
|
|
11
11
|
*
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
type FunctionToRetry<T = any> = (...functionArguments: any[]) => PromiseLike<T>;
|
|
2
|
+
|
|
3
|
+
enum RetryErrorType {
|
|
4
|
+
ABORT,
|
|
5
|
+
ATTEMPT_LIMIT_REACHED,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class RetryError extends Error {
|
|
9
|
+
public name = 'RetryError';
|
|
10
|
+
|
|
11
|
+
private static errorMap = {
|
|
12
|
+
[RetryErrorType.ABORT]: 'Value changed, retry handler aborted',
|
|
13
|
+
[RetryErrorType.ATTEMPT_LIMIT_REACHED]: 'Reached maximum amount of retry attempts',
|
|
14
|
+
} satisfies Record<RetryErrorType, string>;
|
|
15
|
+
|
|
16
|
+
constructor({ type }: { type: RetryErrorType }) {
|
|
17
|
+
super(RetryError.errorMap[type]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const sleep = (duration: number) =>
|
|
22
|
+
new Promise((resolve) => setTimeout(resolve, duration));
|
|
23
|
+
|
|
24
|
+
// export const handleFalsePositiveResponse = <
|
|
25
|
+
// T extends (...v: any[]) => PromiseLike<SuppliesResponse>,
|
|
26
|
+
// >(
|
|
27
|
+
// f: T,
|
|
28
|
+
// ) =>
|
|
29
|
+
// async function falsePositiveHandler(...functionArguments: Parameters<T>) {
|
|
30
|
+
// // await or throw if "f" fails
|
|
31
|
+
// const data = (await f(...functionArguments)) as Awaited<ReturnType<T>>;
|
|
32
|
+
// // check for error data, throw if exist
|
|
33
|
+
// if (data.errors !== null) {
|
|
34
|
+
// const stringifiedErrors = data.errors
|
|
35
|
+
// .map((error, index) => `E${index + 1}(${error.errorCode}): ${error.message}`)
|
|
36
|
+
// .join('\n');
|
|
37
|
+
|
|
38
|
+
// throw new Error(stringifiedErrors);
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
// return data;
|
|
42
|
+
// };
|
|
43
|
+
|
|
44
|
+
export type RunWithRetryOptions<T extends FunctionToRetry> = {
|
|
45
|
+
retryAttempts?: number;
|
|
46
|
+
delayBetweenRetries?: number | ((attempt: number) => number);
|
|
47
|
+
isRetryable?: (error: unknown) => boolean;
|
|
48
|
+
didValueChange?: (...functionArguments: Parameters<T>) => Promise<boolean> | boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Function which wraps asynchronous functions with retry mechanism which'll keep executing said
|
|
53
|
+
* function pre-defined number of times until it resolves, rejects or the retry mechanism runs out of available attempts.
|
|
54
|
+
*
|
|
55
|
+
* #### Available options:
|
|
56
|
+
* - `didValueChange` - check function with initial argument value to check against new values, return `true` to abort next attempt
|
|
57
|
+
*
|
|
58
|
+
* - `isRetryable` - error evaluation function which determines whether to retry the execution
|
|
59
|
+
*
|
|
60
|
+
* - `delayBetweenRetries` - accepts either fixed numeric value or function which provides retry attempt as the argument, expects number as return value
|
|
61
|
+
*
|
|
62
|
+
* - `retryAttempts` - number of attempts to try out before rejecting the promise
|
|
63
|
+
*/
|
|
64
|
+
export const runWithRetry = <T extends FunctionToRetry>(
|
|
65
|
+
f: T,
|
|
66
|
+
{
|
|
67
|
+
retryAttempts = 3,
|
|
68
|
+
delayBetweenRetries,
|
|
69
|
+
isRetryable,
|
|
70
|
+
didValueChange,
|
|
71
|
+
}: RunWithRetryOptions<T> = {},
|
|
72
|
+
) =>
|
|
73
|
+
async function retryable(...functionArguments: Parameters<T>) {
|
|
74
|
+
// starting with -1 as first attempt is not considered a retry
|
|
75
|
+
let retryAttempt = -1;
|
|
76
|
+
|
|
77
|
+
do {
|
|
78
|
+
let data: Awaited<ReturnType<T>> | null = null;
|
|
79
|
+
let error: unknown = null;
|
|
80
|
+
|
|
81
|
+
if (await didValueChange?.(...functionArguments)) {
|
|
82
|
+
throw new RetryError({ type: RetryErrorType.ABORT });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
data = await f(...functionArguments);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
error = e;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// disable value change check after successfull server call
|
|
92
|
+
// throwing error at this point could lead to stale local states
|
|
93
|
+
|
|
94
|
+
// if (await didValueChange?.(...functionArguments)) {
|
|
95
|
+
// throw new RetryError({ type: 'abort' });
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
if (data) return data;
|
|
99
|
+
|
|
100
|
+
const runRetry = isRetryable?.(error) ?? true;
|
|
101
|
+
if (!runRetry) throw error;
|
|
102
|
+
|
|
103
|
+
retryAttempt++;
|
|
104
|
+
|
|
105
|
+
const isLastAttempt = retryAttempt === retryAttempts;
|
|
106
|
+
|
|
107
|
+
if (delayBetweenRetries && !isLastAttempt) {
|
|
108
|
+
await sleep(
|
|
109
|
+
typeof delayBetweenRetries === 'function'
|
|
110
|
+
? delayBetweenRetries(retryAttempt)
|
|
111
|
+
: delayBetweenRetries,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
} while (retryAttempt < retryAttempts);
|
|
115
|
+
|
|
116
|
+
throw new RetryError({ type: RetryErrorType.ATTEMPT_LIMIT_REACHED });
|
|
117
|
+
};
|