@allior/wmake-streamelements-events 2.0.2 → 2.0.4
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/react/hooks/use-on-event-received.d.ts +1 -1
- package/dist/react/hooks/use-on-widget-load.d.ts +1 -1
- package/dist/react/index.iife.js +2 -2
- package/dist/react/index.iife.js.map +1 -1
- package/dist/react/index.js +32 -92
- package/dist/react/index.js.map +1 -1
- package/dist/root/guards/on-event-received.d.ts +1 -1
- package/dist/root/index.iife.js +2 -2
- package/dist/root/index.iife.js.map +1 -1
- package/dist/root/index.js +2 -3116
- package/dist/root/queue/alert-queue.d.ts +1 -1
- package/dist/root/queue/next-alert-callback.d.ts +1 -1
- package/dist/root/types/on-event-received/message.d.ts +1 -1
- package/dist/root-BzhLLMHq.js +2934 -0
- package/dist/root-BzhLLMHq.js.map +1 -0
- package/package.json +11 -13
- package/dist/root/index.js.map +0 -1
- package/src/react/hooks/index.ts +0 -3
- package/src/react/hooks/use-event-listener.ts +0 -20
- package/src/react/hooks/use-on-event-received.ts +0 -108
- package/src/react/hooks/use-on-widget-load.ts +0 -15
- package/src/react/index.ts +0 -3
- package/src/react/types/index.ts +0 -1
- package/src/react/types/window-events.ts +0 -6
- package/src/root/aggregate.ts +0 -257
- package/src/root/classifier.ts +0 -271
- package/src/root/commands.ts +0 -39
- package/src/root/data/field-value.ts +0 -2
- package/src/root/data/index.ts +0 -2
- package/src/root/data/widget-load.ts +0 -5
- package/src/root/guards/index.ts +0 -1
- package/src/root/guards/on-event-received.ts +0 -58
- package/src/root/index.ts +0 -11
- package/src/root/keys.ts +0 -14
- package/src/root/message/index.ts +0 -1
- package/src/root/message/twitch/index.ts +0 -2
- package/src/root/message/twitch/message.ts +0 -48
- package/src/root/message/twitch/user-message-data.ts +0 -112
- package/src/root/queue/alert-queue.ts +0 -31
- package/src/root/queue/index.ts +0 -2
- package/src/root/queue/next-alert-callback.ts +0 -7
- package/src/root/sources/alerts.ts +0 -163
- package/src/root/sources/index.ts +0 -5
- package/src/root/sources/messages.ts +0 -1611
- package/src/root/sources/on-widget-load-detail.ts +0 -968
- package/src/root/types/index.ts +0 -2
- package/src/root/types/on-event-received/base.ts +0 -94
- package/src/root/types/on-event-received/cheer.ts +0 -10
- package/src/root/types/on-event-received/donation.ts +0 -29
- package/src/root/types/on-event-received/follower.ts +0 -9
- package/src/root/types/on-event-received/index.ts +0 -58
- package/src/root/types/on-event-received/message.ts +0 -13
- package/src/root/types/on-event-received/moderation.ts +0 -7
- package/src/root/types/on-event-received/other.ts +0 -14
- package/src/root/types/on-event-received/raid.ts +0 -10
- package/src/root/types/on-event-received/subscriber.ts +0 -77
- package/src/root/types/on-widget-load/base.ts +0 -35
- package/src/root/types/on-widget-load/index.ts +0 -3
- package/src/root/types/on-widget-load/recents.ts +0 -33
- package/src/root/types/on-widget-load/session.ts +0 -102
- package/src/root/window-event-map.ts +0 -9
- package/tsconfig.app.json +0 -31
- package/tsconfig.json +0 -8
- package/tsconfig.node.json +0 -25
- package/vite.config.ts +0 -36
- package/vite.iife.config.ts +0 -52
package/src/root/aggregate.ts
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event normalizer — aggregate mode: buffer events by activityGroup,
|
|
3
|
-
* merge into one normalized event per action (timeout 2.5s).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { classifyEvent, getCacheKey } from "./classifier.js";
|
|
7
|
-
import type {
|
|
8
|
-
CacheSubsByType,
|
|
9
|
-
ClassifiedCommunityGiftPurchase,
|
|
10
|
-
ClassifiedEvent,
|
|
11
|
-
ClassifiedRecipient,
|
|
12
|
-
IncomingDetail,
|
|
13
|
-
NormalizerOptions,
|
|
14
|
-
} from "./types";
|
|
15
|
-
|
|
16
|
-
const AGGREGATE_TIMEOUT_MS = 2500;
|
|
17
|
-
|
|
18
|
-
interface BufferEntry {
|
|
19
|
-
type: string;
|
|
20
|
-
subscribers: Array<{
|
|
21
|
-
recipient?: string;
|
|
22
|
-
username?: string;
|
|
23
|
-
name?: string;
|
|
24
|
-
sender?: string;
|
|
25
|
-
}>;
|
|
26
|
-
tier: number;
|
|
27
|
-
tierText: string;
|
|
28
|
-
totalAmount: number;
|
|
29
|
-
purchase?: ClassifiedCommunityGiftPurchase;
|
|
30
|
-
sender?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const bufferByGroup: Record<string, BufferEntry> = {};
|
|
34
|
-
const bufferTimers: Record<string, ReturnType<typeof setTimeout>> = {};
|
|
35
|
-
|
|
36
|
-
function getCacheForType(
|
|
37
|
-
cacheSubs: CacheSubsByType | undefined,
|
|
38
|
-
type: string,
|
|
39
|
-
): {
|
|
40
|
-
_has: (k: string) => boolean;
|
|
41
|
-
_set: (k: string, v: boolean) => void;
|
|
42
|
-
} | null {
|
|
43
|
-
if (!cacheSubs) return null;
|
|
44
|
-
if (
|
|
45
|
-
typeof cacheSubs._has === "function" &&
|
|
46
|
-
typeof cacheSubs._set === "function"
|
|
47
|
-
) {
|
|
48
|
-
return cacheSubs as unknown as {
|
|
49
|
-
_has: (k: string) => boolean;
|
|
50
|
-
_set: (k: string, v: boolean) => void;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
const c = cacheSubs[type];
|
|
54
|
-
return c && typeof (c as { _has?: unknown })._has === "function"
|
|
55
|
-
? (c as {
|
|
56
|
-
_has: (k: string) => boolean;
|
|
57
|
-
_set: (k: string, v: boolean) => void;
|
|
58
|
-
})
|
|
59
|
-
: null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function emitAggregated(
|
|
63
|
-
groupKey: string,
|
|
64
|
-
merged: ClassifiedCommunityGiftPurchase,
|
|
65
|
-
cacheSubs: CacheSubsByType | undefined,
|
|
66
|
-
onNormalized: (event: ClassifiedEvent | null) => void,
|
|
67
|
-
): void {
|
|
68
|
-
const cache = getCacheForType(cacheSubs, merged.type as string);
|
|
69
|
-
if (cache?._has(groupKey)) return;
|
|
70
|
-
if (cache) cache._set(groupKey, true);
|
|
71
|
-
onNormalized(merged);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function flushBuffer(
|
|
75
|
-
groupKey: string,
|
|
76
|
-
cacheSubs: CacheSubsByType | undefined,
|
|
77
|
-
onNormalized: (event: ClassifiedEvent | null) => void,
|
|
78
|
-
broadcaster: string,
|
|
79
|
-
): void {
|
|
80
|
-
const buf = bufferByGroup[groupKey];
|
|
81
|
-
if (!buf) return;
|
|
82
|
-
delete bufferByGroup[groupKey];
|
|
83
|
-
if (bufferTimers[groupKey]) {
|
|
84
|
-
clearTimeout(bufferTimers[groupKey]);
|
|
85
|
-
delete bufferTimers[groupKey];
|
|
86
|
-
}
|
|
87
|
-
const purchase = buf.purchase;
|
|
88
|
-
const subscribers = buf.subscribers ?? [];
|
|
89
|
-
const type = buf.type;
|
|
90
|
-
const tier = buf.tier;
|
|
91
|
-
const tierText = buf.tierText;
|
|
92
|
-
const totalAmount = buf.totalAmount ?? subscribers.length;
|
|
93
|
-
const recipients = subscribers
|
|
94
|
-
.map((s) => s.recipient ?? s.username ?? s.name)
|
|
95
|
-
.filter(Boolean) as string[];
|
|
96
|
-
const firstSub = subscribers[0];
|
|
97
|
-
const senderFromSub = firstSub?.sender;
|
|
98
|
-
const sender = purchase?.sender ?? buf.sender ?? senderFromSub;
|
|
99
|
-
if (type === "community-gift" && broadcaster && sender === broadcaster) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (type === "community-gift-anonymous") {
|
|
103
|
-
emitAggregated(
|
|
104
|
-
groupKey,
|
|
105
|
-
{
|
|
106
|
-
type: "community-gift-anonymous",
|
|
107
|
-
tier,
|
|
108
|
-
tierText,
|
|
109
|
-
totalAmount,
|
|
110
|
-
recipients,
|
|
111
|
-
anonymousDisplayName: purchase?.anonymousDisplayName,
|
|
112
|
-
},
|
|
113
|
-
cacheSubs,
|
|
114
|
-
onNormalized,
|
|
115
|
-
);
|
|
116
|
-
} else {
|
|
117
|
-
emitAggregated(
|
|
118
|
-
groupKey,
|
|
119
|
-
{
|
|
120
|
-
type: "community-gift",
|
|
121
|
-
sender,
|
|
122
|
-
tier,
|
|
123
|
-
tierText,
|
|
124
|
-
totalAmount,
|
|
125
|
-
recipients,
|
|
126
|
-
},
|
|
127
|
-
cacheSubs,
|
|
128
|
-
onNormalized,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Normalizes an incoming subscription event (StreamElements/Twitch).
|
|
135
|
-
* Buffers community-gift recipients by activityGroup, then emits one normalized event per group.
|
|
136
|
-
* For self-sub, solo-sub, sub-renewal emits immediately (with optional cache dedup).
|
|
137
|
-
*/
|
|
138
|
-
export function normalizeIncomingEvent(
|
|
139
|
-
detail: IncomingDetail,
|
|
140
|
-
options: NormalizerOptions | undefined,
|
|
141
|
-
onNormalized: (event: ClassifiedEvent | null) => void,
|
|
142
|
-
): void {
|
|
143
|
-
const cacheSubs = options?.cacheSubs;
|
|
144
|
-
const broadcaster = options?.broadcasterLogin ?? "";
|
|
145
|
-
|
|
146
|
-
const classified = classifyEvent(detail);
|
|
147
|
-
if (!classified) {
|
|
148
|
-
onNormalized(null);
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const cache = getCacheForType(cacheSubs, classified.type);
|
|
153
|
-
const cacheKey = getCacheKey(detail);
|
|
154
|
-
const event = detail.event ?? {};
|
|
155
|
-
const data = (event.data ?? event) as Record<string, unknown>;
|
|
156
|
-
|
|
157
|
-
if ((classified as ClassifiedRecipient)._role === "recipient") {
|
|
158
|
-
const recipient = classified as ClassifiedRecipient;
|
|
159
|
-
const ag = recipient.activityGroup ?? cacheKey;
|
|
160
|
-
if (!bufferByGroup[ag]) {
|
|
161
|
-
bufferByGroup[ag] = {
|
|
162
|
-
type: recipient.type,
|
|
163
|
-
subscribers: [],
|
|
164
|
-
tier: recipient.tier,
|
|
165
|
-
tierText: recipient.tierText,
|
|
166
|
-
totalAmount: 0,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
if (bufferTimers[ag]) clearTimeout(bufferTimers[ag]);
|
|
170
|
-
bufferTimers[ag] = setTimeout(() => {
|
|
171
|
-
flushBuffer(ag, cacheSubs, onNormalized, broadcaster);
|
|
172
|
-
}, AGGREGATE_TIMEOUT_MS);
|
|
173
|
-
bufferByGroup[ag].subscribers.push({
|
|
174
|
-
recipient: recipient.recipient,
|
|
175
|
-
username: data.username as string,
|
|
176
|
-
name: data.displayName as string,
|
|
177
|
-
sender: data.sender as string,
|
|
178
|
-
});
|
|
179
|
-
if (bufferByGroup[ag].totalAmount === 0) bufferByGroup[ag].totalAmount = 1;
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
classified.type === "community-gift-anonymous" ||
|
|
185
|
-
classified.type === "community-gift"
|
|
186
|
-
) {
|
|
187
|
-
const isPurchase =
|
|
188
|
-
detail.listener === "event" && event.type === "communityGiftPurchase";
|
|
189
|
-
if (isPurchase) {
|
|
190
|
-
const ag = (event.activityGroup ??
|
|
191
|
-
data?.activityGroup ??
|
|
192
|
-
cacheKey) as string;
|
|
193
|
-
const cg = classified as ClassifiedCommunityGiftPurchase;
|
|
194
|
-
if (!bufferByGroup[ag]) {
|
|
195
|
-
bufferByGroup[ag] = {
|
|
196
|
-
type: cg.type,
|
|
197
|
-
purchase: cg,
|
|
198
|
-
subscribers: [],
|
|
199
|
-
tier: cg.tier,
|
|
200
|
-
tierText: cg.tierText,
|
|
201
|
-
totalAmount: Number(cg.totalAmount) || 0,
|
|
202
|
-
sender: cg.sender,
|
|
203
|
-
};
|
|
204
|
-
bufferTimers[ag] = setTimeout(() => {
|
|
205
|
-
flushBuffer(ag, cacheSubs, onNormalized, broadcaster);
|
|
206
|
-
}, AGGREGATE_TIMEOUT_MS);
|
|
207
|
-
} else {
|
|
208
|
-
bufferByGroup[ag].purchase = cg;
|
|
209
|
-
bufferByGroup[ag].tier = cg.tier;
|
|
210
|
-
bufferByGroup[ag].tierText = cg.tierText;
|
|
211
|
-
bufferByGroup[ag].totalAmount =
|
|
212
|
-
(cg.totalAmount as number) ?? bufferByGroup[ag].totalAmount;
|
|
213
|
-
bufferByGroup[ag].sender = cg.sender as string;
|
|
214
|
-
if (bufferTimers[ag]) clearTimeout(bufferTimers[ag]);
|
|
215
|
-
bufferTimers[ag] = setTimeout(() => {
|
|
216
|
-
flushBuffer(ag, cacheSubs, onNormalized, broadcaster);
|
|
217
|
-
}, AGGREGATE_TIMEOUT_MS);
|
|
218
|
-
}
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (detail.listener === "subscriber-latest") {
|
|
222
|
-
const c = classified as ClassifiedCommunityGiftPurchase;
|
|
223
|
-
if (
|
|
224
|
-
classified.type === "community-gift" &&
|
|
225
|
-
broadcaster &&
|
|
226
|
-
c.sender === broadcaster
|
|
227
|
-
) {
|
|
228
|
-
onNormalized(null);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
classified.type === "self-sub" ||
|
|
238
|
-
classified.type === "solo-sub-to-someone" ||
|
|
239
|
-
classified.type === "sub-renewal"
|
|
240
|
-
) {
|
|
241
|
-
if (cache?._has(cacheKey)) {
|
|
242
|
-
onNormalized(null);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (cache) cache._set(cacheKey, true);
|
|
246
|
-
const c = classified as unknown as Record<string, unknown>;
|
|
247
|
-
if (
|
|
248
|
-
classified.type === "solo-sub-to-someone" &&
|
|
249
|
-
broadcaster &&
|
|
250
|
-
c.sender === broadcaster
|
|
251
|
-
) {
|
|
252
|
-
onNormalized(null);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
onNormalized(classified);
|
|
256
|
-
}
|
|
257
|
-
}
|
package/src/root/classifier.ts
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared classification and tier parsing for Twitch/StreamElements subscription events.
|
|
3
|
-
* Used by aggregate normalizer.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ClassifiedEvent, IncomingDetail, TierInfo } from "./types";
|
|
7
|
-
|
|
8
|
-
export function parseTier(raw: string | number | null | undefined): TierInfo {
|
|
9
|
-
if (raw == null) return { tier: 0, tierText: "" };
|
|
10
|
-
const tierText = typeof raw === "string" ? raw : String(raw);
|
|
11
|
-
const num = parseInt(tierText, 10);
|
|
12
|
-
if (Number.isNaN(num)) return { tier: 0, tierText };
|
|
13
|
-
const tier = num >= 3000 ? 3 : num >= 2000 ? 2 : num >= 1000 ? 1 : 0;
|
|
14
|
-
return { tier, tierText };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getCacheKey(detail: IncomingDetail): string {
|
|
18
|
-
const listener = detail.listener;
|
|
19
|
-
const event = detail.event ?? {};
|
|
20
|
-
const ag = event.activityGroup;
|
|
21
|
-
const aid = event.activityId ?? event._id;
|
|
22
|
-
if (ag) return String(ag);
|
|
23
|
-
if (aid) return String(aid);
|
|
24
|
-
if (listener === "subscriber-latest" && event.bulkGifted) {
|
|
25
|
-
return (
|
|
26
|
-
"sl-bulk-" +
|
|
27
|
-
(event.sender ?? "") +
|
|
28
|
-
"-" +
|
|
29
|
-
(event.amount ?? "") +
|
|
30
|
-
"-" +
|
|
31
|
-
(event.tier ?? "") +
|
|
32
|
-
"-" +
|
|
33
|
-
(event._id ?? "")
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
return `sl-${event._id ?? event.activityId ?? ""}`;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function classifyEvent(detail: IncomingDetail): ClassifiedEvent | null {
|
|
40
|
-
const listener = detail.listener;
|
|
41
|
-
const event = detail.event ?? {};
|
|
42
|
-
const data = (event.data ?? event) as Record<string, unknown>;
|
|
43
|
-
const tierInfo = parseTier(
|
|
44
|
-
(data.tier ?? event.tier) as string | number | undefined,
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
if (listener === "event") {
|
|
48
|
-
if (event.type === "communityGiftPurchase") {
|
|
49
|
-
const isAnon =
|
|
50
|
-
(data.username &&
|
|
51
|
-
String(data.username).toLowerCase() === "anonymous") ||
|
|
52
|
-
data.sender === "Anonymous";
|
|
53
|
-
return {
|
|
54
|
-
type: isAnon ? "community-gift-anonymous" : "community-gift",
|
|
55
|
-
tier: tierInfo.tier,
|
|
56
|
-
tierText: tierInfo.tierText,
|
|
57
|
-
totalAmount: parseInt(String(data.amount), 10) || 1,
|
|
58
|
-
recipients: [],
|
|
59
|
-
sender: isAnon
|
|
60
|
-
? undefined
|
|
61
|
-
: ((data.sender ?? data.displayName ?? data.username) as string),
|
|
62
|
-
anonymousDisplayName: isAnon
|
|
63
|
-
? ((data.displayName as string) ?? "Anonymous")
|
|
64
|
-
: undefined,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
if (event.type === "subscriber") {
|
|
68
|
-
const gifted = data.gifted === true;
|
|
69
|
-
const sender = data.sender as string | undefined;
|
|
70
|
-
const amount = parseInt(String(data.amount), 10) || 1;
|
|
71
|
-
const username = (data.username ?? data.displayName) as
|
|
72
|
-
| string
|
|
73
|
-
| undefined;
|
|
74
|
-
const activityGroup = event.activityGroup as string | undefined;
|
|
75
|
-
|
|
76
|
-
if (sender === "Anonymous" && activityGroup) {
|
|
77
|
-
return {
|
|
78
|
-
type: "community-gift-anonymous",
|
|
79
|
-
_role: "recipient",
|
|
80
|
-
activityGroup,
|
|
81
|
-
recipient: (username ?? data.displayName) as string,
|
|
82
|
-
tier: tierInfo.tier,
|
|
83
|
-
tierText: tierInfo.tierText,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
if (gifted && sender && sender !== "Anonymous") {
|
|
87
|
-
const isCommunity =
|
|
88
|
-
data.communityGifted === true ||
|
|
89
|
-
(activityGroup != null && activityGroup !== "");
|
|
90
|
-
if (!isCommunity) {
|
|
91
|
-
const firstGift =
|
|
92
|
-
String(data.message ?? "").indexOf("first Gift Sub") !== -1;
|
|
93
|
-
return {
|
|
94
|
-
type: "solo-sub-to-someone",
|
|
95
|
-
sender,
|
|
96
|
-
recipient: (username ?? data.displayName) as string,
|
|
97
|
-
tier: tierInfo.tier,
|
|
98
|
-
tierText: tierInfo.tierText,
|
|
99
|
-
firstGiftInChannel: firstGift,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
type: "community-gift",
|
|
104
|
-
_role: "recipient",
|
|
105
|
-
activityGroup: activityGroup ?? "",
|
|
106
|
-
recipient: (username ?? data.displayName) as string,
|
|
107
|
-
tier: tierInfo.tier,
|
|
108
|
-
tierText: tierInfo.tierText,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (!gifted && amount > 1) {
|
|
112
|
-
return {
|
|
113
|
-
type: "sub-renewal",
|
|
114
|
-
name: (username ?? data.displayName) as string,
|
|
115
|
-
months: amount,
|
|
116
|
-
tier: tierInfo.tier,
|
|
117
|
-
tierText: tierInfo.tierText,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if (!gifted && amount === 1) {
|
|
121
|
-
return {
|
|
122
|
-
type: "self-sub",
|
|
123
|
-
name: (username ?? data.displayName) as string,
|
|
124
|
-
tier: tierInfo.tier,
|
|
125
|
-
tierText: tierInfo.tierText,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
if (activityGroup) {
|
|
129
|
-
return {
|
|
130
|
-
type: "community-gift",
|
|
131
|
-
_role: "recipient",
|
|
132
|
-
activityGroup,
|
|
133
|
-
recipient: (username ?? data.displayName) as string,
|
|
134
|
-
tier: tierInfo.tier,
|
|
135
|
-
tierText: tierInfo.tierText,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
return {
|
|
139
|
-
type: "unknown",
|
|
140
|
-
detail,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
type: "unknown",
|
|
145
|
-
detail,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (listener === "subscriber-latest") {
|
|
150
|
-
const bulkGifted = event.bulkGifted === true;
|
|
151
|
-
const sender = event.sender as string | undefined;
|
|
152
|
-
const name = event.name as string | undefined;
|
|
153
|
-
const amount = parseInt(String(event.amount), 10) || 1;
|
|
154
|
-
const gifted = event.gifted === true;
|
|
155
|
-
const isCommunityGift =
|
|
156
|
-
event.isCommunityGift === true || event.communityGifted === true;
|
|
157
|
-
|
|
158
|
-
if (bulkGifted && sender === "Anonymous") {
|
|
159
|
-
return {
|
|
160
|
-
type: "community-gift-anonymous",
|
|
161
|
-
tier: tierInfo.tier,
|
|
162
|
-
tierText: tierInfo.tierText,
|
|
163
|
-
totalAmount: amount,
|
|
164
|
-
recipients: [],
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (bulkGifted && sender) {
|
|
168
|
-
return {
|
|
169
|
-
type: "community-gift",
|
|
170
|
-
sender,
|
|
171
|
-
tier: tierInfo.tier,
|
|
172
|
-
tierText: tierInfo.tierText,
|
|
173
|
-
totalAmount: amount,
|
|
174
|
-
recipients: [],
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
if (gifted && !isCommunityGift && sender) {
|
|
178
|
-
const firstGift =
|
|
179
|
-
String(event.message ?? "").indexOf("first Gift Sub") !== -1;
|
|
180
|
-
return {
|
|
181
|
-
type: "solo-sub-to-someone",
|
|
182
|
-
sender,
|
|
183
|
-
recipient: name ?? "",
|
|
184
|
-
tier: tierInfo.tier,
|
|
185
|
-
tierText: tierInfo.tierText,
|
|
186
|
-
firstGiftInChannel: firstGift,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
if (!gifted && amount > 1) {
|
|
190
|
-
return {
|
|
191
|
-
type: "sub-renewal",
|
|
192
|
-
name: name ?? "",
|
|
193
|
-
months: amount,
|
|
194
|
-
tier: tierInfo.tier,
|
|
195
|
-
tierText: tierInfo.tierText,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
if (!gifted && amount === 1 && (sender == null || name === sender)) {
|
|
199
|
-
return {
|
|
200
|
-
type: "self-sub",
|
|
201
|
-
name: name ?? "",
|
|
202
|
-
tier: tierInfo.tier,
|
|
203
|
-
tierText: tierInfo.tierText,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
type: "unknown",
|
|
208
|
-
detail,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (listener === "follower-latest") {
|
|
213
|
-
return {
|
|
214
|
-
type: "follow",
|
|
215
|
-
name: (event.name as string) ?? "",
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (listener === "cheer-latest") {
|
|
220
|
-
const amount = parseInt(String(event.amount), 10) || 0;
|
|
221
|
-
return {
|
|
222
|
-
type: "cheer",
|
|
223
|
-
name: (event.name as string) ?? "",
|
|
224
|
-
amount,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (listener === "raid-latest") {
|
|
229
|
-
const amount = parseInt(String(event.amount), 10) || 0;
|
|
230
|
-
return {
|
|
231
|
-
type: "raid",
|
|
232
|
-
name: (event.name as string) ?? "",
|
|
233
|
-
viewers: amount,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (listener === "donation") {
|
|
238
|
-
const d = detail.event?.data as
|
|
239
|
-
| {
|
|
240
|
-
alert_type?: string;
|
|
241
|
-
currency?: string;
|
|
242
|
-
billing_system?: string;
|
|
243
|
-
id?: number;
|
|
244
|
-
amount_main?: number;
|
|
245
|
-
amount?: number;
|
|
246
|
-
username?: string;
|
|
247
|
-
message?: string;
|
|
248
|
-
}
|
|
249
|
-
| undefined;
|
|
250
|
-
|
|
251
|
-
const donationAmount =
|
|
252
|
-
(d?.amount_main as number | undefined) ??
|
|
253
|
-
(d?.amount as number | undefined) ??
|
|
254
|
-
0;
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
type: "donation",
|
|
258
|
-
amount: donationAmount,
|
|
259
|
-
currency: d?.currency,
|
|
260
|
-
username: d?.username,
|
|
261
|
-
message: d?.message,
|
|
262
|
-
billingSystem: d?.billing_system,
|
|
263
|
-
id: d?.id,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
type: "unknown",
|
|
269
|
-
detail,
|
|
270
|
-
};
|
|
271
|
-
}
|
package/src/root/commands.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Команды, вызывающие onEventReceived с тестовыми сообщением или алертом.
|
|
3
|
-
* Работают только в браузере (требуется window).
|
|
4
|
-
*/
|
|
5
|
-
import { testAlerts, testMessages } from "./sources";
|
|
6
|
-
|
|
7
|
-
const EVENT_NAME = "onEventReceived";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Отправляет тестовое сообщение по ключу: диспатчит CustomEvent onEventReceived.
|
|
11
|
-
*/
|
|
12
|
-
export function testMessage(key: string): void {
|
|
13
|
-
if (typeof window === "undefined") {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const cleanKey = key.startsWith("testMessage_")
|
|
17
|
-
? key.replace("testMessage_", "")
|
|
18
|
-
: key;
|
|
19
|
-
const msg = testMessages[cleanKey as keyof typeof testMessages];
|
|
20
|
-
if (msg) {
|
|
21
|
-
window.dispatchEvent(new CustomEvent(EVENT_NAME, { detail: msg }));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Отправляет тестовый алерт по ключу: диспатчит CustomEvent onEventReceived.
|
|
27
|
-
*/
|
|
28
|
-
export function testAlert(key: string): void {
|
|
29
|
-
if (typeof window === "undefined") {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const cleanKey = key.startsWith("testAlert_")
|
|
33
|
-
? key.replace("testAlert_", "")
|
|
34
|
-
: key;
|
|
35
|
-
const alert = testAlerts[cleanKey as keyof typeof testAlerts];
|
|
36
|
-
if (alert) {
|
|
37
|
-
window.dispatchEvent(new CustomEvent(EVENT_NAME, { detail: alert }));
|
|
38
|
-
}
|
|
39
|
-
}
|
package/src/root/data/index.ts
DELETED
package/src/root/guards/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./on-event-received";
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CheerDetail,
|
|
3
|
-
CommunityGiftPurchaseDetail,
|
|
4
|
-
DeleteMessageDetail,
|
|
5
|
-
DeleteMessagesDetail,
|
|
6
|
-
DonationDetail,
|
|
7
|
-
FollowerDetail,
|
|
8
|
-
MinimalEvent,
|
|
9
|
-
RaidDetail,
|
|
10
|
-
SubscriberDetail,
|
|
11
|
-
SubscriberLatestDetail,
|
|
12
|
-
TwitchMessageDetail,
|
|
13
|
-
WidgetButtonDetail,
|
|
14
|
-
} from "@/root/types/on-event-received";
|
|
15
|
-
|
|
16
|
-
export const isDetail = (d: unknown): d is MinimalEvent =>
|
|
17
|
-
typeof d === "object" && d !== null && "listener" in d;
|
|
18
|
-
|
|
19
|
-
export function createGuard<T extends MinimalEvent>(
|
|
20
|
-
predicate: (d: MinimalEvent) => boolean,
|
|
21
|
-
) {
|
|
22
|
-
return (d: unknown): d is T => isDetail(d) && predicate(d);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const isTwitchMessageEvent = createGuard<TwitchMessageDetail>(
|
|
26
|
-
(d) => d.listener === "message",
|
|
27
|
-
);
|
|
28
|
-
export const isFollowerDetail = createGuard<FollowerDetail>(
|
|
29
|
-
(d) => d.listener === "follower-latest",
|
|
30
|
-
);
|
|
31
|
-
export const isSubscriberLatestDetail = createGuard<SubscriberLatestDetail>(
|
|
32
|
-
(d) => d.listener === "subscriber-latest",
|
|
33
|
-
);
|
|
34
|
-
export const isCheerDetail = createGuard<CheerDetail>(
|
|
35
|
-
(d) => d.listener === "cheer-latest",
|
|
36
|
-
);
|
|
37
|
-
export const isRaidDetail = createGuard<RaidDetail>(
|
|
38
|
-
(d) => d.listener === "raid-latest",
|
|
39
|
-
);
|
|
40
|
-
export const isDonationDetail = createGuard<DonationDetail>(
|
|
41
|
-
(d) => d.listener === "donation",
|
|
42
|
-
);
|
|
43
|
-
export const isDeleteMessageDetail = createGuard<DeleteMessageDetail>(
|
|
44
|
-
(d) => d.listener === "delete-message",
|
|
45
|
-
);
|
|
46
|
-
export const isDeleteMessagesDetail = createGuard<DeleteMessagesDetail>(
|
|
47
|
-
(d) => d.listener === "delete-messages",
|
|
48
|
-
);
|
|
49
|
-
export const isCommunityGiftPurchaseDetail =
|
|
50
|
-
createGuard<CommunityGiftPurchaseDetail>(
|
|
51
|
-
(d) => d.listener === "event" && d.event?.type === "communityGiftPurchase",
|
|
52
|
-
);
|
|
53
|
-
export const isSubscriberDetail = createGuard<SubscriberDetail>(
|
|
54
|
-
(d) => d.listener === "event" && d.event?.type === "subscriber",
|
|
55
|
-
);
|
|
56
|
-
export const isWidgetButtonDetail = createGuard<WidgetButtonDetail>(
|
|
57
|
-
(d) => d.listener === "event:test" && d.event?.listener === "widget-button",
|
|
58
|
-
);
|
package/src/root/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export * from "./aggregate.js";
|
|
2
|
-
export * from "./classifier.js";
|
|
3
|
-
export * from "./types";
|
|
4
|
-
import "./window-event-map";
|
|
5
|
-
|
|
6
|
-
export * from "./commands";
|
|
7
|
-
export * from "./data";
|
|
8
|
-
export * from "./keys";
|
|
9
|
-
export * from "./message";
|
|
10
|
-
export * from "./queue";
|
|
11
|
-
export * from "./sources/index";
|
package/src/root/keys.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Преобразование fieldId виджета в ключ тестовых данных.
|
|
3
|
-
*/
|
|
4
|
-
export function getTestMessageKey(fieldId: string): string | null {
|
|
5
|
-
if (!fieldId.startsWith("testMessage")) return null;
|
|
6
|
-
const name = fieldId.replace("testMessage", "");
|
|
7
|
-
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function getTestAlertKey(fieldId: string): string | null {
|
|
11
|
-
if (!fieldId.startsWith("testAlert")) return null;
|
|
12
|
-
const name = fieldId.replace("testAlert", "");
|
|
13
|
-
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
14
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./twitch"
|