stream-chat 9.28.0 → 9.30.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.js +576 -341
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +576 -341
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +576 -341
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/CooldownTimer.d.ts +45 -0
- package/dist/types/channel.d.ts +5 -2
- package/dist/types/channel_state.d.ts +1 -1
- package/dist/types/client.d.ts +51 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/insights.d.ts +2 -2
- package/dist/types/messageComposer/fileUtils.d.ts +1 -1
- package/dist/types/messageComposer/messageComposer.d.ts +3 -3
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +2 -2
- package/dist/types/messageComposer/types.d.ts +8 -0
- package/dist/types/types.d.ts +73 -0
- package/dist/types/utils.d.ts +5 -5
- package/package.json +1 -1
- package/src/CooldownTimer.ts +196 -0
- package/src/channel.ts +14 -1
- package/src/client.ts +121 -11
- package/src/index.ts +1 -0
- package/src/messageComposer/attachmentManager.ts +18 -13
- package/src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts +5 -4
- package/src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts +5 -4
- package/src/messageComposer/types.ts +8 -0
- package/src/types.ts +86 -0
package/dist/esm/index.mjs
CHANGED
|
@@ -1944,6 +1944,399 @@ var ChannelState = class {
|
|
|
1944
1944
|
}
|
|
1945
1945
|
};
|
|
1946
1946
|
|
|
1947
|
+
// src/store.ts
|
|
1948
|
+
var isPatch = (value) => typeof value === "function";
|
|
1949
|
+
var noop = () => {
|
|
1950
|
+
};
|
|
1951
|
+
var StateStore = class {
|
|
1952
|
+
constructor(value) {
|
|
1953
|
+
this.value = value;
|
|
1954
|
+
this.handlers = /* @__PURE__ */ new Set();
|
|
1955
|
+
this.preprocessors = /* @__PURE__ */ new Set();
|
|
1956
|
+
this.partialNext = (partial) => this.next((current) => ({ ...current, ...partial }));
|
|
1957
|
+
this.subscribeWithSelector = (selector, handler) => {
|
|
1958
|
+
let previouslySelectedValues;
|
|
1959
|
+
const wrappedHandler = (nextValue) => {
|
|
1960
|
+
const newlySelectedValues = selector(nextValue);
|
|
1961
|
+
let hasUpdatedValues = typeof previouslySelectedValues === "undefined";
|
|
1962
|
+
for (const key in previouslySelectedValues) {
|
|
1963
|
+
if (previouslySelectedValues[key] === newlySelectedValues[key]) continue;
|
|
1964
|
+
hasUpdatedValues = true;
|
|
1965
|
+
break;
|
|
1966
|
+
}
|
|
1967
|
+
if (!hasUpdatedValues) return;
|
|
1968
|
+
const previouslySelectedValuesCopy = previouslySelectedValues;
|
|
1969
|
+
previouslySelectedValues = newlySelectedValues;
|
|
1970
|
+
handler(newlySelectedValues, previouslySelectedValuesCopy);
|
|
1971
|
+
};
|
|
1972
|
+
return this.subscribe(wrappedHandler);
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Allows merging two stores only if their keys differ otherwise there's no way to ensure the data type stability.
|
|
1977
|
+
* @experimental
|
|
1978
|
+
* This method is experimental and may change in future versions.
|
|
1979
|
+
*/
|
|
1980
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1981
|
+
merge(stateStore) {
|
|
1982
|
+
return new MergedStateStore({
|
|
1983
|
+
original: this,
|
|
1984
|
+
merged: stateStore
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
next(newValueOrPatch) {
|
|
1988
|
+
const newValue = isPatch(newValueOrPatch) ? newValueOrPatch(this.value) : newValueOrPatch;
|
|
1989
|
+
if (newValue === this.value) return;
|
|
1990
|
+
this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
|
|
1991
|
+
const oldValue = this.value;
|
|
1992
|
+
this.value = newValue;
|
|
1993
|
+
this.handlers.forEach((handler) => handler(this.value, oldValue));
|
|
1994
|
+
}
|
|
1995
|
+
getLatestValue() {
|
|
1996
|
+
return this.value;
|
|
1997
|
+
}
|
|
1998
|
+
subscribe(handler) {
|
|
1999
|
+
handler(this.value, void 0);
|
|
2000
|
+
this.handlers.add(handler);
|
|
2001
|
+
return () => {
|
|
2002
|
+
this.handlers.delete(handler);
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Registers a preprocessor function that will be called before the state is updated.
|
|
2007
|
+
*
|
|
2008
|
+
* Preprocessors are invoked with the new and previous values whenever `next` or `partialNext` methods
|
|
2009
|
+
* are called, allowing you to mutate or react to the new value before it is set. Preprocessors run in the
|
|
2010
|
+
* order they were registered.
|
|
2011
|
+
*
|
|
2012
|
+
* @example
|
|
2013
|
+
* ```ts
|
|
2014
|
+
* const store = new StateStore<{ count: number; isMaxValue: bool; }>({ count: 0, isMaxValue: false });
|
|
2015
|
+
*
|
|
2016
|
+
* store.addPreprocessor((nextValue, prevValue) => {
|
|
2017
|
+
* if (nextValue.count > 10) {
|
|
2018
|
+
* nextValue.count = 10; // Clamp the value to a maximum of 10
|
|
2019
|
+
* }
|
|
2020
|
+
*
|
|
2021
|
+
* if (nextValue.count === 10) {
|
|
2022
|
+
* nextValue.isMaxValue = true; // Set isMaxValue to true if count is 10
|
|
2023
|
+
* } else {
|
|
2024
|
+
* nextValue.isMaxValue = false; // Reset isMaxValue otherwise
|
|
2025
|
+
* }
|
|
2026
|
+
* });
|
|
2027
|
+
*
|
|
2028
|
+
* store.partialNext({ count: 15 });
|
|
2029
|
+
*
|
|
2030
|
+
* store.getLatestValue(); // { count: 10, isMaxValue: true }
|
|
2031
|
+
*
|
|
2032
|
+
* store.partialNext({ count: 5 });
|
|
2033
|
+
*
|
|
2034
|
+
* store.getLatestValue(); // { count: 5, isMaxValue: false }
|
|
2035
|
+
* ```
|
|
2036
|
+
*
|
|
2037
|
+
* @param preprocessor - The function to be called with the next and previous values before the state is updated.
|
|
2038
|
+
* @returns A `RemovePreprocessor` function that removes the preprocessor when called.
|
|
2039
|
+
*/
|
|
2040
|
+
addPreprocessor(preprocessor) {
|
|
2041
|
+
this.preprocessors.add(preprocessor);
|
|
2042
|
+
return () => {
|
|
2043
|
+
this.preprocessors.delete(preprocessor);
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
var MergedStateStore = class _MergedStateStore extends StateStore {
|
|
2048
|
+
constructor({ original, merged }) {
|
|
2049
|
+
const originalValue = original.getLatestValue();
|
|
2050
|
+
const mergedValue = merged.getLatestValue();
|
|
2051
|
+
super({
|
|
2052
|
+
...originalValue,
|
|
2053
|
+
...mergedValue
|
|
2054
|
+
});
|
|
2055
|
+
// override original methods and "disable" them
|
|
2056
|
+
this.next = () => {
|
|
2057
|
+
console.warn(
|
|
2058
|
+
`${_MergedStateStore.name}.next is disabled, call original.next or merged.next instead`
|
|
2059
|
+
);
|
|
2060
|
+
};
|
|
2061
|
+
this.partialNext = () => {
|
|
2062
|
+
console.warn(
|
|
2063
|
+
`${_MergedStateStore.name}.partialNext is disabled, call original.partialNext or merged.partialNext instead`
|
|
2064
|
+
);
|
|
2065
|
+
};
|
|
2066
|
+
this.cachedOriginalValue = originalValue;
|
|
2067
|
+
this.cachedMergedValue = mergedValue;
|
|
2068
|
+
this.original = original;
|
|
2069
|
+
this.merged = merged;
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Subscribes to changes in the merged state store.
|
|
2073
|
+
*
|
|
2074
|
+
* This method extends the base subscribe functionality to handle the merged nature of this store:
|
|
2075
|
+
* 1. The first subscriber triggers registration of helper subscribers that listen to both source stores
|
|
2076
|
+
* 2. Changes from either source store are propagated to this merged store
|
|
2077
|
+
* 3. Source store values are cached to prevent unnecessary updates
|
|
2078
|
+
*
|
|
2079
|
+
* When the first subscriber is added, the method sets up listeners on both original and merged stores.
|
|
2080
|
+
* These listeners update the combined store value whenever either source store changes.
|
|
2081
|
+
* All subscriptions (helpers and the actual handler) are tracked so they can be properly cleaned up.
|
|
2082
|
+
*
|
|
2083
|
+
* @param handler - The callback function that will be executed when the state changes
|
|
2084
|
+
* @returns An unsubscribe function that, when called, removes the subscription and any helper subscriptions
|
|
2085
|
+
*/
|
|
2086
|
+
subscribe(handler) {
|
|
2087
|
+
const unsubscribeFunctions = [];
|
|
2088
|
+
if (!this.handlers.size) {
|
|
2089
|
+
const base = (nextValue) => {
|
|
2090
|
+
super.next((currentValue) => ({
|
|
2091
|
+
...currentValue,
|
|
2092
|
+
...nextValue
|
|
2093
|
+
}));
|
|
2094
|
+
};
|
|
2095
|
+
unsubscribeFunctions.push(
|
|
2096
|
+
this.original.subscribe((nextValue) => {
|
|
2097
|
+
if (nextValue === this.cachedOriginalValue) return;
|
|
2098
|
+
this.cachedOriginalValue = nextValue;
|
|
2099
|
+
base(nextValue);
|
|
2100
|
+
}),
|
|
2101
|
+
this.merged.subscribe((nextValue) => {
|
|
2102
|
+
if (nextValue === this.cachedMergedValue) return;
|
|
2103
|
+
this.cachedMergedValue = nextValue;
|
|
2104
|
+
base(nextValue);
|
|
2105
|
+
})
|
|
2106
|
+
);
|
|
2107
|
+
}
|
|
2108
|
+
unsubscribeFunctions.push(super.subscribe(handler));
|
|
2109
|
+
return () => {
|
|
2110
|
+
unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Retrieves the latest combined state from both original and merged stores.
|
|
2115
|
+
*
|
|
2116
|
+
* This method extends the base getLatestValue functionality to ensure the merged store
|
|
2117
|
+
* remains in sync with its source stores even when there are no active subscribers.
|
|
2118
|
+
*
|
|
2119
|
+
* When there are no handlers registered, the method:
|
|
2120
|
+
* 1. Fetches the latest values from both source stores
|
|
2121
|
+
* 2. Compares them with the cached values to detect changes
|
|
2122
|
+
* 3. If changes are detected, updates the internal value and caches
|
|
2123
|
+
* the new source values to maintain consistency
|
|
2124
|
+
*
|
|
2125
|
+
* This approach ensures that calling getLatestValue() always returns the most
|
|
2126
|
+
* up-to-date combined state, even if the merged store hasn't been actively
|
|
2127
|
+
* receiving updates through subscriptions.
|
|
2128
|
+
*
|
|
2129
|
+
* @returns The latest combined state from both original and merged stores
|
|
2130
|
+
*/
|
|
2131
|
+
getLatestValue() {
|
|
2132
|
+
if (!this.handlers.size) {
|
|
2133
|
+
const originalValue = this.original.getLatestValue();
|
|
2134
|
+
const mergedValue = this.merged.getLatestValue();
|
|
2135
|
+
if (originalValue !== this.cachedOriginalValue || mergedValue !== this.cachedMergedValue) {
|
|
2136
|
+
this.value = {
|
|
2137
|
+
...originalValue,
|
|
2138
|
+
...mergedValue
|
|
2139
|
+
};
|
|
2140
|
+
this.cachedMergedValue = mergedValue;
|
|
2141
|
+
this.cachedOriginalValue = originalValue;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
return super.getLatestValue();
|
|
2145
|
+
}
|
|
2146
|
+
addPreprocessor() {
|
|
2147
|
+
console.warn(
|
|
2148
|
+
`${_MergedStateStore.name}.addPreprocessor is disabled, call original.addPreprocessor or merged.addPreprocessor instead`
|
|
2149
|
+
);
|
|
2150
|
+
return noop;
|
|
2151
|
+
}
|
|
2152
|
+
};
|
|
2153
|
+
|
|
2154
|
+
// src/utils/WithSubscriptions.ts
|
|
2155
|
+
var _WithSubscriptions = class _WithSubscriptions {
|
|
2156
|
+
constructor() {
|
|
2157
|
+
this.unsubscribeFunctions = /* @__PURE__ */ new Set();
|
|
2158
|
+
this.refCount = 0;
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Returns a boolean, provides information of whether `registerSubscriptions`
|
|
2162
|
+
* method has already been called for this instance.
|
|
2163
|
+
*/
|
|
2164
|
+
get hasSubscriptions() {
|
|
2165
|
+
return this.unsubscribeFunctions.size > 0;
|
|
2166
|
+
}
|
|
2167
|
+
addUnsubscribeFunction(unsubscribeFunction) {
|
|
2168
|
+
this.unsubscribeFunctions.add(unsubscribeFunction);
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Increments `refCount` by one and returns new value.
|
|
2172
|
+
*/
|
|
2173
|
+
incrementRefCount() {
|
|
2174
|
+
return ++this.refCount;
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* If you re-declare `unregisterSubscriptions` method within your class
|
|
2178
|
+
* make sure to run the original too.
|
|
2179
|
+
*
|
|
2180
|
+
* @example
|
|
2181
|
+
* ```ts
|
|
2182
|
+
* class T extends WithSubscriptions {
|
|
2183
|
+
* ...
|
|
2184
|
+
* public unregisterSubscriptions = () => {
|
|
2185
|
+
* this.customThing();
|
|
2186
|
+
* return super.unregisterSubscriptions();
|
|
2187
|
+
* }
|
|
2188
|
+
* }
|
|
2189
|
+
* ```
|
|
2190
|
+
*/
|
|
2191
|
+
unregisterSubscriptions() {
|
|
2192
|
+
if (this.refCount > 1) {
|
|
2193
|
+
this.refCount--;
|
|
2194
|
+
return _WithSubscriptions.symbol;
|
|
2195
|
+
}
|
|
2196
|
+
this.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
2197
|
+
this.unsubscribeFunctions.clear();
|
|
2198
|
+
this.refCount = 0;
|
|
2199
|
+
return _WithSubscriptions.symbol;
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
/**
|
|
2203
|
+
* Workaround for the missing TS keyword - ensures that inheritants
|
|
2204
|
+
* overriding `unregisterSubscriptions` call the base method and return
|
|
2205
|
+
* its unique symbol value.
|
|
2206
|
+
*/
|
|
2207
|
+
_WithSubscriptions.symbol = Symbol(_WithSubscriptions.name);
|
|
2208
|
+
var WithSubscriptions = _WithSubscriptions;
|
|
2209
|
+
|
|
2210
|
+
// src/CooldownTimer.ts
|
|
2211
|
+
var toDateOrUndefined = (value) => {
|
|
2212
|
+
if (value instanceof Date) return value;
|
|
2213
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
2214
|
+
const parsed = new Date(value);
|
|
2215
|
+
if (!Number.isNaN(parsed.getTime())) return parsed;
|
|
2216
|
+
}
|
|
2217
|
+
return void 0;
|
|
2218
|
+
};
|
|
2219
|
+
var CooldownTimer = class extends WithSubscriptions {
|
|
2220
|
+
constructor({ channel }) {
|
|
2221
|
+
super();
|
|
2222
|
+
this.timeout = null;
|
|
2223
|
+
this.registerSubscriptions = () => {
|
|
2224
|
+
this.incrementRefCount();
|
|
2225
|
+
if (this.hasSubscriptions) return;
|
|
2226
|
+
this.addUnsubscribeFunction(
|
|
2227
|
+
this.channel.on("message.new", (event) => {
|
|
2228
|
+
const isOwnMessage = event.message?.user?.id && event.message.user.id === this.getOwnUserId();
|
|
2229
|
+
if (!isOwnMessage) return;
|
|
2230
|
+
this.setOwnLatestMessageDate(toDateOrUndefined(event.message?.created_at));
|
|
2231
|
+
}).unsubscribe
|
|
2232
|
+
);
|
|
2233
|
+
this.addUnsubscribeFunction(
|
|
2234
|
+
this.channel.on("channel.updated", (event) => {
|
|
2235
|
+
const cooldownChanged = event.channel?.cooldown !== this.cooldownConfigSeconds;
|
|
2236
|
+
if (!cooldownChanged) return;
|
|
2237
|
+
this.refresh();
|
|
2238
|
+
}).unsubscribe
|
|
2239
|
+
);
|
|
2240
|
+
};
|
|
2241
|
+
this.setCooldownRemaining = (cooldownRemaining) => {
|
|
2242
|
+
this.state.partialNext({ cooldownRemaining });
|
|
2243
|
+
};
|
|
2244
|
+
this.clearTimeout = () => {
|
|
2245
|
+
if (!this.timeout) return;
|
|
2246
|
+
clearTimeout(this.timeout);
|
|
2247
|
+
this.timeout = null;
|
|
2248
|
+
};
|
|
2249
|
+
this.refresh = () => {
|
|
2250
|
+
const { cooldown: cooldownConfigSeconds = 0, own_capabilities } = this.channel.data ?? {};
|
|
2251
|
+
const canSkipCooldown = (own_capabilities ?? []).includes("skip-slow-mode");
|
|
2252
|
+
const ownLatestMessageDate = this.findOwnLatestMessageDate({
|
|
2253
|
+
messages: this.channel.state.latestMessages
|
|
2254
|
+
});
|
|
2255
|
+
if (cooldownConfigSeconds !== this.cooldownConfigSeconds || ownLatestMessageDate?.getTime() !== this.ownLatestMessageDate?.getTime() || canSkipCooldown !== this.canSkipCooldown) {
|
|
2256
|
+
this.state.partialNext({
|
|
2257
|
+
cooldownConfigSeconds,
|
|
2258
|
+
ownLatestMessageDate,
|
|
2259
|
+
canSkipCooldown
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
if (this.canSkipCooldown || this.cooldownConfigSeconds === 0) {
|
|
2263
|
+
this.clearTimeout();
|
|
2264
|
+
if (this.cooldownRemaining !== 0) {
|
|
2265
|
+
this.setCooldownRemaining(0);
|
|
2266
|
+
}
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
this.recalculate();
|
|
2270
|
+
};
|
|
2271
|
+
/**
|
|
2272
|
+
* Updates the known latest own message date and recomputes remaining time.
|
|
2273
|
+
* Prefer calling this when you already know the message date (e.g. from an event).
|
|
2274
|
+
*/
|
|
2275
|
+
this.setOwnLatestMessageDate = (date) => {
|
|
2276
|
+
this.state.partialNext({ ownLatestMessageDate: date });
|
|
2277
|
+
this.recalculate();
|
|
2278
|
+
};
|
|
2279
|
+
this.recalculate = () => {
|
|
2280
|
+
this.clearTimeout();
|
|
2281
|
+
const { cooldownConfigSeconds, ownLatestMessageDate, canSkipCooldown } = this.state.getLatestValue();
|
|
2282
|
+
const timeSinceOwnLastMessage = ownLatestMessageDate != null ? (
|
|
2283
|
+
// prevent negative values
|
|
2284
|
+
Math.max(0, (Date.now() - ownLatestMessageDate.getTime()) / 1e3)
|
|
2285
|
+
) : void 0;
|
|
2286
|
+
const remaining = !canSkipCooldown && typeof timeSinceOwnLastMessage !== "undefined" && cooldownConfigSeconds > timeSinceOwnLastMessage ? Math.round(cooldownConfigSeconds - timeSinceOwnLastMessage) : 0;
|
|
2287
|
+
if (remaining !== this.cooldownRemaining) {
|
|
2288
|
+
this.setCooldownRemaining(remaining);
|
|
2289
|
+
}
|
|
2290
|
+
if (remaining <= 0) return;
|
|
2291
|
+
this.timeout = setTimeout(() => {
|
|
2292
|
+
this.recalculate();
|
|
2293
|
+
}, 1e3);
|
|
2294
|
+
};
|
|
2295
|
+
this.channel = channel;
|
|
2296
|
+
this.state = new StateStore({
|
|
2297
|
+
cooldownConfigSeconds: 0,
|
|
2298
|
+
cooldownRemaining: 0,
|
|
2299
|
+
ownLatestMessageDate: void 0,
|
|
2300
|
+
canSkipCooldown: false
|
|
2301
|
+
});
|
|
2302
|
+
this.refresh();
|
|
2303
|
+
}
|
|
2304
|
+
get cooldownConfigSeconds() {
|
|
2305
|
+
return this.state.getLatestValue().cooldownConfigSeconds;
|
|
2306
|
+
}
|
|
2307
|
+
get cooldownRemaining() {
|
|
2308
|
+
return this.state.getLatestValue().cooldownRemaining;
|
|
2309
|
+
}
|
|
2310
|
+
get canSkipCooldown() {
|
|
2311
|
+
return this.state.getLatestValue().canSkipCooldown;
|
|
2312
|
+
}
|
|
2313
|
+
get ownLatestMessageDate() {
|
|
2314
|
+
return this.state.getLatestValue().ownLatestMessageDate;
|
|
2315
|
+
}
|
|
2316
|
+
getOwnUserId() {
|
|
2317
|
+
const client = this.channel.getClient();
|
|
2318
|
+
return client.userID ?? client.user?.id;
|
|
2319
|
+
}
|
|
2320
|
+
findOwnLatestMessageDate({
|
|
2321
|
+
messages
|
|
2322
|
+
}) {
|
|
2323
|
+
const ownUserId = this.getOwnUserId();
|
|
2324
|
+
if (!ownUserId) return void 0;
|
|
2325
|
+
let latest;
|
|
2326
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2327
|
+
const message = messages[i];
|
|
2328
|
+
if (message.user?.id !== ownUserId) continue;
|
|
2329
|
+
const createdAt = toDateOrUndefined(message.created_at);
|
|
2330
|
+
if (!createdAt) continue;
|
|
2331
|
+
if (!latest || createdAt.getTime() > latest.getTime()) {
|
|
2332
|
+
latest = createdAt;
|
|
2333
|
+
}
|
|
2334
|
+
if (latest.getTime() > createdAt.getTime()) break;
|
|
2335
|
+
}
|
|
2336
|
+
return latest;
|
|
2337
|
+
}
|
|
2338
|
+
};
|
|
2339
|
+
|
|
1947
2340
|
// src/messageComposer/attachmentIdentity.ts
|
|
1948
2341
|
var isScrapedContent = (attachment) => !!attachment?.og_scrape_url || !!attachment?.title_link;
|
|
1949
2342
|
var isLocalAttachment = (attachment) => !!attachment?.localMetadata?.id;
|
|
@@ -2035,11 +2428,12 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2035
2428
|
if (error) return forward();
|
|
2036
2429
|
if (!attachment || !response) return discard();
|
|
2037
2430
|
const enrichedAttachment = { ...attachment };
|
|
2431
|
+
const previewUri = attachment.localMetadata.previewUri;
|
|
2432
|
+
if (previewUri) {
|
|
2433
|
+
if (previewUri.startsWith("blob:")) URL.revokeObjectURL(previewUri);
|
|
2434
|
+
delete enrichedAttachment.localMetadata.previewUri;
|
|
2435
|
+
}
|
|
2038
2436
|
if (isLocalImageAttachment(attachment)) {
|
|
2039
|
-
if (attachment.localMetadata.previewUri) {
|
|
2040
|
-
URL.revokeObjectURL(attachment.localMetadata.previewUri);
|
|
2041
|
-
delete enrichedAttachment.localMetadata.previewUri;
|
|
2042
|
-
}
|
|
2043
2437
|
enrichedAttachment.image_url = response.file;
|
|
2044
2438
|
} else {
|
|
2045
2439
|
enrichedAttachment.asset_url = response.file;
|
|
@@ -2250,275 +2644,68 @@ var createUploadConfigCheckMiddleware = (composer) => ({
|
|
|
2250
2644
|
id: "stream-io/attachment-manager-middleware/file-upload-config-check",
|
|
2251
2645
|
handlers: {
|
|
2252
2646
|
prepare: async ({
|
|
2253
|
-
state,
|
|
2254
|
-
next,
|
|
2255
|
-
discard
|
|
2256
|
-
}) => {
|
|
2257
|
-
const { attachmentManager } = composer;
|
|
2258
|
-
if (!attachmentManager || !state.attachment) return discard();
|
|
2259
|
-
const uploadPermissionCheck = await attachmentManager.getUploadConfigCheck(
|
|
2260
|
-
state.attachment.localMetadata.file
|
|
2261
|
-
);
|
|
2262
|
-
const attachment = {
|
|
2263
|
-
...state.attachment,
|
|
2264
|
-
localMetadata: {
|
|
2265
|
-
...state.attachment.localMetadata,
|
|
2266
|
-
uploadPermissionCheck,
|
|
2267
|
-
uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
|
|
2268
|
-
}
|
|
2269
|
-
};
|
|
2270
|
-
return next({
|
|
2271
|
-
...state,
|
|
2272
|
-
attachment
|
|
2273
|
-
});
|
|
2274
|
-
}
|
|
2275
|
-
}
|
|
2276
|
-
});
|
|
2277
|
-
|
|
2278
|
-
// src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts
|
|
2279
|
-
var createBlockedAttachmentUploadNotificationMiddleware = (composer) => ({
|
|
2280
|
-
id: "stream-io/attachment-manager-middleware/blocked-upload-notification",
|
|
2281
|
-
handlers: {
|
|
2282
|
-
prepare: ({
|
|
2283
|
-
state: { attachment },
|
|
2284
|
-
forward
|
|
2285
|
-
}) => {
|
|
2286
|
-
if (!attachment) return forward();
|
|
2287
|
-
if (attachment.localMetadata.uploadPermissionCheck?.uploadBlocked) {
|
|
2288
|
-
composer.client.notifications.addError({
|
|
2289
|
-
message: `The attachment upload was blocked`,
|
|
2290
|
-
origin: {
|
|
2291
|
-
emitter: "AttachmentManager",
|
|
2292
|
-
context: { blockedAttachment: attachment }
|
|
2293
|
-
},
|
|
2294
|
-
options: {
|
|
2295
|
-
type: "validation:attachment:upload:blocked",
|
|
2296
|
-
metadata: {
|
|
2297
|
-
reason: attachment.localMetadata.uploadPermissionCheck?.reason
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2302
|
-
return forward();
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
});
|
|
2306
|
-
|
|
2307
|
-
// src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts
|
|
2308
|
-
var AttachmentPreUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
2309
|
-
constructor({ composer }) {
|
|
2310
|
-
super();
|
|
2311
|
-
this.use([
|
|
2312
|
-
createUploadConfigCheckMiddleware(composer),
|
|
2313
|
-
createBlockedAttachmentUploadNotificationMiddleware(composer)
|
|
2314
|
-
]);
|
|
2315
|
-
}
|
|
2316
|
-
};
|
|
2317
|
-
|
|
2318
|
-
// src/store.ts
|
|
2319
|
-
var isPatch = (value) => typeof value === "function";
|
|
2320
|
-
var noop = () => {
|
|
2321
|
-
};
|
|
2322
|
-
var StateStore = class {
|
|
2323
|
-
constructor(value) {
|
|
2324
|
-
this.value = value;
|
|
2325
|
-
this.handlers = /* @__PURE__ */ new Set();
|
|
2326
|
-
this.preprocessors = /* @__PURE__ */ new Set();
|
|
2327
|
-
this.partialNext = (partial) => this.next((current) => ({ ...current, ...partial }));
|
|
2328
|
-
this.subscribeWithSelector = (selector, handler) => {
|
|
2329
|
-
let previouslySelectedValues;
|
|
2330
|
-
const wrappedHandler = (nextValue) => {
|
|
2331
|
-
const newlySelectedValues = selector(nextValue);
|
|
2332
|
-
let hasUpdatedValues = typeof previouslySelectedValues === "undefined";
|
|
2333
|
-
for (const key in previouslySelectedValues) {
|
|
2334
|
-
if (previouslySelectedValues[key] === newlySelectedValues[key]) continue;
|
|
2335
|
-
hasUpdatedValues = true;
|
|
2336
|
-
break;
|
|
2337
|
-
}
|
|
2338
|
-
if (!hasUpdatedValues) return;
|
|
2339
|
-
const previouslySelectedValuesCopy = previouslySelectedValues;
|
|
2340
|
-
previouslySelectedValues = newlySelectedValues;
|
|
2341
|
-
handler(newlySelectedValues, previouslySelectedValuesCopy);
|
|
2342
|
-
};
|
|
2343
|
-
return this.subscribe(wrappedHandler);
|
|
2344
|
-
};
|
|
2345
|
-
}
|
|
2346
|
-
/**
|
|
2347
|
-
* Allows merging two stores only if their keys differ otherwise there's no way to ensure the data type stability.
|
|
2348
|
-
* @experimental
|
|
2349
|
-
* This method is experimental and may change in future versions.
|
|
2350
|
-
*/
|
|
2351
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2352
|
-
merge(stateStore) {
|
|
2353
|
-
return new MergedStateStore({
|
|
2354
|
-
original: this,
|
|
2355
|
-
merged: stateStore
|
|
2356
|
-
});
|
|
2357
|
-
}
|
|
2358
|
-
next(newValueOrPatch) {
|
|
2359
|
-
const newValue = isPatch(newValueOrPatch) ? newValueOrPatch(this.value) : newValueOrPatch;
|
|
2360
|
-
if (newValue === this.value) return;
|
|
2361
|
-
this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
|
|
2362
|
-
const oldValue = this.value;
|
|
2363
|
-
this.value = newValue;
|
|
2364
|
-
this.handlers.forEach((handler) => handler(this.value, oldValue));
|
|
2365
|
-
}
|
|
2366
|
-
getLatestValue() {
|
|
2367
|
-
return this.value;
|
|
2368
|
-
}
|
|
2369
|
-
subscribe(handler) {
|
|
2370
|
-
handler(this.value, void 0);
|
|
2371
|
-
this.handlers.add(handler);
|
|
2372
|
-
return () => {
|
|
2373
|
-
this.handlers.delete(handler);
|
|
2374
|
-
};
|
|
2375
|
-
}
|
|
2376
|
-
/**
|
|
2377
|
-
* Registers a preprocessor function that will be called before the state is updated.
|
|
2378
|
-
*
|
|
2379
|
-
* Preprocessors are invoked with the new and previous values whenever `next` or `partialNext` methods
|
|
2380
|
-
* are called, allowing you to mutate or react to the new value before it is set. Preprocessors run in the
|
|
2381
|
-
* order they were registered.
|
|
2382
|
-
*
|
|
2383
|
-
* @example
|
|
2384
|
-
* ```ts
|
|
2385
|
-
* const store = new StateStore<{ count: number; isMaxValue: bool; }>({ count: 0, isMaxValue: false });
|
|
2386
|
-
*
|
|
2387
|
-
* store.addPreprocessor((nextValue, prevValue) => {
|
|
2388
|
-
* if (nextValue.count > 10) {
|
|
2389
|
-
* nextValue.count = 10; // Clamp the value to a maximum of 10
|
|
2390
|
-
* }
|
|
2391
|
-
*
|
|
2392
|
-
* if (nextValue.count === 10) {
|
|
2393
|
-
* nextValue.isMaxValue = true; // Set isMaxValue to true if count is 10
|
|
2394
|
-
* } else {
|
|
2395
|
-
* nextValue.isMaxValue = false; // Reset isMaxValue otherwise
|
|
2396
|
-
* }
|
|
2397
|
-
* });
|
|
2398
|
-
*
|
|
2399
|
-
* store.partialNext({ count: 15 });
|
|
2400
|
-
*
|
|
2401
|
-
* store.getLatestValue(); // { count: 10, isMaxValue: true }
|
|
2402
|
-
*
|
|
2403
|
-
* store.partialNext({ count: 5 });
|
|
2404
|
-
*
|
|
2405
|
-
* store.getLatestValue(); // { count: 5, isMaxValue: false }
|
|
2406
|
-
* ```
|
|
2407
|
-
*
|
|
2408
|
-
* @param preprocessor - The function to be called with the next and previous values before the state is updated.
|
|
2409
|
-
* @returns A `RemovePreprocessor` function that removes the preprocessor when called.
|
|
2410
|
-
*/
|
|
2411
|
-
addPreprocessor(preprocessor) {
|
|
2412
|
-
this.preprocessors.add(preprocessor);
|
|
2413
|
-
return () => {
|
|
2414
|
-
this.preprocessors.delete(preprocessor);
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
|
-
};
|
|
2418
|
-
var MergedStateStore = class _MergedStateStore extends StateStore {
|
|
2419
|
-
constructor({ original, merged }) {
|
|
2420
|
-
const originalValue = original.getLatestValue();
|
|
2421
|
-
const mergedValue = merged.getLatestValue();
|
|
2422
|
-
super({
|
|
2423
|
-
...originalValue,
|
|
2424
|
-
...mergedValue
|
|
2425
|
-
});
|
|
2426
|
-
// override original methods and "disable" them
|
|
2427
|
-
this.next = () => {
|
|
2428
|
-
console.warn(
|
|
2429
|
-
`${_MergedStateStore.name}.next is disabled, call original.next or merged.next instead`
|
|
2430
|
-
);
|
|
2431
|
-
};
|
|
2432
|
-
this.partialNext = () => {
|
|
2433
|
-
console.warn(
|
|
2434
|
-
`${_MergedStateStore.name}.partialNext is disabled, call original.partialNext or merged.partialNext instead`
|
|
2647
|
+
state,
|
|
2648
|
+
next,
|
|
2649
|
+
discard
|
|
2650
|
+
}) => {
|
|
2651
|
+
const { attachmentManager } = composer;
|
|
2652
|
+
if (!attachmentManager || !state.attachment) return discard();
|
|
2653
|
+
const uploadPermissionCheck = await attachmentManager.getUploadConfigCheck(
|
|
2654
|
+
state.attachment.localMetadata.file
|
|
2435
2655
|
);
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
* Subscribes to changes in the merged state store.
|
|
2444
|
-
*
|
|
2445
|
-
* This method extends the base subscribe functionality to handle the merged nature of this store:
|
|
2446
|
-
* 1. The first subscriber triggers registration of helper subscribers that listen to both source stores
|
|
2447
|
-
* 2. Changes from either source store are propagated to this merged store
|
|
2448
|
-
* 3. Source store values are cached to prevent unnecessary updates
|
|
2449
|
-
*
|
|
2450
|
-
* When the first subscriber is added, the method sets up listeners on both original and merged stores.
|
|
2451
|
-
* These listeners update the combined store value whenever either source store changes.
|
|
2452
|
-
* All subscriptions (helpers and the actual handler) are tracked so they can be properly cleaned up.
|
|
2453
|
-
*
|
|
2454
|
-
* @param handler - The callback function that will be executed when the state changes
|
|
2455
|
-
* @returns An unsubscribe function that, when called, removes the subscription and any helper subscriptions
|
|
2456
|
-
*/
|
|
2457
|
-
subscribe(handler) {
|
|
2458
|
-
const unsubscribeFunctions = [];
|
|
2459
|
-
if (!this.handlers.size) {
|
|
2460
|
-
const base = (nextValue) => {
|
|
2461
|
-
super.next((currentValue) => ({
|
|
2462
|
-
...currentValue,
|
|
2463
|
-
...nextValue
|
|
2464
|
-
}));
|
|
2656
|
+
const attachment = {
|
|
2657
|
+
...state.attachment,
|
|
2658
|
+
localMetadata: {
|
|
2659
|
+
...state.attachment.localMetadata,
|
|
2660
|
+
uploadPermissionCheck,
|
|
2661
|
+
uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
|
|
2662
|
+
}
|
|
2465
2663
|
};
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
base(nextValue);
|
|
2471
|
-
}),
|
|
2472
|
-
this.merged.subscribe((nextValue) => {
|
|
2473
|
-
if (nextValue === this.cachedMergedValue) return;
|
|
2474
|
-
this.cachedMergedValue = nextValue;
|
|
2475
|
-
base(nextValue);
|
|
2476
|
-
})
|
|
2477
|
-
);
|
|
2664
|
+
return next({
|
|
2665
|
+
...state,
|
|
2666
|
+
attachment
|
|
2667
|
+
});
|
|
2478
2668
|
}
|
|
2479
|
-
unsubscribeFunctions.push(super.subscribe(handler));
|
|
2480
|
-
return () => {
|
|
2481
|
-
unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
2482
|
-
};
|
|
2483
2669
|
}
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
...mergedValue
|
|
2510
|
-
};
|
|
2511
|
-
this.cachedMergedValue = mergedValue;
|
|
2512
|
-
this.cachedOriginalValue = originalValue;
|
|
2670
|
+
});
|
|
2671
|
+
|
|
2672
|
+
// src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts
|
|
2673
|
+
var createBlockedAttachmentUploadNotificationMiddleware = (composer) => ({
|
|
2674
|
+
id: "stream-io/attachment-manager-middleware/blocked-upload-notification",
|
|
2675
|
+
handlers: {
|
|
2676
|
+
prepare: ({
|
|
2677
|
+
state: { attachment },
|
|
2678
|
+
forward
|
|
2679
|
+
}) => {
|
|
2680
|
+
if (!attachment) return forward();
|
|
2681
|
+
if (attachment.localMetadata.uploadPermissionCheck?.uploadBlocked) {
|
|
2682
|
+
composer.client.notifications.addError({
|
|
2683
|
+
message: `The attachment upload was blocked`,
|
|
2684
|
+
origin: {
|
|
2685
|
+
emitter: "AttachmentManager",
|
|
2686
|
+
context: { blockedAttachment: attachment }
|
|
2687
|
+
},
|
|
2688
|
+
options: {
|
|
2689
|
+
type: "validation:attachment:upload:blocked",
|
|
2690
|
+
metadata: {
|
|
2691
|
+
reason: attachment.localMetadata.uploadPermissionCheck?.reason
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
});
|
|
2513
2695
|
}
|
|
2696
|
+
return forward();
|
|
2514
2697
|
}
|
|
2515
|
-
return super.getLatestValue();
|
|
2516
2698
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2699
|
+
});
|
|
2700
|
+
|
|
2701
|
+
// src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts
|
|
2702
|
+
var AttachmentPreUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
2703
|
+
constructor({ composer }) {
|
|
2704
|
+
super();
|
|
2705
|
+
this.use([
|
|
2706
|
+
createUploadConfigCheckMiddleware(composer),
|
|
2707
|
+
createBlockedAttachmentUploadNotificationMiddleware(composer)
|
|
2708
|
+
]);
|
|
2522
2709
|
}
|
|
2523
2710
|
};
|
|
2524
2711
|
|
|
@@ -3148,11 +3335,12 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3148
3335
|
uploadState: "finished"
|
|
3149
3336
|
}
|
|
3150
3337
|
};
|
|
3338
|
+
const previewUri = uploadedAttachment.localMetadata.previewUri;
|
|
3339
|
+
if (previewUri) {
|
|
3340
|
+
if (previewUri.startsWith("blob:")) URL.revokeObjectURL(previewUri);
|
|
3341
|
+
delete uploadedAttachment.localMetadata.previewUri;
|
|
3342
|
+
}
|
|
3151
3343
|
if (isLocalImageAttachment(uploadedAttachment)) {
|
|
3152
|
-
if (uploadedAttachment.localMetadata.previewUri) {
|
|
3153
|
-
URL.revokeObjectURL(uploadedAttachment.localMetadata.previewUri);
|
|
3154
|
-
delete uploadedAttachment.localMetadata.previewUri;
|
|
3155
|
-
}
|
|
3156
3344
|
uploadedAttachment.image_url = response.file;
|
|
3157
3345
|
} else {
|
|
3158
3346
|
uploadedAttachment.asset_url = response.file;
|
|
@@ -3333,12 +3521,10 @@ _AttachmentManager.toLocalUploadAttachment = (fileLike) => {
|
|
|
3333
3521
|
type: getAttachmentTypeFromMimeType(file.type)
|
|
3334
3522
|
};
|
|
3335
3523
|
localAttachment[isImageFile(file) ? "fallback" : "title"] = file.name;
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
localAttachment.original_width = fileLike.width;
|
|
3341
|
-
}
|
|
3524
|
+
localAttachment.localMetadata.previewUri = isFileReference(fileLike) ? fileLike.uri : URL.createObjectURL?.(fileLike);
|
|
3525
|
+
if (isFileReference(fileLike) && fileLike.height && fileLike.width && isImageFile(file)) {
|
|
3526
|
+
localAttachment.original_height = fileLike.height;
|
|
3527
|
+
localAttachment.original_width = fileLike.width;
|
|
3342
3528
|
}
|
|
3343
3529
|
if (isFileReference(fileLike) && fileLike.thumb_url) {
|
|
3344
3530
|
localAttachment.thumb_url = fileLike.thumb_url;
|
|
@@ -5372,10 +5558,11 @@ var getTriggerCharWithToken = ({
|
|
|
5372
5558
|
isCommand = false,
|
|
5373
5559
|
acceptTrailingSpaces = true
|
|
5374
5560
|
}) => {
|
|
5375
|
-
const
|
|
5561
|
+
const escapedTrigger = escapeRegExp(trigger);
|
|
5562
|
+
const triggerNorWhitespace = `[^\\s${escapedTrigger}]*`;
|
|
5376
5563
|
const match = text.match(
|
|
5377
5564
|
new RegExp(
|
|
5378
|
-
isCommand ? `^[${
|
|
5565
|
+
isCommand ? `^[${escapedTrigger}]${triggerNorWhitespace}$` : acceptTrailingSpaces ? `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$` : `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}$`,
|
|
5379
5566
|
"g"
|
|
5380
5567
|
)
|
|
5381
5568
|
);
|
|
@@ -6153,62 +6340,6 @@ var TextComposer = class {
|
|
|
6153
6340
|
// --- END TEXT PROCESSING ----
|
|
6154
6341
|
};
|
|
6155
6342
|
|
|
6156
|
-
// src/utils/WithSubscriptions.ts
|
|
6157
|
-
var _WithSubscriptions = class _WithSubscriptions {
|
|
6158
|
-
constructor() {
|
|
6159
|
-
this.unsubscribeFunctions = /* @__PURE__ */ new Set();
|
|
6160
|
-
this.refCount = 0;
|
|
6161
|
-
}
|
|
6162
|
-
/**
|
|
6163
|
-
* Returns a boolean, provides information of whether `registerSubscriptions`
|
|
6164
|
-
* method has already been called for this instance.
|
|
6165
|
-
*/
|
|
6166
|
-
get hasSubscriptions() {
|
|
6167
|
-
return this.unsubscribeFunctions.size > 0;
|
|
6168
|
-
}
|
|
6169
|
-
addUnsubscribeFunction(unsubscribeFunction) {
|
|
6170
|
-
this.unsubscribeFunctions.add(unsubscribeFunction);
|
|
6171
|
-
}
|
|
6172
|
-
/**
|
|
6173
|
-
* Increments `refCount` by one and returns new value.
|
|
6174
|
-
*/
|
|
6175
|
-
incrementRefCount() {
|
|
6176
|
-
return ++this.refCount;
|
|
6177
|
-
}
|
|
6178
|
-
/**
|
|
6179
|
-
* If you re-declare `unregisterSubscriptions` method within your class
|
|
6180
|
-
* make sure to run the original too.
|
|
6181
|
-
*
|
|
6182
|
-
* @example
|
|
6183
|
-
* ```ts
|
|
6184
|
-
* class T extends WithSubscriptions {
|
|
6185
|
-
* ...
|
|
6186
|
-
* public unregisterSubscriptions = () => {
|
|
6187
|
-
* this.customThing();
|
|
6188
|
-
* return super.unregisterSubscriptions();
|
|
6189
|
-
* }
|
|
6190
|
-
* }
|
|
6191
|
-
* ```
|
|
6192
|
-
*/
|
|
6193
|
-
unregisterSubscriptions() {
|
|
6194
|
-
if (this.refCount > 1) {
|
|
6195
|
-
this.refCount--;
|
|
6196
|
-
return _WithSubscriptions.symbol;
|
|
6197
|
-
}
|
|
6198
|
-
this.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
6199
|
-
this.unsubscribeFunctions.clear();
|
|
6200
|
-
this.refCount = 0;
|
|
6201
|
-
return _WithSubscriptions.symbol;
|
|
6202
|
-
}
|
|
6203
|
-
};
|
|
6204
|
-
/**
|
|
6205
|
-
* Workaround for the missing TS keyword - ensures that inheritants
|
|
6206
|
-
* overriding `unregisterSubscriptions` call the base method and return
|
|
6207
|
-
* its unique symbol value.
|
|
6208
|
-
*/
|
|
6209
|
-
_WithSubscriptions.symbol = Symbol(_WithSubscriptions.name);
|
|
6210
|
-
var WithSubscriptions = _WithSubscriptions;
|
|
6211
|
-
|
|
6212
6343
|
// src/thread.ts
|
|
6213
6344
|
var DEFAULT_PAGE_LIMIT = 50;
|
|
6214
6345
|
var DEFAULT_SORT = [{ created_at: -1 }];
|
|
@@ -7795,6 +7926,7 @@ var Channel = class {
|
|
|
7795
7926
|
return msg && { timestampMs, msgId: msg.id };
|
|
7796
7927
|
}
|
|
7797
7928
|
});
|
|
7929
|
+
this.cooldownTimer = new CooldownTimer({ channel: this });
|
|
7798
7930
|
}
|
|
7799
7931
|
/**
|
|
7800
7932
|
* getClient - Get the chat client for this channel. If client.disconnect() was called, this function will error
|
|
@@ -8930,6 +9062,7 @@ var Channel = class {
|
|
|
8930
9062
|
].sort().join();
|
|
8931
9063
|
this.data = state.channel;
|
|
8932
9064
|
this.offlineMode = false;
|
|
9065
|
+
this.cooldownTimer.refresh();
|
|
8933
9066
|
if (areCapabilitiesChanged) {
|
|
8934
9067
|
this.getClient().dispatchEvent({
|
|
8935
9068
|
type: "capabilities.changed",
|
|
@@ -9000,11 +9133,13 @@ var Channel = class {
|
|
|
9000
9133
|
* unbanUser - Removes the bans for a user on a channel
|
|
9001
9134
|
*
|
|
9002
9135
|
* @param {string} targetUserID
|
|
9136
|
+
* @param {UnBanUserOptions} options
|
|
9003
9137
|
* @returns {Promise<APIResponse>}
|
|
9004
9138
|
*/
|
|
9005
|
-
async unbanUser(targetUserID) {
|
|
9139
|
+
async unbanUser(targetUserID, options) {
|
|
9006
9140
|
this._checkInitialized();
|
|
9007
9141
|
return await this.getClient().unbanUser(targetUserID, {
|
|
9142
|
+
...options,
|
|
9008
9143
|
type: this.type,
|
|
9009
9144
|
id: this.id
|
|
9010
9145
|
});
|
|
@@ -9309,6 +9444,9 @@ var Channel = class {
|
|
|
9309
9444
|
channelState.addPinnedMessage(event.message);
|
|
9310
9445
|
}
|
|
9311
9446
|
const preventUnreadCountUpdate = ownMessage || isThreadMessage;
|
|
9447
|
+
if (ownMessage) {
|
|
9448
|
+
this.cooldownTimer.refresh();
|
|
9449
|
+
}
|
|
9312
9450
|
if (preventUnreadCountUpdate) break;
|
|
9313
9451
|
if (event.user?.id) {
|
|
9314
9452
|
for (const userId in channelState.read) {
|
|
@@ -9443,6 +9581,7 @@ var Channel = class {
|
|
|
9443
9581
|
own_capabilities: event.channel?.own_capabilities ?? channel.data?.own_capabilities
|
|
9444
9582
|
};
|
|
9445
9583
|
channel.data = newChannelData;
|
|
9584
|
+
this.cooldownTimer.refresh();
|
|
9446
9585
|
}
|
|
9447
9586
|
break;
|
|
9448
9587
|
case "reaction.new":
|
|
@@ -9627,6 +9766,7 @@ var Channel = class {
|
|
|
9627
9766
|
}
|
|
9628
9767
|
);
|
|
9629
9768
|
this.disconnected = true;
|
|
9769
|
+
this.cooldownTimer.clearTimeout();
|
|
9630
9770
|
this.state.setIsUpToDate(false);
|
|
9631
9771
|
}
|
|
9632
9772
|
};
|
|
@@ -13590,6 +13730,20 @@ var StreamChat = class _StreamChat {
|
|
|
13590
13730
|
}
|
|
13591
13731
|
});
|
|
13592
13732
|
}
|
|
13733
|
+
/**
|
|
13734
|
+
* queryFutureChannelBans - Query future channel bans created by a user
|
|
13735
|
+
*
|
|
13736
|
+
* @param {QueryFutureChannelBansOptions} options Option object with user_id, exclude_expired_bans, limit, offset
|
|
13737
|
+
* @returns {Promise<FutureChannelBansResponse>} Future Channel Bans Response
|
|
13738
|
+
*/
|
|
13739
|
+
async queryFutureChannelBans(options = {}) {
|
|
13740
|
+
return await this.get(
|
|
13741
|
+
this.baseURL + "/query_future_channel_bans",
|
|
13742
|
+
{
|
|
13743
|
+
payload: options
|
|
13744
|
+
}
|
|
13745
|
+
);
|
|
13746
|
+
}
|
|
13593
13747
|
/**
|
|
13594
13748
|
* queryMessageFlags - Query message flags
|
|
13595
13749
|
*
|
|
@@ -13609,10 +13763,10 @@ var StreamChat = class _StreamChat {
|
|
|
13609
13763
|
/**
|
|
13610
13764
|
* queryChannelsRequest - Queries channels and returns the raw response
|
|
13611
13765
|
*
|
|
13612
|
-
* @param {ChannelFilters} filterConditions object MongoDB style filters
|
|
13766
|
+
* @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
|
|
13613
13767
|
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
13614
13768
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
13615
|
-
* @param {ChannelOptions} [options] Options object
|
|
13769
|
+
* @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
|
|
13616
13770
|
*
|
|
13617
13771
|
* @return {Promise<Array<ChannelAPIResponse>>} search channels response
|
|
13618
13772
|
*/
|
|
@@ -13626,11 +13780,18 @@ var StreamChat = class _StreamChat {
|
|
|
13626
13780
|
if (!this._hasConnectionID()) {
|
|
13627
13781
|
defaultOptions.watch = false;
|
|
13628
13782
|
}
|
|
13629
|
-
const
|
|
13783
|
+
const { predefined_filter, filter_values, sort_values, ...restOptions } = options;
|
|
13784
|
+
const payload = predefined_filter ? {
|
|
13785
|
+
predefined_filter,
|
|
13786
|
+
filter_values,
|
|
13787
|
+
sort_values,
|
|
13788
|
+
...defaultOptions,
|
|
13789
|
+
...restOptions
|
|
13790
|
+
} : {
|
|
13630
13791
|
filter_conditions: filterConditions,
|
|
13631
13792
|
sort: normalizeQuerySort(sort),
|
|
13632
13793
|
...defaultOptions,
|
|
13633
|
-
...
|
|
13794
|
+
...restOptions
|
|
13634
13795
|
};
|
|
13635
13796
|
const data = await this.post(
|
|
13636
13797
|
this.baseURL + "/channels",
|
|
@@ -13742,6 +13903,7 @@ var StreamChat = class _StreamChat {
|
|
|
13742
13903
|
this.reminders.hydrateState(channelState.messages);
|
|
13743
13904
|
}
|
|
13744
13905
|
c.messageComposer.initStateFromChannelResponse(channelState);
|
|
13906
|
+
c.cooldownTimer.refresh();
|
|
13745
13907
|
channels.push(c);
|
|
13746
13908
|
}
|
|
13747
13909
|
this.syncDeliveredCandidates(channels);
|
|
@@ -14737,7 +14899,7 @@ var StreamChat = class _StreamChat {
|
|
|
14737
14899
|
if (this.userAgent) {
|
|
14738
14900
|
return this.userAgent;
|
|
14739
14901
|
}
|
|
14740
|
-
const version = "9.
|
|
14902
|
+
const version = "9.30.0";
|
|
14741
14903
|
const clientBundle = "browser-esm";
|
|
14742
14904
|
let userAgentString = "";
|
|
14743
14905
|
if (this.sdkIdentifier) {
|
|
@@ -15053,7 +15215,7 @@ var StreamChat = class _StreamChat {
|
|
|
15053
15215
|
validateServerSideAuth() {
|
|
15054
15216
|
if (!this.secret) {
|
|
15055
15217
|
throw new Error(
|
|
15056
|
-
"
|
|
15218
|
+
"This feature can be used server-side only. Please initialize the client with a secret to use this feature."
|
|
15057
15219
|
);
|
|
15058
15220
|
}
|
|
15059
15221
|
}
|
|
@@ -15918,6 +16080,79 @@ var StreamChat = class _StreamChat {
|
|
|
15918
16080
|
payload
|
|
15919
16081
|
);
|
|
15920
16082
|
}
|
|
16083
|
+
/**
|
|
16084
|
+
* createPredefinedFilter - Creates a new predefined filter (server-side only)
|
|
16085
|
+
*
|
|
16086
|
+
* @param {CreatePredefinedFilterOptions} options Predefined filter options
|
|
16087
|
+
*
|
|
16088
|
+
* @return {Promise<PredefinedFilterResponse>} The created predefined filter
|
|
16089
|
+
*/
|
|
16090
|
+
async createPredefinedFilter(options) {
|
|
16091
|
+
this.validateServerSideAuth();
|
|
16092
|
+
return await this.post(
|
|
16093
|
+
`${this.baseURL}/predefined_filters`,
|
|
16094
|
+
options
|
|
16095
|
+
);
|
|
16096
|
+
}
|
|
16097
|
+
/**
|
|
16098
|
+
* getPredefinedFilter - Gets a predefined filter by name (server-side only)
|
|
16099
|
+
*
|
|
16100
|
+
* @param {string} name Predefined filter name
|
|
16101
|
+
*
|
|
16102
|
+
* @return {Promise<PredefinedFilterResponse>} The predefined filter
|
|
16103
|
+
*/
|
|
16104
|
+
async getPredefinedFilter(name) {
|
|
16105
|
+
this.validateServerSideAuth();
|
|
16106
|
+
return await this.get(
|
|
16107
|
+
`${this.baseURL}/predefined_filters/${encodeURIComponent(name)}`
|
|
16108
|
+
);
|
|
16109
|
+
}
|
|
16110
|
+
/**
|
|
16111
|
+
* updatePredefinedFilter - Updates a predefined filter (server-side only)
|
|
16112
|
+
*
|
|
16113
|
+
* @param {string} name Predefined filter name
|
|
16114
|
+
* @param {UpdatePredefinedFilterOptions} options Predefined filter options
|
|
16115
|
+
*
|
|
16116
|
+
* @return {Promise<PredefinedFilterResponse>} The updated predefined filter
|
|
16117
|
+
*/
|
|
16118
|
+
async updatePredefinedFilter(name, options) {
|
|
16119
|
+
this.validateServerSideAuth();
|
|
16120
|
+
return await this.put(
|
|
16121
|
+
`${this.baseURL}/predefined_filters/${encodeURIComponent(name)}`,
|
|
16122
|
+
options
|
|
16123
|
+
);
|
|
16124
|
+
}
|
|
16125
|
+
/**
|
|
16126
|
+
* deletePredefinedFilter - Deletes a predefined filter (server-side only)
|
|
16127
|
+
*
|
|
16128
|
+
* @param {string} name Predefined filter name
|
|
16129
|
+
*
|
|
16130
|
+
* @return {Promise<APIResponse>} The server response
|
|
16131
|
+
*/
|
|
16132
|
+
async deletePredefinedFilter(name) {
|
|
16133
|
+
this.validateServerSideAuth();
|
|
16134
|
+
return await this.delete(
|
|
16135
|
+
`${this.baseURL}/predefined_filters/${encodeURIComponent(name)}`
|
|
16136
|
+
);
|
|
16137
|
+
}
|
|
16138
|
+
/**
|
|
16139
|
+
* listPredefinedFilters - Lists all predefined filters (server-side only)
|
|
16140
|
+
*
|
|
16141
|
+
* @param {ListPredefinedFiltersOptions} options Query options
|
|
16142
|
+
*
|
|
16143
|
+
* @return {Promise<ListPredefinedFiltersResponse>} The list of predefined filters
|
|
16144
|
+
*/
|
|
16145
|
+
async listPredefinedFilters(options = {}) {
|
|
16146
|
+
this.validateServerSideAuth();
|
|
16147
|
+
const { sort, ...paginationOptions } = options;
|
|
16148
|
+
return await this.get(
|
|
16149
|
+
`${this.baseURL}/predefined_filters`,
|
|
16150
|
+
{
|
|
16151
|
+
...paginationOptions,
|
|
16152
|
+
...sort ? { sort: JSON.stringify(sort) } : {}
|
|
16153
|
+
}
|
|
16154
|
+
);
|
|
16155
|
+
}
|
|
15921
16156
|
};
|
|
15922
16157
|
|
|
15923
16158
|
// src/events.ts
|