stream-chat 9.43.1 → 9.44.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/README.md +1 -1
- package/dist/cjs/index.browser.js +156 -7
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +166 -8
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +156 -7
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/client.d.ts +36 -4
- package/dist/types/messageComposer/middleware/textComposer/index.d.ts +1 -0
- package/dist/types/signing.d.ts +99 -5
- package/dist/types/types.d.ts +121 -15
- package/package.json +2 -1
- package/src/channel.ts +3 -1
- package/src/client.ts +78 -11
- package/src/messageComposer/messageComposer.ts +2 -0
- package/src/messageComposer/middleware/textComposer/index.ts +1 -0
- package/src/signing.ts +195 -7
- package/src/types.ts +133 -15
- package/src/utils.ts +1 -1
package/dist/types/client.d.ts
CHANGED
|
@@ -1246,6 +1246,38 @@ export declare class StreamChat {
|
|
|
1246
1246
|
* @returns {boolean}
|
|
1247
1247
|
*/
|
|
1248
1248
|
verifyWebhook(requestBody: string | Buffer, xSignature: string): boolean;
|
|
1249
|
+
/**
|
|
1250
|
+
* Verify and parse an HTTP webhook event.
|
|
1251
|
+
*
|
|
1252
|
+
* Decompresses `rawBody` when gzipped (detected from the body bytes),
|
|
1253
|
+
* verifies the `X-Signature` header against the app's API secret, and
|
|
1254
|
+
* returns the parsed `Event`. Works whether or not Stream is currently
|
|
1255
|
+
* compressing payloads for this app, and stays correct behind
|
|
1256
|
+
* middleware that auto-decompresses the request.
|
|
1257
|
+
*
|
|
1258
|
+
* @param rawBody Raw HTTP request body bytes Stream signed
|
|
1259
|
+
* @param signature Value of the `X-Signature` header
|
|
1260
|
+
* @throws {InvalidWebhookError} When the signature does not match or
|
|
1261
|
+
* the gzip envelope is malformed.
|
|
1262
|
+
*/
|
|
1263
|
+
verifyAndParseWebhook(rawBody: string | Buffer, signature: string): Event;
|
|
1264
|
+
/**
|
|
1265
|
+
* Parse an SQS firehose event: decodes the message `Body` (base64 +
|
|
1266
|
+
* optional gzip) and returns the parsed `Event`. No HMAC verification
|
|
1267
|
+
* (Stream does not sign SQS bodies).
|
|
1268
|
+
*
|
|
1269
|
+
* @param messageBody SQS message `Body` string
|
|
1270
|
+
* @throws {InvalidWebhookError} When the base64 / gzip envelope is malformed.
|
|
1271
|
+
*/
|
|
1272
|
+
parseSqs(messageBody: string): Event;
|
|
1273
|
+
/**
|
|
1274
|
+
* Parse an SNS-delivered event (unwraps envelope JSON when needed, then
|
|
1275
|
+
* same decode path as SQS). No HMAC verification.
|
|
1276
|
+
*
|
|
1277
|
+
* @param notificationBody Raw SNS POST body or pre-extracted `Message` string
|
|
1278
|
+
* @throws {InvalidWebhookError} When the envelope cannot be decoded.
|
|
1279
|
+
*/
|
|
1280
|
+
parseSns(notificationBody: string): Event;
|
|
1249
1281
|
/** getPermission - gets the definition for a permission
|
|
1250
1282
|
*
|
|
1251
1283
|
* @param {string} name
|
|
@@ -2039,7 +2071,7 @@ export declare class StreamChat {
|
|
|
2039
2071
|
*
|
|
2040
2072
|
* @return {Promise<PredefinedFilterResponse>} The created predefined filter
|
|
2041
2073
|
*/
|
|
2042
|
-
createPredefinedFilter(options: CreatePredefinedFilterOptions): Promise<PredefinedFilterResponse
|
|
2074
|
+
createPredefinedFilter<F extends Record<string, unknown> = Record<string, unknown>>(options: CreatePredefinedFilterOptions<F>): Promise<PredefinedFilterResponse<F>>;
|
|
2043
2075
|
/**
|
|
2044
2076
|
* getPredefinedFilter - Gets a predefined filter by name (server-side only)
|
|
2045
2077
|
*
|
|
@@ -2047,7 +2079,7 @@ export declare class StreamChat {
|
|
|
2047
2079
|
*
|
|
2048
2080
|
* @return {Promise<PredefinedFilterResponse>} The predefined filter
|
|
2049
2081
|
*/
|
|
2050
|
-
getPredefinedFilter(name: string): Promise<PredefinedFilterResponse
|
|
2082
|
+
getPredefinedFilter<F extends Record<string, unknown> = Record<string, unknown>>(name: string): Promise<PredefinedFilterResponse<F>>;
|
|
2051
2083
|
/**
|
|
2052
2084
|
* updatePredefinedFilter - Updates a predefined filter (server-side only)
|
|
2053
2085
|
*
|
|
@@ -2056,7 +2088,7 @@ export declare class StreamChat {
|
|
|
2056
2088
|
*
|
|
2057
2089
|
* @return {Promise<PredefinedFilterResponse>} The updated predefined filter
|
|
2058
2090
|
*/
|
|
2059
|
-
updatePredefinedFilter(name: string, options: UpdatePredefinedFilterOptions): Promise<PredefinedFilterResponse
|
|
2091
|
+
updatePredefinedFilter<F extends Record<string, unknown> = Record<string, unknown>>(name: string, options: UpdatePredefinedFilterOptions<F>): Promise<PredefinedFilterResponse<F>>;
|
|
2060
2092
|
/**
|
|
2061
2093
|
* deletePredefinedFilter - Deletes a predefined filter (server-side only)
|
|
2062
2094
|
*
|
|
@@ -2072,7 +2104,7 @@ export declare class StreamChat {
|
|
|
2072
2104
|
*
|
|
2073
2105
|
* @return {Promise<ListPredefinedFiltersResponse>} The list of predefined filters
|
|
2074
2106
|
*/
|
|
2075
|
-
listPredefinedFilters(options?: ListPredefinedFiltersOptions): Promise<ListPredefinedFiltersResponse
|
|
2107
|
+
listPredefinedFilters<F extends Record<string, unknown> = Record<string, unknown>>(options?: ListPredefinedFiltersOptions): Promise<ListPredefinedFiltersResponse<F>>;
|
|
2076
2108
|
/**
|
|
2077
2109
|
* setRetentionPolicy - Creates or updates a retention policy for the app.
|
|
2078
2110
|
* Server-side only.
|
|
@@ -2,6 +2,7 @@ export * from './activeCommandGuard';
|
|
|
2
2
|
export * from './commands';
|
|
3
3
|
export * from './commandEffects';
|
|
4
4
|
export * from './commandStringExtraction';
|
|
5
|
+
export * from './commandUtils';
|
|
5
6
|
export * from './mentions';
|
|
6
7
|
export * from './validation';
|
|
7
8
|
export * from './TextComposerMiddlewareExecutor';
|
package/dist/types/signing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import jwt from 'jsonwebtoken';
|
|
2
|
-
import type { UR } from './types';
|
|
2
|
+
import type { Event, UR } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Creates the JWT token that can be used for a UserSession
|
|
5
5
|
* @method JWTUserToken
|
|
@@ -21,10 +21,104 @@ export declare function UserFromToken(token: string): string;
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function DevToken(userId: string): string;
|
|
23
23
|
/**
|
|
24
|
+
* Constant-time HMAC-SHA256 verification of `signature` against the
|
|
25
|
+
* digest of `body` using `secret` as the key. The signature is always
|
|
26
|
+
* computed over the **uncompressed** JSON bytes, so callers that
|
|
27
|
+
* decoded a gzipped or base64-wrapped payload must pass the inflated
|
|
28
|
+
* bytes here.
|
|
24
29
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
30
|
+
* The legacy `client.verifyWebhook` helper wraps this function, so
|
|
31
|
+
* callers that have already migrated to `verifyAndParseWebhook`,
|
|
32
|
+
* `parseSqs`, or `parseSns` rarely need to invoke this
|
|
33
|
+
* directly.
|
|
34
|
+
*/
|
|
35
|
+
export declare function verifySignature(body: string | Buffer, signature: string, secret: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated Use {@link verifySignature} - same logic, parameters
|
|
38
|
+
* reordered to match the cross-SDK contract
|
|
39
|
+
* (`verifySignature(body, signature, secret)`).
|
|
29
40
|
*/
|
|
30
41
|
export declare function CheckSignature(body: string | Buffer, secret: string, signature: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Canonical failure-mode messages for {@link InvalidWebhookError}.
|
|
44
|
+
*
|
|
45
|
+
* Customers that prefer exact-match filtering (security logging, retry
|
|
46
|
+
* policy) over substring matches can compare `err.message` to these
|
|
47
|
+
* constants instead of pattern-matching free-form text.
|
|
48
|
+
*/
|
|
49
|
+
export declare const InvalidWebhookErrorMessages: {
|
|
50
|
+
readonly signatureMismatch: "signature mismatch";
|
|
51
|
+
readonly invalidBase64: "invalid base64 encoding";
|
|
52
|
+
readonly gzipFailed: "gzip decompression failed";
|
|
53
|
+
readonly invalidJson: "invalid JSON payload";
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Thrown by {@link verifyAndParseWebhook} when the supplied `x-signature` does not
|
|
57
|
+
* match the HMAC of the uncompressed payload, and by all webhook helpers (including
|
|
58
|
+
* {@link parseSqs} / {@link parseSns}) when a gzip / base64 / JSON envelope is malformed.
|
|
59
|
+
*
|
|
60
|
+
* The message identifies which failure mode fired. See
|
|
61
|
+
* {@link InvalidWebhookErrorMessages} for the canonical strings.
|
|
62
|
+
*/
|
|
63
|
+
export declare class InvalidWebhookError extends Error {
|
|
64
|
+
name: string;
|
|
65
|
+
constructor(message?: string);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns `body` as a `Buffer`, gzip-decompressed when its first two
|
|
69
|
+
* bytes match the gzip magic (`1f 8b`, per RFC 1952). When the body is
|
|
70
|
+
* plain JSON (no compression, or middleware already decompressed), the
|
|
71
|
+
* bytes are returned unchanged.
|
|
72
|
+
*
|
|
73
|
+
* Magic-byte detection (rather than relying on a header) keeps the
|
|
74
|
+
* same handler correct when middleware - Express, Next.js, AWS Lambda
|
|
75
|
+
* - auto-decompresses the request before your code sees it.
|
|
76
|
+
*/
|
|
77
|
+
export declare function gunzipPayload(rawBody: string | Buffer): Buffer;
|
|
78
|
+
/**
|
|
79
|
+
* Reverses the SQS firehose envelope: the message `Body` is
|
|
80
|
+
* base64-decoded, then the result is gzip-decompressed when it begins
|
|
81
|
+
* with the gzip magic. Returns the raw JSON `Buffer` Stream signed.
|
|
82
|
+
*
|
|
83
|
+
* SQS bodies are always base64-encoded so they remain valid UTF-8 over
|
|
84
|
+
* the queue. The same call works whether or not Stream is currently
|
|
85
|
+
* compressing payloads for this app.
|
|
86
|
+
*/
|
|
87
|
+
export declare function decodeSqsPayload(body: string): Buffer;
|
|
88
|
+
/**
|
|
89
|
+
* Reverses an SNS HTTP notification envelope. When `notificationBody`
|
|
90
|
+
* is a JSON envelope (`{"Type":"Notification","Message":"..."}`), the
|
|
91
|
+
* inner `Message` field is extracted and run through the SQS pipeline
|
|
92
|
+
* (base64-decode, then gzip-if-magic). When the input is not a JSON
|
|
93
|
+
* envelope it is treated as the already-extracted `Message` string,
|
|
94
|
+
* so call sites that pre-unwrap continue to work.
|
|
95
|
+
*/
|
|
96
|
+
export declare function decodeSnsPayload(notificationBody: string): Buffer;
|
|
97
|
+
/**
|
|
98
|
+
* Parse a JSON-encoded webhook event into a typed {@link Event}. New
|
|
99
|
+
* event types Stream introduces still parse successfully - the runtime
|
|
100
|
+
* shape is the JSON Stream sent and the `type` field stays preserved.
|
|
101
|
+
*/
|
|
102
|
+
export declare function parseEvent(payload: Buffer | string): Event;
|
|
103
|
+
/**
|
|
104
|
+
* Decompress (when gzipped), verify the HMAC `signature`, and return
|
|
105
|
+
* the parsed {@link Event}.
|
|
106
|
+
*
|
|
107
|
+
* @param rawBody Raw HTTP request body bytes Stream signed
|
|
108
|
+
* @param signature Value of the `X-Signature` header
|
|
109
|
+
* @param secret Your app's API secret
|
|
110
|
+
* @throws {InvalidWebhookError} When the signature does not match or
|
|
111
|
+
* the gzip envelope is malformed.
|
|
112
|
+
*/
|
|
113
|
+
export declare function verifyAndParseWebhook(rawBody: string | Buffer, signature: string, secret: string): Event;
|
|
114
|
+
/**
|
|
115
|
+
* Decode the SQS message `Body` (base64, then gzip-if-magic) and return
|
|
116
|
+
* the parsed {@link Event}. Stream does not attach an application-level HMAC
|
|
117
|
+
* to SQS deliveries — use {@link verifyAndParseWebhook} for HTTP webhooks.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseSqs(messageBody: string): Event;
|
|
120
|
+
/**
|
|
121
|
+
* Decode an SNS notification (unwrap the JSON envelope when needed; same
|
|
122
|
+
* inner format as SQS). No application-level HMAC verification.
|
|
123
|
+
*/
|
|
124
|
+
export declare function parseSns(notificationBody: string): Event;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -900,13 +900,29 @@ export type ChannelOptions = {
|
|
|
900
900
|
user_id?: string;
|
|
901
901
|
watch?: boolean;
|
|
902
902
|
/**
|
|
903
|
-
* Name of a predefined filter to use instead of
|
|
904
|
-
*
|
|
903
|
+
* Name of a predefined filter to use instead of sending raw
|
|
904
|
+
* `filter_conditions`.
|
|
905
|
+
*
|
|
906
|
+
* The backend resolves the filter template by name and interpolates it using
|
|
907
|
+
* `filter_values`.
|
|
908
|
+
*
|
|
909
|
+
* A regular `sort` can still be passed to `queryChannels()`, but backend
|
|
910
|
+
* precedence rules apply:
|
|
911
|
+
*
|
|
912
|
+
* - if the predefined filter has its own stored sort template, that stored
|
|
913
|
+
* sort takes precedence and the request `sort` is ignored
|
|
914
|
+
* - if the predefined filter does not define a sort template, the request
|
|
915
|
+
* `sort` can still be used
|
|
905
916
|
*/
|
|
906
917
|
predefined_filter?: string;
|
|
907
918
|
/**
|
|
908
|
-
* Values to interpolate
|
|
909
|
-
*
|
|
919
|
+
* Values used to interpolate placeholders inside the predefined filter's
|
|
920
|
+
* `filter` template.
|
|
921
|
+
*
|
|
922
|
+
* Example: a template value like `{{user_id}}` can be resolved with
|
|
923
|
+
* `{ user_id: 'alice' }`.
|
|
924
|
+
*
|
|
925
|
+
* Only used when `predefined_filter` is provided.
|
|
910
926
|
*/
|
|
911
927
|
filter_values?: Record<string, unknown>;
|
|
912
928
|
/**
|
|
@@ -3510,33 +3526,114 @@ export type UpdateChannelsBatchResponse = {
|
|
|
3510
3526
|
*/
|
|
3511
3527
|
export type PredefinedFilterOperation = 'QueryChannels';
|
|
3512
3528
|
export type PredefinedFilterSortParam = {
|
|
3529
|
+
/**
|
|
3530
|
+
* Field name to sort by.
|
|
3531
|
+
*
|
|
3532
|
+
* This may be a literal field name such as `created_at`, or a placeholder
|
|
3533
|
+
* template such as `{{sort_field}}` that will be interpolated server-side.
|
|
3534
|
+
*/
|
|
3513
3535
|
field: string;
|
|
3536
|
+
/**
|
|
3537
|
+
* Sort direction. `1` means ascending and `-1` means descending.
|
|
3538
|
+
*
|
|
3539
|
+
* The backend defaults this to `1` when omitted.
|
|
3540
|
+
*/
|
|
3514
3541
|
direction?: AscDesc;
|
|
3542
|
+
/**
|
|
3543
|
+
* Optional server-side hint describing how the sort field value should be
|
|
3544
|
+
* interpreted.
|
|
3545
|
+
*
|
|
3546
|
+
* This is mainly relevant for predefined-filter sort templates and is not
|
|
3547
|
+
* part of the regular `queryChannels()` sort shape. Omitting it uses the
|
|
3548
|
+
* backend default string behavior. Known backend values include:
|
|
3549
|
+
*
|
|
3550
|
+
* - `number`: cast custom-field values to numeric before sorting
|
|
3551
|
+
* - `boolean`: cast custom-field values to boolean before sorting
|
|
3552
|
+
*
|
|
3553
|
+
* Other values are backend-defined. In most cases this should be omitted
|
|
3554
|
+
* unless you are sorting by a custom field whose stored JSON value is not
|
|
3555
|
+
* string-like.
|
|
3556
|
+
*/
|
|
3515
3557
|
type?: string;
|
|
3516
3558
|
};
|
|
3517
|
-
|
|
3559
|
+
/**
|
|
3560
|
+
* Stored predefined filter definition as returned by the server.
|
|
3561
|
+
*
|
|
3562
|
+
* `F` represents the raw filter template shape. It defaults to a generic record
|
|
3563
|
+
* because predefined filters are server-managed templates and may include
|
|
3564
|
+
* placeholders or app-specific structures.
|
|
3565
|
+
*/
|
|
3566
|
+
export type PredefinedFilter<F extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3567
|
+
/**
|
|
3568
|
+
* Unique predefined filter name within the app.
|
|
3569
|
+
*/
|
|
3518
3570
|
name: string;
|
|
3571
|
+
/**
|
|
3572
|
+
* Operation this predefined filter is valid for.
|
|
3573
|
+
*/
|
|
3519
3574
|
operation: PredefinedFilterOperation;
|
|
3520
|
-
|
|
3575
|
+
/**
|
|
3576
|
+
* Filter template stored on the server.
|
|
3577
|
+
*
|
|
3578
|
+
* This is not necessarily the fully interpolated runtime filter; placeholder
|
|
3579
|
+
* values such as `{{user_id}}` may still be present.
|
|
3580
|
+
*/
|
|
3581
|
+
filter: F;
|
|
3582
|
+
/**
|
|
3583
|
+
* Server creation timestamp in ISO-8601 format.
|
|
3584
|
+
*/
|
|
3521
3585
|
created_at: string;
|
|
3586
|
+
/**
|
|
3587
|
+
* Server update timestamp in ISO-8601 format.
|
|
3588
|
+
*/
|
|
3522
3589
|
updated_at: string;
|
|
3590
|
+
/**
|
|
3591
|
+
* Optional human-readable description.
|
|
3592
|
+
*/
|
|
3523
3593
|
description?: string;
|
|
3594
|
+
/**
|
|
3595
|
+
* Optional sort template stored with the predefined filter.
|
|
3596
|
+
*/
|
|
3524
3597
|
sort?: PredefinedFilterSortParam[];
|
|
3598
|
+
/**
|
|
3599
|
+
* Query identifier generated by the backend for the filter/sort pattern.
|
|
3600
|
+
*
|
|
3601
|
+
* The exact value is backend-generated and primarily useful for correlating
|
|
3602
|
+
* predefined filters with query analysis / query performance data.
|
|
3603
|
+
*/
|
|
3525
3604
|
query_id?: number;
|
|
3526
3605
|
};
|
|
3527
|
-
export type CreatePredefinedFilterOptions = {
|
|
3606
|
+
export type CreatePredefinedFilterOptions<F extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3607
|
+
/**
|
|
3608
|
+
* Unique predefined filter name.
|
|
3609
|
+
*/
|
|
3528
3610
|
name: string;
|
|
3611
|
+
/**
|
|
3612
|
+
* Operation this predefined filter will be used with.
|
|
3613
|
+
*/
|
|
3529
3614
|
operation: PredefinedFilterOperation;
|
|
3530
|
-
|
|
3615
|
+
/**
|
|
3616
|
+
* Filter template to store on the server.
|
|
3617
|
+
*/
|
|
3618
|
+
filter: F;
|
|
3619
|
+
/**
|
|
3620
|
+
* Optional human-readable description.
|
|
3621
|
+
*/
|
|
3531
3622
|
description?: string;
|
|
3623
|
+
/**
|
|
3624
|
+
* Optional sort template stored with the predefined filter.
|
|
3625
|
+
*/
|
|
3532
3626
|
sort?: PredefinedFilterSortParam[];
|
|
3533
3627
|
};
|
|
3534
|
-
export type UpdatePredefinedFilterOptions = Omit<CreatePredefinedFilterOptions
|
|
3535
|
-
export type PredefinedFilterResponse = APIResponse & {
|
|
3536
|
-
predefined_filter: PredefinedFilter
|
|
3628
|
+
export type UpdatePredefinedFilterOptions<F extends Record<string, unknown> = Record<string, unknown>> = Omit<CreatePredefinedFilterOptions<F>, 'name'>;
|
|
3629
|
+
export type PredefinedFilterResponse<F extends Record<string, unknown> = Record<string, unknown>> = APIResponse & {
|
|
3630
|
+
predefined_filter: PredefinedFilter<F>;
|
|
3537
3631
|
};
|
|
3538
|
-
|
|
3539
|
-
|
|
3632
|
+
/**
|
|
3633
|
+
* Paginated response returned when listing predefined filters.
|
|
3634
|
+
*/
|
|
3635
|
+
export type ListPredefinedFiltersResponse<F extends Record<string, unknown> = Record<string, unknown>> = APIResponse & {
|
|
3636
|
+
predefined_filters: PredefinedFilter<F>[];
|
|
3540
3637
|
next?: string;
|
|
3541
3638
|
prev?: string;
|
|
3542
3639
|
};
|
|
@@ -3544,9 +3641,18 @@ export type ListPredefinedFiltersResponse = APIResponse & {
|
|
|
3544
3641
|
* Contains the interpolated filter and sort from a predefined filter.
|
|
3545
3642
|
* This is returned in the QueryChannels response when using a predefined filter.
|
|
3546
3643
|
*/
|
|
3547
|
-
export type ParsedPredefinedFilterResponse = {
|
|
3644
|
+
export type ParsedPredefinedFilterResponse<F extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3645
|
+
/**
|
|
3646
|
+
* Name of the predefined filter that was resolved.
|
|
3647
|
+
*/
|
|
3548
3648
|
name: string;
|
|
3549
|
-
|
|
3649
|
+
/**
|
|
3650
|
+
* Fully interpolated filter that the backend executed.
|
|
3651
|
+
*/
|
|
3652
|
+
filter: F;
|
|
3653
|
+
/**
|
|
3654
|
+
* Fully interpolated sort parameters resolved from the predefined filter.
|
|
3655
|
+
*/
|
|
3550
3656
|
sort?: PredefinedFilterSortParam[];
|
|
3551
3657
|
};
|
|
3552
3658
|
export type PredefinedFilterSort = SortParam[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stream-chat",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.44.0",
|
|
4
4
|
"description": "JS SDK for the Stream Chat API",
|
|
5
5
|
"homepage": "https://getstream.io/chat/",
|
|
6
6
|
"author": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"browser": {
|
|
32
32
|
"https": false,
|
|
33
33
|
"crypto": false,
|
|
34
|
+
"zlib": false,
|
|
34
35
|
"jsonwebtoken": false,
|
|
35
36
|
"ws": false
|
|
36
37
|
},
|
package/src/channel.ts
CHANGED
|
@@ -1438,7 +1438,9 @@ export class Channel {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
|
|
1440
1440
|
// FIXME: see #1265, adjust and count new messages even when the channel is muted
|
|
1441
|
-
|
|
1441
|
+
// Read mute state directly from the client to avoid _checkInitialized() — this method
|
|
1442
|
+
// is invoked from _handleChannelEvent (e.g. message.new) before .watch() resolves.
|
|
1443
|
+
if (this.getClient()._muteStatus(this.cid).muted) return false;
|
|
1442
1444
|
|
|
1443
1445
|
return true;
|
|
1444
1446
|
}
|
package/src/client.ts
CHANGED
|
@@ -9,7 +9,15 @@ import { Channel } from './channel';
|
|
|
9
9
|
import { ClientState } from './client_state';
|
|
10
10
|
import { StableWSConnection } from './connection';
|
|
11
11
|
import { UploadManager } from './uploadManager';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DevToken,
|
|
14
|
+
InvalidWebhookError,
|
|
15
|
+
JWTUserToken,
|
|
16
|
+
parseSns as parseSnsHelper,
|
|
17
|
+
parseSqs as parseSqsHelper,
|
|
18
|
+
verifyAndParseWebhook as verifyAndParseWebhookHelper,
|
|
19
|
+
verifySignature,
|
|
20
|
+
} from './signing';
|
|
13
21
|
import { TokenManager } from './token_manager';
|
|
14
22
|
import { WSConnectionFallback } from './connection_fallback';
|
|
15
23
|
import { Campaign } from './campaign';
|
|
@@ -1907,6 +1915,7 @@ export class StreamChat {
|
|
|
1907
1915
|
}
|
|
1908
1916
|
|
|
1909
1917
|
const { predefined_filter, filter_values, sort_values, ...restOptions } = options;
|
|
1918
|
+
const normalizedSort = normalizeQuerySort(sort);
|
|
1910
1919
|
|
|
1911
1920
|
// Build payload based on whether we're using a predefined filter or traditional filters
|
|
1912
1921
|
const payload = predefined_filter
|
|
@@ -1914,12 +1923,13 @@ export class StreamChat {
|
|
|
1914
1923
|
predefined_filter,
|
|
1915
1924
|
filter_values,
|
|
1916
1925
|
sort_values,
|
|
1926
|
+
sort: normalizedSort,
|
|
1917
1927
|
...defaultOptions,
|
|
1918
1928
|
...restOptions,
|
|
1919
1929
|
}
|
|
1920
1930
|
: {
|
|
1921
1931
|
filter_conditions: filterConditions,
|
|
1922
|
-
sort:
|
|
1932
|
+
sort: normalizedSort,
|
|
1923
1933
|
...defaultOptions,
|
|
1924
1934
|
...restOptions,
|
|
1925
1935
|
};
|
|
@@ -1929,6 +1939,9 @@ export class StreamChat {
|
|
|
1929
1939
|
payload,
|
|
1930
1940
|
);
|
|
1931
1941
|
|
|
1942
|
+
// FIXME: In the next major release, return the full QueryChannelsAPIResponse
|
|
1943
|
+
// instead of only `data.channels` so top-level metadata such as
|
|
1944
|
+
// `predefined_filter` is not lost.
|
|
1932
1945
|
return data.channels;
|
|
1933
1946
|
}
|
|
1934
1947
|
|
|
@@ -3634,7 +3647,53 @@ export class StreamChat {
|
|
|
3634
3647
|
* @returns {boolean}
|
|
3635
3648
|
*/
|
|
3636
3649
|
verifyWebhook(requestBody: string | Buffer, xSignature: string) {
|
|
3637
|
-
return !!this.secret &&
|
|
3650
|
+
return !!this.secret && verifySignature(requestBody, xSignature, this.secret);
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
/**
|
|
3654
|
+
* Verify and parse an HTTP webhook event.
|
|
3655
|
+
*
|
|
3656
|
+
* Decompresses `rawBody` when gzipped (detected from the body bytes),
|
|
3657
|
+
* verifies the `X-Signature` header against the app's API secret, and
|
|
3658
|
+
* returns the parsed `Event`. Works whether or not Stream is currently
|
|
3659
|
+
* compressing payloads for this app, and stays correct behind
|
|
3660
|
+
* middleware that auto-decompresses the request.
|
|
3661
|
+
*
|
|
3662
|
+
* @param rawBody Raw HTTP request body bytes Stream signed
|
|
3663
|
+
* @param signature Value of the `X-Signature` header
|
|
3664
|
+
* @throws {InvalidWebhookError} When the signature does not match or
|
|
3665
|
+
* the gzip envelope is malformed.
|
|
3666
|
+
*/
|
|
3667
|
+
verifyAndParseWebhook(rawBody: string | Buffer, signature: string) {
|
|
3668
|
+
if (!this.secret) {
|
|
3669
|
+
throw new InvalidWebhookError(
|
|
3670
|
+
'cannot verify webhook signature without an API secret on the client',
|
|
3671
|
+
);
|
|
3672
|
+
}
|
|
3673
|
+
return verifyAndParseWebhookHelper(rawBody, signature, this.secret);
|
|
3674
|
+
}
|
|
3675
|
+
|
|
3676
|
+
/**
|
|
3677
|
+
* Parse an SQS firehose event: decodes the message `Body` (base64 +
|
|
3678
|
+
* optional gzip) and returns the parsed `Event`. No HMAC verification
|
|
3679
|
+
* (Stream does not sign SQS bodies).
|
|
3680
|
+
*
|
|
3681
|
+
* @param messageBody SQS message `Body` string
|
|
3682
|
+
* @throws {InvalidWebhookError} When the base64 / gzip envelope is malformed.
|
|
3683
|
+
*/
|
|
3684
|
+
parseSqs(messageBody: string) {
|
|
3685
|
+
return parseSqsHelper(messageBody);
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
/**
|
|
3689
|
+
* Parse an SNS-delivered event (unwraps envelope JSON when needed, then
|
|
3690
|
+
* same decode path as SQS). No HMAC verification.
|
|
3691
|
+
*
|
|
3692
|
+
* @param notificationBody Raw SNS POST body or pre-extracted `Message` string
|
|
3693
|
+
* @throws {InvalidWebhookError} When the envelope cannot be decoded.
|
|
3694
|
+
*/
|
|
3695
|
+
parseSns(notificationBody: string) {
|
|
3696
|
+
return parseSnsHelper(notificationBody);
|
|
3638
3697
|
}
|
|
3639
3698
|
|
|
3640
3699
|
/** getPermission - gets the definition for a permission
|
|
@@ -4981,9 +5040,11 @@ export class StreamChat {
|
|
|
4981
5040
|
*
|
|
4982
5041
|
* @return {Promise<PredefinedFilterResponse>} The created predefined filter
|
|
4983
5042
|
*/
|
|
4984
|
-
async createPredefinedFilter
|
|
5043
|
+
async createPredefinedFilter<
|
|
5044
|
+
F extends Record<string, unknown> = Record<string, unknown>,
|
|
5045
|
+
>(options: CreatePredefinedFilterOptions<F>) {
|
|
4985
5046
|
this.validateServerSideAuth();
|
|
4986
|
-
return await this.post<PredefinedFilterResponse
|
|
5047
|
+
return await this.post<PredefinedFilterResponse<F>>(
|
|
4987
5048
|
`${this.baseURL}/predefined_filters`,
|
|
4988
5049
|
options,
|
|
4989
5050
|
);
|
|
@@ -4996,9 +5057,11 @@ export class StreamChat {
|
|
|
4996
5057
|
*
|
|
4997
5058
|
* @return {Promise<PredefinedFilterResponse>} The predefined filter
|
|
4998
5059
|
*/
|
|
4999
|
-
async getPredefinedFilter
|
|
5060
|
+
async getPredefinedFilter<F extends Record<string, unknown> = Record<string, unknown>>(
|
|
5061
|
+
name: string,
|
|
5062
|
+
) {
|
|
5000
5063
|
this.validateServerSideAuth();
|
|
5001
|
-
return await this.get<PredefinedFilterResponse
|
|
5064
|
+
return await this.get<PredefinedFilterResponse<F>>(
|
|
5002
5065
|
`${this.baseURL}/predefined_filters/${encodeURIComponent(name)}`,
|
|
5003
5066
|
);
|
|
5004
5067
|
}
|
|
@@ -5011,9 +5074,11 @@ export class StreamChat {
|
|
|
5011
5074
|
*
|
|
5012
5075
|
* @return {Promise<PredefinedFilterResponse>} The updated predefined filter
|
|
5013
5076
|
*/
|
|
5014
|
-
async updatePredefinedFilter
|
|
5077
|
+
async updatePredefinedFilter<
|
|
5078
|
+
F extends Record<string, unknown> = Record<string, unknown>,
|
|
5079
|
+
>(name: string, options: UpdatePredefinedFilterOptions<F>) {
|
|
5015
5080
|
this.validateServerSideAuth();
|
|
5016
|
-
return await this.put<PredefinedFilterResponse
|
|
5081
|
+
return await this.put<PredefinedFilterResponse<F>>(
|
|
5017
5082
|
`${this.baseURL}/predefined_filters/${encodeURIComponent(name)}`,
|
|
5018
5083
|
options,
|
|
5019
5084
|
);
|
|
@@ -5040,10 +5105,12 @@ export class StreamChat {
|
|
|
5040
5105
|
*
|
|
5041
5106
|
* @return {Promise<ListPredefinedFiltersResponse>} The list of predefined filters
|
|
5042
5107
|
*/
|
|
5043
|
-
async listPredefinedFilters
|
|
5108
|
+
async listPredefinedFilters<
|
|
5109
|
+
F extends Record<string, unknown> = Record<string, unknown>,
|
|
5110
|
+
>(options: ListPredefinedFiltersOptions = {}) {
|
|
5044
5111
|
this.validateServerSideAuth();
|
|
5045
5112
|
const { sort, ...paginationOptions } = options;
|
|
5046
|
-
return await this.get<ListPredefinedFiltersResponse
|
|
5113
|
+
return await this.get<ListPredefinedFiltersResponse<F>>(
|
|
5047
5114
|
`${this.baseURL}/predefined_filters`,
|
|
5048
5115
|
{
|
|
5049
5116
|
...paginationOptions,
|
|
@@ -624,6 +624,7 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
624
624
|
draft.channel_cid !== this.channel.cid
|
|
625
625
|
)
|
|
626
626
|
return;
|
|
627
|
+
if (this.editedMessage) return;
|
|
627
628
|
this.initState({ composition: draft });
|
|
628
629
|
}).unsubscribe;
|
|
629
630
|
|
|
@@ -637,6 +638,7 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
637
638
|
) {
|
|
638
639
|
return;
|
|
639
640
|
}
|
|
641
|
+
if (this.editedMessage) return;
|
|
640
642
|
|
|
641
643
|
this.logDraftUpdateTimestamp();
|
|
642
644
|
|
|
@@ -2,6 +2,7 @@ export * from './activeCommandGuard';
|
|
|
2
2
|
export * from './commands';
|
|
3
3
|
export * from './commandEffects';
|
|
4
4
|
export * from './commandStringExtraction';
|
|
5
|
+
export * from './commandUtils';
|
|
5
6
|
export * from './mentions';
|
|
6
7
|
export * from './validation';
|
|
7
8
|
export * from './TextComposerMiddlewareExecutor';
|