stream-chat 9.2.0 → 9.4.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.
- package/dist/cjs/index.browser.cjs +251 -34
- package/dist/cjs/index.browser.cjs.map +4 -4
- package/dist/cjs/index.node.cjs +258 -39
- package/dist/cjs/index.node.cjs.map +4 -4
- package/dist/esm/index.js +254 -37
- package/dist/esm/index.js.map +4 -4
- package/dist/types/channel.d.ts +3 -5
- package/dist/types/client.d.ts +20 -3
- package/dist/types/offline-support/offline_support_api.d.ts +2 -4
- package/dist/types/offline-support/types.d.ts +14 -4
- package/dist/types/store.d.ts +114 -5
- package/dist/types/types.d.ts +29 -3
- package/package.json +4 -4
- package/src/channel.ts +5 -5
- package/src/client.ts +26 -7
- package/src/offline-support/offline_support_api.ts +12 -9
- package/src/offline-support/types.ts +28 -4
- package/src/store.ts +237 -11
- package/src/types.ts +29 -1
- package/src/utils/mergeWith/mergeWithCore.ts +7 -1
package/dist/esm/index.js
CHANGED
|
@@ -3900,26 +3900,14 @@ var ensureIsLocalAttachment = (attachment) => {
|
|
|
3900
3900
|
|
|
3901
3901
|
// src/store.ts
|
|
3902
3902
|
var isPatch = (value) => typeof value === "function";
|
|
3903
|
+
var noop2 = () => {
|
|
3904
|
+
};
|
|
3903
3905
|
var StateStore = class {
|
|
3904
3906
|
constructor(value) {
|
|
3905
3907
|
this.value = value;
|
|
3906
|
-
this.
|
|
3907
|
-
this.
|
|
3908
|
-
const newValue = isPatch(newValueOrPatch) ? newValueOrPatch(this.value) : newValueOrPatch;
|
|
3909
|
-
if (newValue === this.value) return;
|
|
3910
|
-
const oldValue = this.value;
|
|
3911
|
-
this.value = newValue;
|
|
3912
|
-
this.handlerSet.forEach((handler) => handler(this.value, oldValue));
|
|
3913
|
-
};
|
|
3908
|
+
this.handlers = /* @__PURE__ */ new Set();
|
|
3909
|
+
this.preprocessors = /* @__PURE__ */ new Set();
|
|
3914
3910
|
this.partialNext = (partial) => this.next((current) => ({ ...current, ...partial }));
|
|
3915
|
-
this.getLatestValue = () => this.value;
|
|
3916
|
-
this.subscribe = (handler) => {
|
|
3917
|
-
handler(this.value, void 0);
|
|
3918
|
-
this.handlerSet.add(handler);
|
|
3919
|
-
return () => {
|
|
3920
|
-
this.handlerSet.delete(handler);
|
|
3921
|
-
};
|
|
3922
|
-
};
|
|
3923
3911
|
this.subscribeWithSelector = (selector, handler) => {
|
|
3924
3912
|
let previouslySelectedValues;
|
|
3925
3913
|
const wrappedHandler = (nextValue) => {
|
|
@@ -3938,6 +3926,183 @@ var StateStore = class {
|
|
|
3938
3926
|
return this.subscribe(wrappedHandler);
|
|
3939
3927
|
};
|
|
3940
3928
|
}
|
|
3929
|
+
/**
|
|
3930
|
+
* Allows merging two stores only if their keys differ otherwise there's no way to ensure the data type stability.
|
|
3931
|
+
* @experimental
|
|
3932
|
+
* This method is experimental and may change in future versions.
|
|
3933
|
+
*/
|
|
3934
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3935
|
+
merge(stateStore) {
|
|
3936
|
+
return new MergedStateStore({
|
|
3937
|
+
original: this,
|
|
3938
|
+
merged: stateStore
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
next(newValueOrPatch) {
|
|
3942
|
+
const newValue = isPatch(newValueOrPatch) ? newValueOrPatch(this.value) : newValueOrPatch;
|
|
3943
|
+
if (newValue === this.value) return;
|
|
3944
|
+
this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
|
|
3945
|
+
const oldValue = this.value;
|
|
3946
|
+
this.value = newValue;
|
|
3947
|
+
this.handlers.forEach((handler) => handler(this.value, oldValue));
|
|
3948
|
+
}
|
|
3949
|
+
getLatestValue() {
|
|
3950
|
+
return this.value;
|
|
3951
|
+
}
|
|
3952
|
+
subscribe(handler) {
|
|
3953
|
+
handler(this.value, void 0);
|
|
3954
|
+
this.handlers.add(handler);
|
|
3955
|
+
return () => {
|
|
3956
|
+
this.handlers.delete(handler);
|
|
3957
|
+
};
|
|
3958
|
+
}
|
|
3959
|
+
/**
|
|
3960
|
+
* Registers a preprocessor function that will be called before the state is updated.
|
|
3961
|
+
*
|
|
3962
|
+
* Preprocessors are invoked with the new and previous values whenever `next` or `partialNext` methods
|
|
3963
|
+
* are called, allowing you to mutate or react to the new value before it is set. Preprocessors run in the
|
|
3964
|
+
* order they were registered.
|
|
3965
|
+
*
|
|
3966
|
+
* @example
|
|
3967
|
+
* ```ts
|
|
3968
|
+
* const store = new StateStore<{ count: number; isMaxValue: bool; }>({ count: 0, isMaxValue: false });
|
|
3969
|
+
*
|
|
3970
|
+
* store.addPreprocessor((nextValue, prevValue) => {
|
|
3971
|
+
* if (nextValue.count > 10) {
|
|
3972
|
+
* nextValue.count = 10; // Clamp the value to a maximum of 10
|
|
3973
|
+
* }
|
|
3974
|
+
*
|
|
3975
|
+
* if (nextValue.count === 10) {
|
|
3976
|
+
* nextValue.isMaxValue = true; // Set isMaxValue to true if count is 10
|
|
3977
|
+
* } else {
|
|
3978
|
+
* nextValue.isMaxValue = false; // Reset isMaxValue otherwise
|
|
3979
|
+
* }
|
|
3980
|
+
* });
|
|
3981
|
+
*
|
|
3982
|
+
* store.partialNext({ count: 15 });
|
|
3983
|
+
*
|
|
3984
|
+
* store.getLatestValue(); // { count: 10, isMaxValue: true }
|
|
3985
|
+
*
|
|
3986
|
+
* store.partialNext({ count: 5 });
|
|
3987
|
+
*
|
|
3988
|
+
* store.getLatestValue(); // { count: 5, isMaxValue: false }
|
|
3989
|
+
* ```
|
|
3990
|
+
*
|
|
3991
|
+
* @param preprocessor - The function to be called with the next and previous values before the state is updated.
|
|
3992
|
+
* @returns A `RemovePreprocessor` function that removes the preprocessor when called.
|
|
3993
|
+
*/
|
|
3994
|
+
addPreprocessor(preprocessor) {
|
|
3995
|
+
this.preprocessors.add(preprocessor);
|
|
3996
|
+
return () => {
|
|
3997
|
+
this.preprocessors.delete(preprocessor);
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
};
|
|
4001
|
+
var MergedStateStore = class _MergedStateStore extends StateStore {
|
|
4002
|
+
constructor({ original, merged }) {
|
|
4003
|
+
const originalValue = original.getLatestValue();
|
|
4004
|
+
const mergedValue = merged.getLatestValue();
|
|
4005
|
+
super({
|
|
4006
|
+
...originalValue,
|
|
4007
|
+
...mergedValue
|
|
4008
|
+
});
|
|
4009
|
+
// override original methods and "disable" them
|
|
4010
|
+
this.next = () => {
|
|
4011
|
+
console.warn(
|
|
4012
|
+
`${_MergedStateStore.name}.next is disabled, call original.next or merged.next instead`
|
|
4013
|
+
);
|
|
4014
|
+
};
|
|
4015
|
+
this.partialNext = () => {
|
|
4016
|
+
console.warn(
|
|
4017
|
+
`${_MergedStateStore.name}.partialNext is disabled, call original.partialNext or merged.partialNext instead`
|
|
4018
|
+
);
|
|
4019
|
+
};
|
|
4020
|
+
this.cachedOriginalValue = originalValue;
|
|
4021
|
+
this.cachedMergedValue = mergedValue;
|
|
4022
|
+
this.original = original;
|
|
4023
|
+
this.merged = merged;
|
|
4024
|
+
}
|
|
4025
|
+
/**
|
|
4026
|
+
* Subscribes to changes in the merged state store.
|
|
4027
|
+
*
|
|
4028
|
+
* This method extends the base subscribe functionality to handle the merged nature of this store:
|
|
4029
|
+
* 1. The first subscriber triggers registration of helper subscribers that listen to both source stores
|
|
4030
|
+
* 2. Changes from either source store are propagated to this merged store
|
|
4031
|
+
* 3. Source store values are cached to prevent unnecessary updates
|
|
4032
|
+
*
|
|
4033
|
+
* When the first subscriber is added, the method sets up listeners on both original and merged stores.
|
|
4034
|
+
* These listeners update the combined store value whenever either source store changes.
|
|
4035
|
+
* All subscriptions (helpers and the actual handler) are tracked so they can be properly cleaned up.
|
|
4036
|
+
*
|
|
4037
|
+
* @param handler - The callback function that will be executed when the state changes
|
|
4038
|
+
* @returns An unsubscribe function that, when called, removes the subscription and any helper subscriptions
|
|
4039
|
+
*/
|
|
4040
|
+
subscribe(handler) {
|
|
4041
|
+
const unsubscribeFunctions = [];
|
|
4042
|
+
if (!this.handlers.size) {
|
|
4043
|
+
const base = (nextValue) => {
|
|
4044
|
+
super.next((currentValue) => ({
|
|
4045
|
+
...currentValue,
|
|
4046
|
+
...nextValue
|
|
4047
|
+
}));
|
|
4048
|
+
};
|
|
4049
|
+
unsubscribeFunctions.push(
|
|
4050
|
+
this.original.subscribe((nextValue) => {
|
|
4051
|
+
if (nextValue === this.cachedOriginalValue) return;
|
|
4052
|
+
this.cachedOriginalValue = nextValue;
|
|
4053
|
+
base(nextValue);
|
|
4054
|
+
}),
|
|
4055
|
+
this.merged.subscribe((nextValue) => {
|
|
4056
|
+
if (nextValue === this.cachedMergedValue) return;
|
|
4057
|
+
this.cachedMergedValue = nextValue;
|
|
4058
|
+
base(nextValue);
|
|
4059
|
+
})
|
|
4060
|
+
);
|
|
4061
|
+
}
|
|
4062
|
+
unsubscribeFunctions.push(super.subscribe(handler));
|
|
4063
|
+
return () => {
|
|
4064
|
+
unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
4067
|
+
/**
|
|
4068
|
+
* Retrieves the latest combined state from both original and merged stores.
|
|
4069
|
+
*
|
|
4070
|
+
* This method extends the base getLatestValue functionality to ensure the merged store
|
|
4071
|
+
* remains in sync with its source stores even when there are no active subscribers.
|
|
4072
|
+
*
|
|
4073
|
+
* When there are no handlers registered, the method:
|
|
4074
|
+
* 1. Fetches the latest values from both source stores
|
|
4075
|
+
* 2. Compares them with the cached values to detect changes
|
|
4076
|
+
* 3. If changes are detected, updates the internal value and caches
|
|
4077
|
+
* the new source values to maintain consistency
|
|
4078
|
+
*
|
|
4079
|
+
* This approach ensures that calling getLatestValue() always returns the most
|
|
4080
|
+
* up-to-date combined state, even if the merged store hasn't been actively
|
|
4081
|
+
* receiving updates through subscriptions.
|
|
4082
|
+
*
|
|
4083
|
+
* @returns The latest combined state from both original and merged stores
|
|
4084
|
+
*/
|
|
4085
|
+
getLatestValue() {
|
|
4086
|
+
if (!this.handlers.size) {
|
|
4087
|
+
const originalValue = this.original.getLatestValue();
|
|
4088
|
+
const mergedValue = this.merged.getLatestValue();
|
|
4089
|
+
if (originalValue !== this.cachedOriginalValue || mergedValue !== this.cachedMergedValue) {
|
|
4090
|
+
this.value = {
|
|
4091
|
+
...originalValue,
|
|
4092
|
+
...mergedValue
|
|
4093
|
+
};
|
|
4094
|
+
this.cachedMergedValue = mergedValue;
|
|
4095
|
+
this.cachedOriginalValue = originalValue;
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
return super.getLatestValue();
|
|
4099
|
+
}
|
|
4100
|
+
addPreprocessor() {
|
|
4101
|
+
console.warn(
|
|
4102
|
+
`${_MergedStateStore.name}.addPreprocessor is disabled, call original.addPreprocessor or merged.addPreprocessor instead`
|
|
4103
|
+
);
|
|
4104
|
+
return noop2;
|
|
4105
|
+
}
|
|
3941
4106
|
};
|
|
3942
4107
|
|
|
3943
4108
|
// src/utils/mergeWith/mergeWithCore.ts
|
|
@@ -4182,6 +4347,12 @@ function createMergeCore(options = {}) {
|
|
|
4182
4347
|
return false;
|
|
4183
4348
|
}
|
|
4184
4349
|
function createNewTarget(targetValue, srcValue) {
|
|
4350
|
+
if (targetValue === null || typeof targetValue === "undefined") {
|
|
4351
|
+
return srcValue;
|
|
4352
|
+
}
|
|
4353
|
+
if (!Array.isArray(targetValue) && typeof targetValue !== "object") {
|
|
4354
|
+
return srcValue;
|
|
4355
|
+
}
|
|
4185
4356
|
if (targetValue && typeof targetValue === "object") {
|
|
4186
4357
|
const isTargetClassInstance = isClassInstance(targetValue);
|
|
4187
4358
|
const isSourceClassInstance = isClassInstance(srcValue);
|
|
@@ -5283,8 +5454,8 @@ function decodeTlds(encoded) {
|
|
|
5283
5454
|
var defaults2 = {
|
|
5284
5455
|
defaultProtocol: "http",
|
|
5285
5456
|
events: null,
|
|
5286
|
-
format:
|
|
5287
|
-
formatHref:
|
|
5457
|
+
format: noop3,
|
|
5458
|
+
formatHref: noop3,
|
|
5288
5459
|
nl2br: false,
|
|
5289
5460
|
tagName: "a",
|
|
5290
5461
|
target: null,
|
|
@@ -5389,7 +5560,7 @@ Options.prototype = {
|
|
|
5389
5560
|
return renderFn(ir, token.t, token);
|
|
5390
5561
|
}
|
|
5391
5562
|
};
|
|
5392
|
-
function
|
|
5563
|
+
function noop3(val) {
|
|
5393
5564
|
return val;
|
|
5394
5565
|
}
|
|
5395
5566
|
function MultiToken(value, tokens) {
|
|
@@ -6480,7 +6651,9 @@ var ErrorFromResponse = class extends Error {
|
|
|
6480
6651
|
return {
|
|
6481
6652
|
message: `(${joinable.join(", ")}) - ${this.message}`,
|
|
6482
6653
|
stack: this.stack,
|
|
6483
|
-
name: this.name
|
|
6654
|
+
name: this.name,
|
|
6655
|
+
code: this.code,
|
|
6656
|
+
status: this.status
|
|
6484
6657
|
};
|
|
6485
6658
|
}
|
|
6486
6659
|
};
|
|
@@ -8613,7 +8786,7 @@ var initState5 = (composition) => {
|
|
|
8613
8786
|
pollId: message.poll_id ?? null
|
|
8614
8787
|
};
|
|
8615
8788
|
};
|
|
8616
|
-
var
|
|
8789
|
+
var noop4 = () => void 0;
|
|
8617
8790
|
var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
8618
8791
|
// todo: mediaRecorder: MediaRecorderController;
|
|
8619
8792
|
constructor({
|
|
@@ -8641,7 +8814,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8641
8814
|
this.initEditingAuditState = (composition) => initEditingAuditState(composition);
|
|
8642
8815
|
this.registerSubscriptions = () => {
|
|
8643
8816
|
if (this.hasSubscriptions) {
|
|
8644
|
-
return
|
|
8817
|
+
return noop4;
|
|
8645
8818
|
}
|
|
8646
8819
|
this.addUnsubscribeFunction(this.subscribeMessageComposerSetupStateChange());
|
|
8647
8820
|
this.addUnsubscribeFunction(this.subscribeMessageUpdated());
|
|
@@ -13894,7 +14067,24 @@ var StreamChat = class _StreamChat {
|
|
|
13894
14067
|
'data_template': 'data handlebars template',
|
|
13895
14068
|
'apn_template': 'apn notification handlebars template under v2'
|
|
13896
14069
|
},
|
|
13897
|
-
'webhook_url': 'https://acme.com/my/awesome/webhook/'
|
|
14070
|
+
'webhook_url': 'https://acme.com/my/awesome/webhook/',
|
|
14071
|
+
'event_hooks': [
|
|
14072
|
+
{
|
|
14073
|
+
'hook_type': 'webhook',
|
|
14074
|
+
'enabled': true,
|
|
14075
|
+
'event_types': ['message.new'],
|
|
14076
|
+
'webhook_url': 'https://acme.com/my/awesome/webhook/'
|
|
14077
|
+
},
|
|
14078
|
+
{
|
|
14079
|
+
'hook_type': 'sqs',
|
|
14080
|
+
'enabled': true,
|
|
14081
|
+
'event_types': ['message.new'],
|
|
14082
|
+
'sqs_url': 'https://sqs.us-east-1.amazonaws.com/1234567890/my-queue',
|
|
14083
|
+
'sqs_auth_type': 'key',
|
|
14084
|
+
'sqs_key': 'my-access-key',
|
|
14085
|
+
'sqs_secret': 'my-secret-key'
|
|
14086
|
+
}
|
|
14087
|
+
]
|
|
13898
14088
|
}
|
|
13899
14089
|
*/
|
|
13900
14090
|
async updateAppSettings(options) {
|
|
@@ -15238,13 +15428,15 @@ var StreamChat = class _StreamChat {
|
|
|
15238
15428
|
} else {
|
|
15239
15429
|
await this.offlineDb.softDeleteMessage({ id: messageID });
|
|
15240
15430
|
}
|
|
15241
|
-
return await this.offlineDb.queueTask(
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
|
|
15431
|
+
return await this.offlineDb.queueTask(
|
|
15432
|
+
{
|
|
15433
|
+
task: {
|
|
15434
|
+
messageId: messageID,
|
|
15435
|
+
payload: [messageID, hardDelete],
|
|
15436
|
+
type: "delete-message"
|
|
15437
|
+
}
|
|
15246
15438
|
}
|
|
15247
|
-
|
|
15439
|
+
);
|
|
15248
15440
|
}
|
|
15249
15441
|
} catch (error) {
|
|
15250
15442
|
this.logger("error", `offlineDb:deleteMessage`, {
|
|
@@ -15398,7 +15590,7 @@ var StreamChat = class _StreamChat {
|
|
|
15398
15590
|
if (this.userAgent) {
|
|
15399
15591
|
return this.userAgent;
|
|
15400
15592
|
}
|
|
15401
|
-
const version = "9.
|
|
15593
|
+
const version = "9.4.0";
|
|
15402
15594
|
const clientBundle = "browser-esm";
|
|
15403
15595
|
let userAgentString = "";
|
|
15404
15596
|
if (this.sdkIdentifier) {
|
|
@@ -16574,6 +16766,26 @@ var BuiltinPermissions = {
|
|
|
16574
16766
|
UseFrozenChannel: "Send messages and reactions to frozen channels"
|
|
16575
16767
|
};
|
|
16576
16768
|
|
|
16769
|
+
// src/offline-support/types.ts
|
|
16770
|
+
var OfflineError = class extends Error {
|
|
16771
|
+
constructor(message, {
|
|
16772
|
+
type
|
|
16773
|
+
}) {
|
|
16774
|
+
super(message);
|
|
16775
|
+
this.name = "OfflineError";
|
|
16776
|
+
this.type = type;
|
|
16777
|
+
}
|
|
16778
|
+
// Vitest helper (serialized errors are too large to read)
|
|
16779
|
+
// https://github.com/vitest-dev/vitest/blob/v3.1.3/packages/utils/src/error.ts#L60-L62
|
|
16780
|
+
toJSON() {
|
|
16781
|
+
return {
|
|
16782
|
+
message: `${this.type} - ${this.message}`,
|
|
16783
|
+
stack: this.stack,
|
|
16784
|
+
name: this.name
|
|
16785
|
+
};
|
|
16786
|
+
}
|
|
16787
|
+
};
|
|
16788
|
+
|
|
16577
16789
|
// src/offline-support/offline_sync_manager.ts
|
|
16578
16790
|
var OfflineDBSyncManager = class {
|
|
16579
16791
|
constructor({
|
|
@@ -17179,20 +17391,23 @@ var AbstractOfflineDB = class {
|
|
|
17179
17391
|
* @param task - the pending task we want to execute
|
|
17180
17392
|
*/
|
|
17181
17393
|
this.queueTask = async ({ task }) => {
|
|
17182
|
-
|
|
17183
|
-
try {
|
|
17394
|
+
const attemptTaskExecution = async () => {
|
|
17184
17395
|
if (!this.client.wsConnection?.isHealthy) {
|
|
17185
|
-
|
|
17186
|
-
|
|
17396
|
+
throw new OfflineError(
|
|
17397
|
+
"Cannot execute task because the connection has been lost.",
|
|
17398
|
+
{ type: "connection:lost" }
|
|
17399
|
+
);
|
|
17187
17400
|
}
|
|
17188
|
-
|
|
17401
|
+
return await this.executeTask({ task });
|
|
17402
|
+
};
|
|
17403
|
+
try {
|
|
17404
|
+
return await attemptTaskExecution();
|
|
17189
17405
|
} catch (e) {
|
|
17190
17406
|
if (!this.shouldSkipQueueingTask(e)) {
|
|
17191
17407
|
await this.addPendingTask(task);
|
|
17192
|
-
throw e;
|
|
17193
17408
|
}
|
|
17409
|
+
throw e;
|
|
17194
17410
|
}
|
|
17195
|
-
return response;
|
|
17196
17411
|
};
|
|
17197
17412
|
/**
|
|
17198
17413
|
* A utility method that determines if a failed task should be added to the
|
|
@@ -17385,6 +17600,7 @@ export {
|
|
|
17385
17600
|
MODERATION_ENTITY_TYPES,
|
|
17386
17601
|
MaxPriority,
|
|
17387
17602
|
MentionsSearchSource,
|
|
17603
|
+
MergedStateStore,
|
|
17388
17604
|
MessageComposer,
|
|
17389
17605
|
MessageComposerMiddlewareExecutor,
|
|
17390
17606
|
MessageDraftComposerMiddlewareExecutor,
|
|
@@ -17393,6 +17609,7 @@ export {
|
|
|
17393
17609
|
MinPriority,
|
|
17394
17610
|
Moderation,
|
|
17395
17611
|
OfflineDBSyncManager,
|
|
17612
|
+
OfflineError,
|
|
17396
17613
|
Permission,
|
|
17397
17614
|
Poll,
|
|
17398
17615
|
PollComposer,
|