@streamlayer/feature-gamification 1.16.9 → 1.16.11
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/lib/background.js +49 -31
- package/lib/detail.js +15 -7
- package/lib/gamification.js +7 -1
- package/lib/queries/deepLink.js +1 -1
- package/lib/queries/index.d.ts +1 -1
- package/lib/queries/index.js +51 -19
- package/lib/queries/moderation.js +1 -1
- package/lib/storage.d.ts +2 -2
- package/lib/storage.js +5 -5
- package/package.json +8 -8
package/lib/background.js
CHANGED
|
@@ -4,7 +4,6 @@ import { QuestionStatus, QuestionType } from '@streamlayer/sdk-web-types';
|
|
|
4
4
|
import '@streamlayer/sdk-web-core/store';
|
|
5
5
|
import * as queries from './queries';
|
|
6
6
|
import { detail } from './detail';
|
|
7
|
-
import { advertisement } from './advertisement';
|
|
8
7
|
import { GamificationStorage } from './storage';
|
|
9
8
|
export var InteractiveAllowed;
|
|
10
9
|
(function (InteractiveAllowed) {
|
|
@@ -61,39 +60,56 @@ export class GamificationBackground {
|
|
|
61
60
|
this.notifications = instance.notifications;
|
|
62
61
|
this.moderation = new ApiStore(queries.$moderation(this.slStreamId, instance.transport), 'gamification:moderation');
|
|
63
62
|
const onlyBetPack = !!instance.sdk.options.get().betPack;
|
|
64
|
-
this.feedList = new ApiStore(queries.$feedList(this.slStreamId, this.interactiveAllowed, onlyBetPack, instance.transport), 'gamification:feedList');
|
|
63
|
+
this.feedList = new ApiStore(queries.$feedList(this.slStreamId, this.interactiveAllowed, this.userId, this.organizationId, this.storage, onlyBetPack, instance.transport), 'gamification:feedList');
|
|
65
64
|
this.betPack = new ApiStore(queries.$betPack(this.slStreamId, this.userId, this.organizationId, this.storage, instance.transport), 'gamification:betPack');
|
|
66
65
|
this.activeQuestionId = queries.$activeQuestion(this.slStreamId, onlyBetPack, instance.transport);
|
|
67
66
|
this.openedQuestion = detail(instance.transport, this.openedQuestionId, this.feedList.getStore());
|
|
68
67
|
this.cancels.add(this.openedQuestionId.listen((item) => {
|
|
69
68
|
this.log.debug({ item }, 'received question');
|
|
70
69
|
if (item?.questionId) {
|
|
70
|
+
this.log.info('cleanup on close question');
|
|
71
|
+
if (this.questionSubscription !== undefined) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
instance.transport.removeSubscription(this.questionSubscription);
|
|
74
|
+
this.questionSubscription = undefined;
|
|
75
|
+
}
|
|
71
76
|
this.questionSubscription = queries.questionSubscription(item.questionId, instance.transport);
|
|
72
|
-
this.questionSubscription.addListener('feed-subscription-opened-question',
|
|
77
|
+
this.questionSubscription.addListener('feed-subscription-opened-question', (response) => {
|
|
73
78
|
const question = response.data?.attributes?.question;
|
|
74
79
|
this.openedQuestion.updateExtendedQuestion(question);
|
|
75
80
|
if (question?.type === QuestionType.PREDICTION &&
|
|
76
81
|
(question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
|
|
77
82
|
const betPackData = this.betPack.getValues().data?.data || {};
|
|
78
83
|
const betPackItem = betPackData?.[question.id];
|
|
79
|
-
if (betPackItem
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
// if question is not in the feed list, get extended question data from the server
|
|
84
|
-
let extendedQuestion = data.get().data;
|
|
85
|
-
if (!extendedQuestion) {
|
|
86
|
-
extendedQuestion = await queries.questionByUser(question.id, this.transport);
|
|
87
|
-
}
|
|
88
|
-
cancel();
|
|
89
|
-
window.requestAnimationFrame(() => {
|
|
90
|
-
data.invalidate();
|
|
84
|
+
if (betPackItem) {
|
|
85
|
+
const answers = [];
|
|
86
|
+
const sortedPrev = betPackItem.answers.sort((a, b) => {
|
|
87
|
+
return a.id > b.id ? 1 : -1;
|
|
91
88
|
});
|
|
89
|
+
const sortedNew = question.answers.sort((a, b) => {
|
|
90
|
+
return a.id > b.id ? 1 : -1;
|
|
91
|
+
});
|
|
92
|
+
for (let i = 0; i < sortedPrev.length; i++) {
|
|
93
|
+
answers.push({
|
|
94
|
+
...sortedPrev[i],
|
|
95
|
+
...sortedNew[i],
|
|
96
|
+
correct: sortedPrev[i].correct,
|
|
97
|
+
youVoted: sortedPrev[i].youVoted,
|
|
98
|
+
pointsEarned: sortedPrev[i].pointsEarned,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
92
101
|
this.betPack.getStore().mutate({
|
|
93
102
|
timestamp: Date.now(),
|
|
94
103
|
data: {
|
|
95
104
|
...betPackData,
|
|
96
|
-
[question.id]:
|
|
105
|
+
[question.id]: {
|
|
106
|
+
...betPackItem,
|
|
107
|
+
status: question.status,
|
|
108
|
+
marketClosed: question.marketClosed,
|
|
109
|
+
activatedAt: question.activatedAt,
|
|
110
|
+
answerSetAt: question.answerSetAt,
|
|
111
|
+
answers,
|
|
112
|
+
},
|
|
97
113
|
},
|
|
98
114
|
});
|
|
99
115
|
}
|
|
@@ -117,21 +133,23 @@ export class GamificationBackground {
|
|
|
117
133
|
(question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
|
|
118
134
|
const betPackData = this.betPack.getValues().data?.data || {};
|
|
119
135
|
const betPackItem = betPackData?.[question.id];
|
|
120
|
-
if (betPackItem
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
if (betPackItem) {
|
|
137
|
+
this.betPack.getStore().mutate({
|
|
138
|
+
timestamp: Date.now(),
|
|
139
|
+
data: {
|
|
140
|
+
...betPackData,
|
|
141
|
+
[question.id]: {
|
|
142
|
+
...betPackItem,
|
|
143
|
+
status: question.status,
|
|
144
|
+
marketClosed: question.marketClosed,
|
|
145
|
+
activatedAt: question.activatedAt,
|
|
146
|
+
answerSetAt: question.answerSetAt,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
133
149
|
});
|
|
134
|
-
|
|
150
|
+
}
|
|
151
|
+
else if (!betPackItem && Object.keys(betPackData).length < 5) {
|
|
152
|
+
const extendedQuestion = await queries.questionByUser(question.id, this.transport);
|
|
135
153
|
this.betPack.getStore().mutate({
|
|
136
154
|
timestamp: Date.now(),
|
|
137
155
|
data: {
|
|
@@ -215,7 +233,7 @@ export class GamificationBackground {
|
|
|
215
233
|
};
|
|
216
234
|
});
|
|
217
235
|
if (!onlyBetPack) {
|
|
218
|
-
this.advertisement = advertisement(this.slStreamId, this.feedSubscription, instance)
|
|
236
|
+
// this.advertisement = advertisement(this.slStreamId, this.feedSubscription, instance)
|
|
219
237
|
}
|
|
220
238
|
}
|
|
221
239
|
/**
|
package/lib/detail.js
CHANGED
|
@@ -22,16 +22,24 @@ export const detail = (transport, $openedQuestionId, $feedList) => {
|
|
|
22
22
|
const currentQuestion = $extendedStore.get().data;
|
|
23
23
|
const mergeQuestionAnswers = (currentAnswers, newAnswers) => {
|
|
24
24
|
if (!currentAnswers || !newAnswers) {
|
|
25
|
-
return currentAnswers || newAnswers || []
|
|
25
|
+
return (currentAnswers || newAnswers || []).sort((a, b) => {
|
|
26
|
+
return a.id > b.id ? 1 : -1;
|
|
27
|
+
});
|
|
26
28
|
}
|
|
29
|
+
const sortedPrev = currentAnswers.sort((a, b) => {
|
|
30
|
+
return a.id > b.id ? 1 : -1;
|
|
31
|
+
});
|
|
32
|
+
const sortedNew = newAnswers.sort((a, b) => {
|
|
33
|
+
return a.id > b.id ? 1 : -1;
|
|
34
|
+
});
|
|
27
35
|
const answers = [];
|
|
28
|
-
for (let i = 0; i <
|
|
36
|
+
for (let i = 0; i < sortedPrev.length; i++) {
|
|
29
37
|
answers.push({
|
|
30
|
-
...
|
|
31
|
-
...
|
|
32
|
-
correct:
|
|
33
|
-
youVoted:
|
|
34
|
-
pointsEarned:
|
|
38
|
+
...sortedPrev[i],
|
|
39
|
+
...sortedNew[i],
|
|
40
|
+
correct: sortedPrev[i].correct,
|
|
41
|
+
youVoted: sortedPrev[i].youVoted,
|
|
42
|
+
pointsEarned: sortedPrev[i].pointsEarned,
|
|
35
43
|
});
|
|
36
44
|
}
|
|
37
45
|
return answers;
|
package/lib/gamification.js
CHANGED
|
@@ -190,6 +190,7 @@ export class Gamification extends AbstractFeature {
|
|
|
190
190
|
let extendedQuestion = data.get().data;
|
|
191
191
|
if (!extendedQuestion) {
|
|
192
192
|
extendedQuestion = await questionByUser(id, this.transport);
|
|
193
|
+
data.mutate(extendedQuestion);
|
|
193
194
|
}
|
|
194
195
|
cancel();
|
|
195
196
|
window.requestAnimationFrame(() => {
|
|
@@ -301,7 +302,12 @@ export class Gamification extends AbstractFeature {
|
|
|
301
302
|
status: prev.attributes.attributes.value.status,
|
|
302
303
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
303
304
|
// @ts-ignore
|
|
304
|
-
openForVoting:
|
|
305
|
+
openForVoting:
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
307
|
+
// @ts-ignore
|
|
308
|
+
prev.attributes.attributes.value.openForVoting === false
|
|
309
|
+
? false
|
|
310
|
+
: feedItem.attributes.attributes.value.openForVoting,
|
|
305
311
|
},
|
|
306
312
|
},
|
|
307
313
|
},
|
package/lib/queries/deepLink.js
CHANGED
package/lib/queries/index.d.ts
CHANGED
|
@@ -400,7 +400,7 @@ export declare const getPromotionDetail: (promoId: string, transport: Transport)
|
|
|
400
400
|
notification: import("@streamlayer/sl-eslib/interactive/interactive.common_pb").QuestionNotification | undefined;
|
|
401
401
|
} | undefined>;
|
|
402
402
|
export declare const $pickHistory: (slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<(import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").PickHistory | undefined)[], any>;
|
|
403
|
-
export declare const $feedList: ($slStreamId: ReadableAtom<string | undefined>, $interactiveAllowed: ReadableAtom<InteractiveAllowed>, onlyBetPack: boolean, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem[], any>;
|
|
403
|
+
export declare const $feedList: ($slStreamId: ReadableAtom<string | undefined>, $interactiveAllowed: ReadableAtom<InteractiveAllowed>, $slUserId: ReadableAtom<string | undefined>, $slOrganizationId: ReadableAtom<string | undefined>, storage: GamificationStorage, onlyBetPack: boolean, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem[], any>;
|
|
404
404
|
export declare const $activePromotionId: ($slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<{
|
|
405
405
|
id: string;
|
|
406
406
|
question: {
|
package/lib/queries/index.js
CHANGED
|
@@ -24,7 +24,7 @@ export const $activeQuestion = (slStreamId, onlyBetPack, transport) => {
|
|
|
24
24
|
return res.data?.attributes;
|
|
25
25
|
},
|
|
26
26
|
dedupeTime: 1000 * 60 * 10, // 10 minutes
|
|
27
|
-
refetchInterval:
|
|
27
|
+
refetchInterval: Infinity,
|
|
28
28
|
});
|
|
29
29
|
};
|
|
30
30
|
export const getFeedItem = async (questionId, transport) => {
|
|
@@ -67,17 +67,29 @@ export const questionByUser = async ($questionId, transport) => {
|
|
|
67
67
|
});
|
|
68
68
|
return res.data?.attributes?.question;
|
|
69
69
|
};
|
|
70
|
+
const storeCache = new Map();
|
|
70
71
|
export const $questionByUser = ($questionId, transport) => {
|
|
71
|
-
const { client, queryKey } = transport.createPromiseClient(Feed, {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const res = await client.questionByUser({
|
|
75
|
-
questionId: questionId,
|
|
76
|
-
});
|
|
77
|
-
return res.data?.attributes?.question;
|
|
78
|
-
},
|
|
79
|
-
dedupeTime: 1000 * 60 * 5,
|
|
72
|
+
const { client, queryKey, queryKeyStr } = transport.createPromiseClient(Feed, {
|
|
73
|
+
method: 'questionByUser',
|
|
74
|
+
params: [$questionId],
|
|
80
75
|
});
|
|
76
|
+
if (storeCache.has(queryKeyStr)) {
|
|
77
|
+
return storeCache.get(queryKeyStr);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const store = transport.nanoquery.createFetcherStore(queryKey, {
|
|
81
|
+
fetcher: async (_, __, questionId) => {
|
|
82
|
+
const res = await client.questionByUser({
|
|
83
|
+
questionId: questionId,
|
|
84
|
+
});
|
|
85
|
+
return res.data?.attributes?.question;
|
|
86
|
+
},
|
|
87
|
+
dedupeTime: Infinity,
|
|
88
|
+
refetchInterval: Infinity,
|
|
89
|
+
});
|
|
90
|
+
storeCache.set(queryKeyStr, store);
|
|
91
|
+
return store;
|
|
92
|
+
}
|
|
81
93
|
};
|
|
82
94
|
export const getPromotionDetail = async (promoId, transport) => {
|
|
83
95
|
if (!promoId) {
|
|
@@ -108,7 +120,7 @@ export const $pickHistory = (slStreamId, transport) => {
|
|
|
108
120
|
},
|
|
109
121
|
});
|
|
110
122
|
};
|
|
111
|
-
export const $feedList = ($slStreamId, $interactiveAllowed, onlyBetPack, transport) => {
|
|
123
|
+
export const $feedList = ($slStreamId, $interactiveAllowed, $slUserId, $slOrganizationId, storage, onlyBetPack, transport) => {
|
|
112
124
|
const { client, queryKey } = transport.createPromiseClient(Feed, {
|
|
113
125
|
method: 'list',
|
|
114
126
|
params: [$slStreamId, $interactiveAllowed, onlyBetPack ? 'true' : ''],
|
|
@@ -127,10 +139,27 @@ export const $feedList = ($slStreamId, $interactiveAllowed, onlyBetPack, transpo
|
|
|
127
139
|
statuses: [QuestionStatus.ACTIVE, QuestionStatus.RESOLVED],
|
|
128
140
|
},
|
|
129
141
|
});
|
|
142
|
+
const flags = {
|
|
143
|
+
eventId: slStreamId,
|
|
144
|
+
userId: $slUserId.get(),
|
|
145
|
+
organizationId: $slOrganizationId.get(),
|
|
146
|
+
};
|
|
147
|
+
for (const question of res.data) {
|
|
148
|
+
if (!storage.isQuestionReceived(flags, question.id)) {
|
|
149
|
+
eventBus.emit('poll', {
|
|
150
|
+
action: 'received',
|
|
151
|
+
payload: {
|
|
152
|
+
questionId: question.id,
|
|
153
|
+
questionType: question.attributes?.type,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
storage.saveQuestionReceived(flags, question.id);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
130
159
|
return res.data;
|
|
131
160
|
},
|
|
132
|
-
dedupeTime:
|
|
133
|
-
refetchInterval:
|
|
161
|
+
dedupeTime: Infinity,
|
|
162
|
+
refetchInterval: Infinity,
|
|
134
163
|
});
|
|
135
164
|
};
|
|
136
165
|
export const $activePromotionId = ($slStreamId, transport) => {
|
|
@@ -160,8 +189,8 @@ export const $activePromotionId = ($slStreamId, transport) => {
|
|
|
160
189
|
}
|
|
161
190
|
return undefined;
|
|
162
191
|
},
|
|
163
|
-
dedupeTime:
|
|
164
|
-
refetchInterval:
|
|
192
|
+
dedupeTime: Infinity,
|
|
193
|
+
refetchInterval: Infinity,
|
|
165
194
|
});
|
|
166
195
|
};
|
|
167
196
|
export { $userSummary, $leaderboardList } from './leaderboard';
|
|
@@ -208,7 +237,7 @@ export const $betPack = ($slStreamId, $slUserId, $slOrganizationId, storage, tra
|
|
|
208
237
|
userId: userId,
|
|
209
238
|
organizationId: organizationId,
|
|
210
239
|
};
|
|
211
|
-
if (!storage.
|
|
240
|
+
if (!storage.isQuestionReceived(flags, question.id)) {
|
|
212
241
|
eventBus.emit('poll', {
|
|
213
242
|
action: 'received',
|
|
214
243
|
payload: {
|
|
@@ -216,13 +245,16 @@ export const $betPack = ($slStreamId, $slUserId, $slOrganizationId, storage, tra
|
|
|
216
245
|
questionType: question.type,
|
|
217
246
|
},
|
|
218
247
|
});
|
|
219
|
-
storage.
|
|
248
|
+
storage.saveQuestionReceived(flags, question.id);
|
|
220
249
|
}
|
|
250
|
+
question.answers = question.answers.sort((a, b) => {
|
|
251
|
+
return a.id > b.id ? 1 : -1;
|
|
252
|
+
});
|
|
221
253
|
return { ...acc, [question.id]: question };
|
|
222
254
|
}, {}),
|
|
223
255
|
};
|
|
224
256
|
},
|
|
225
|
-
dedupeTime:
|
|
226
|
-
refetchInterval:
|
|
257
|
+
dedupeTime: Infinity,
|
|
258
|
+
refetchInterval: Infinity,
|
|
227
259
|
});
|
|
228
260
|
};
|
package/lib/storage.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ type UserProps = {
|
|
|
8
8
|
export declare class GamificationStorage extends Storage {
|
|
9
9
|
private sessionStorage;
|
|
10
10
|
constructor();
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
saveQuestionReceived: ({ userId, eventId, organizationId }: UserProps, questionId: string) => void;
|
|
12
|
+
isQuestionReceived: ({ userId, eventId, organizationId }: UserProps, questionId: string) => boolean;
|
|
13
13
|
saveQuestionOpened: ({ userId, eventId, organizationId }: UserProps, questionId: string) => void;
|
|
14
14
|
isQuestionOpened: ({ userId, eventId, organizationId }: UserProps, questionId: string) => boolean;
|
|
15
15
|
saveOnboardingStatus: ({ userId, eventId, organizationId }: UserProps, status: OnboardingStatus) => void;
|
package/lib/storage.js
CHANGED
|
@@ -3,7 +3,7 @@ var KEY_PREFIX;
|
|
|
3
3
|
(function (KEY_PREFIX) {
|
|
4
4
|
KEY_PREFIX["ONBOARDING"] = "onboarding";
|
|
5
5
|
KEY_PREFIX["ONBOARDING_IO"] = "onboarding_io";
|
|
6
|
-
KEY_PREFIX["
|
|
6
|
+
KEY_PREFIX["QUESTION_RECEIVED"] = "q-received";
|
|
7
7
|
KEY_PREFIX["QUESTION_OPENED"] = "q-opened";
|
|
8
8
|
})(KEY_PREFIX || (KEY_PREFIX = {}));
|
|
9
9
|
class GamificationSessionStorage extends Storage {
|
|
@@ -23,11 +23,11 @@ export class GamificationStorage extends Storage {
|
|
|
23
23
|
super('gamification');
|
|
24
24
|
this.sessionStorage = new GamificationSessionStorage();
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
this.write(KEY_PREFIX.
|
|
26
|
+
saveQuestionReceived = ({ userId, eventId, organizationId }, questionId) => {
|
|
27
|
+
this.write(KEY_PREFIX.QUESTION_RECEIVED, organizationId, userId, eventId, questionId, '1');
|
|
28
28
|
};
|
|
29
|
-
|
|
30
|
-
return !!this.read(KEY_PREFIX.
|
|
29
|
+
isQuestionReceived = ({ userId, eventId, organizationId }, questionId) => {
|
|
30
|
+
return !!this.read(KEY_PREFIX.QUESTION_RECEIVED, organizationId, userId, eventId, questionId);
|
|
31
31
|
};
|
|
32
32
|
saveQuestionOpened = ({ userId, eventId, organizationId }, questionId) => {
|
|
33
33
|
this.write(KEY_PREFIX.QUESTION_OPENED, organizationId, userId, eventId, questionId, '1');
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamlayer/feature-gamification",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.11",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@bufbuild/protobuf": "^1.10.0",
|
|
6
6
|
"@fastify/deepmerge": "^2.0.0",
|
|
7
7
|
"@streamlayer/sl-eslib": "^5.149.1",
|
|
8
8
|
"uuid": "^11.1.0",
|
|
9
9
|
"nanostores": "^0.11.4",
|
|
10
|
-
"@streamlayer/sdk-web-api": "^1.8.
|
|
11
|
-
"@streamlayer/sdk-web-core": "^1.11.
|
|
12
|
-
"@streamlayer/sdk-web-interfaces": "^1.5.
|
|
13
|
-
"@streamlayer/sdk-web-logger": "^1.0.
|
|
14
|
-
"@streamlayer/sdk-web-notifications": "^1.3.
|
|
15
|
-
"@streamlayer/sdk-web-storage": "^1.0.
|
|
16
|
-
"@streamlayer/sdk-web-types": "^1.10.
|
|
10
|
+
"@streamlayer/sdk-web-api": "^1.8.11",
|
|
11
|
+
"@streamlayer/sdk-web-core": "^1.11.13",
|
|
12
|
+
"@streamlayer/sdk-web-interfaces": "^1.5.2",
|
|
13
|
+
"@streamlayer/sdk-web-logger": "^1.0.58",
|
|
14
|
+
"@streamlayer/sdk-web-notifications": "^1.3.20",
|
|
15
|
+
"@streamlayer/sdk-web-storage": "^1.0.58",
|
|
16
|
+
"@streamlayer/sdk-web-types": "^1.10.15"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"tslib": "^2.7.0"
|