@overlive/se 0.1.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.
@@ -0,0 +1,42 @@
1
+ import type { RestCapableAdapter, AdapterEventHandler, ConnectionState, SuppressionMap, AdapterStateInfo } from '@overlive/core';
2
+ import { SERestClient } from './SERestClient.js';
3
+ export interface SEAdapterConfig {
4
+ /**
5
+ * StreamElements JWT token.
6
+ * Found at https://streamelements.com/dashboard/account/channels
7
+ */
8
+ jwt: string;
9
+ /**
10
+ * Your StreamElements channel ID.
11
+ */
12
+ channelId: string;
13
+ }
14
+ export declare class SEAdapter implements RestCapableAdapter {
15
+ private readonly config;
16
+ readonly platform: "streamelements";
17
+ readonly displayName = "StreamElements";
18
+ /**
19
+ * When Twitch is present, SE defers on all events it can't own exclusively.
20
+ * Tips/donations are NOT in this list — SE owns those.
21
+ */
22
+ readonly suppressedBy: SuppressionMap;
23
+ private _state;
24
+ private handler;
25
+ private stateHandler;
26
+ private socket;
27
+ readonly rest: SERestClient;
28
+ constructor(config: SEAdapterConfig);
29
+ get state(): ConnectionState;
30
+ onEvent(handler: AdapterEventHandler): void;
31
+ onStateChange(handler: (info: AdapterStateInfo) => void): void;
32
+ connect(): Promise<void>;
33
+ disconnect(): Promise<void>;
34
+ private dispatchSEEvent;
35
+ private normalizeTip;
36
+ private normalizeSub;
37
+ private normalizeRaid;
38
+ private normalizeFollow;
39
+ private normalizeCheer;
40
+ private setState;
41
+ }
42
+ //# sourceMappingURL=SEAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SEAdapter.d.ts","sourceRoot":"","sources":["../src/SEAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,gBAAgB,EAMjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAShD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,SAAU,YAAW,kBAAkB;IA8BtC,OAAO,CAAC,QAAQ,CAAC,MAAM;IA7BnC,QAAQ,CAAC,QAAQ,mBAAW;IAC5B,QAAQ,CAAC,WAAW,oBAAmB;IAEvC;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,cAAc,CAapC;IAED,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,YAAY,CAAkD;IACtE,OAAO,CAAC,MAAM,CAAgB;IAE9B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;gBAEE,MAAM,EAAE,eAAe;IAIpD,IAAI,KAAK,IAAI,eAAe,CAE3B;IAED,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAI3C,aAAa,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI;IAIxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoDxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,QAAQ;CAYjB"}
@@ -0,0 +1,232 @@
1
+ const randomUUID = () => globalThis.crypto.randomUUID();
2
+ import { SERestClient } from './SERestClient.js';
3
+ const PLATFORM = 'streamelements';
4
+ const SE_REALTIME = 'https://realtime.streamelements.com';
5
+ export class SEAdapter {
6
+ config;
7
+ platform = PLATFORM;
8
+ displayName = 'StreamElements';
9
+ /**
10
+ * When Twitch is present, SE defers on all events it can't own exclusively.
11
+ * Tips/donations are NOT in this list — SE owns those.
12
+ */
13
+ suppressedBy = {
14
+ subscription: ['twitch'],
15
+ gift_bomb: ['twitch'],
16
+ raid: ['twitch'],
17
+ follow: ['twitch'],
18
+ ban: ['twitch'],
19
+ 'chat.message': ['twitch'],
20
+ 'chat.command': ['twitch'],
21
+ 'chat.delete': ['twitch'],
22
+ 'ad.start': ['twitch'],
23
+ 'ad.end': ['twitch'],
24
+ 'stream.online': ['twitch'],
25
+ 'stream.offline': ['twitch'],
26
+ };
27
+ _state = 'disconnected';
28
+ handler = null;
29
+ stateHandler = null;
30
+ socket = null;
31
+ rest;
32
+ constructor(config) {
33
+ this.config = config;
34
+ this.rest = new SERestClient(config.jwt, config.channelId);
35
+ }
36
+ get state() {
37
+ return this._state;
38
+ }
39
+ onEvent(handler) {
40
+ this.handler = handler;
41
+ }
42
+ onStateChange(handler) {
43
+ this.stateHandler = handler;
44
+ }
45
+ async connect() {
46
+ this.setState('connecting');
47
+ const { io } = await import('socket.io-client');
48
+ const socket = io(SE_REALTIME, {
49
+ transports: ['websocket'],
50
+ });
51
+ return new Promise((resolve, reject) => {
52
+ socket.on('connect', () => {
53
+ socket.emit('authenticate', {
54
+ method: 'jwt',
55
+ token: this.config.jwt,
56
+ });
57
+ });
58
+ socket.on('authenticated', () => {
59
+ this.setState('connected');
60
+ resolve();
61
+ });
62
+ socket.on('unauthorized', (err) => {
63
+ this.setState('error', { reason: 'token_revoked', message: `SE authentication failed: ${String(err)}` });
64
+ reject(new Error(`SE authentication failed: ${String(err)}`));
65
+ });
66
+ socket.on('disconnect', () => {
67
+ this.setState('disconnected');
68
+ });
69
+ socket.on('reconnecting', () => {
70
+ this.setState('reconnecting');
71
+ });
72
+ socket.on('event', (data) => {
73
+ this.dispatchSEEvent(data);
74
+ });
75
+ socket.on('event:test', (data) => {
76
+ this.dispatchSEEvent(data);
77
+ });
78
+ socket.on('connect_error', (err) => {
79
+ this.setState('error', { reason: 'network', message: err.message });
80
+ reject(err);
81
+ });
82
+ this.socket = socket;
83
+ });
84
+ }
85
+ async disconnect() {
86
+ if (this.socket) {
87
+ ;
88
+ this.socket.disconnect();
89
+ this.socket = null;
90
+ }
91
+ this.setState('disconnected');
92
+ }
93
+ // ─── SE event dispatch ────────────────────────────────────────────────────
94
+ dispatchSEEvent(raw) {
95
+ if (!this.handler)
96
+ return;
97
+ const data = raw;
98
+ const type = String(data['type'] ?? '');
99
+ const channel = this.config.channelId;
100
+ try {
101
+ switch (type) {
102
+ case 'tip':
103
+ this.handler(this.normalizeTip(data, channel));
104
+ break;
105
+ case 'subscriber':
106
+ this.handler(this.normalizeSub(data, channel));
107
+ break;
108
+ case 'raid':
109
+ this.handler(this.normalizeRaid(data, channel));
110
+ break;
111
+ case 'follower':
112
+ this.handler(this.normalizeFollow(data, channel));
113
+ break;
114
+ case 'cheer':
115
+ this.handler(this.normalizeCheer(data, channel));
116
+ break;
117
+ // merch, redemptions etc. can be added as SE exposes them
118
+ }
119
+ }
120
+ catch (e) {
121
+ console.error(`[overlive:se] Error normalizing ${type}:`, e);
122
+ }
123
+ }
124
+ // ─── Normalizers ──────────────────────────────────────────────────────────
125
+ normalizeTip(data, channel) {
126
+ const e = (data['event'] ?? data);
127
+ return {
128
+ id: String(e['_id'] ?? randomUUID()),
129
+ type: 'redemption',
130
+ platform: PLATFORM,
131
+ channel,
132
+ timestamp: new Date(String(e['createdAt'] ?? Date.now())),
133
+ raw: data,
134
+ data: {
135
+ username: String(e['username'] ?? ''),
136
+ displayName: String(e['username'] ?? ''),
137
+ currency: {
138
+ kind: 'tip',
139
+ amount: Number(e['amount'] ?? 0),
140
+ currency: String(e['currency'] ?? 'USD'),
141
+ formattedAmount: String(e['formattedAmount'] ?? `$${e['amount']}`),
142
+ },
143
+ ...(e['message'] ? { message: String(e['message']) } : {}),
144
+ },
145
+ };
146
+ }
147
+ normalizeSub(data, channel) {
148
+ const e = (data['event'] ?? data);
149
+ return {
150
+ id: randomUUID(),
151
+ type: 'subscription',
152
+ platform: PLATFORM,
153
+ channel,
154
+ timestamp: new Date(),
155
+ raw: data,
156
+ data: {
157
+ username: String(e['name'] ?? ''),
158
+ displayName: String(e['displayName'] ?? e['name'] ?? ''),
159
+ tier: 'tier1', // SE doesn't always expose tier
160
+ months: Number(e['amount'] ?? 1),
161
+ isFirst: false,
162
+ isResub: Number(e['amount'] ?? 1) > 1,
163
+ isGift: Boolean(e['gifted']),
164
+ ...(e['sender'] ? { gifter: { username: String(e['sender']), displayName: String(e['sender']) } } : {}),
165
+ ...(e['message'] ? { message: String(e['message']) } : {}),
166
+ },
167
+ };
168
+ }
169
+ normalizeRaid(data, channel) {
170
+ const e = (data['event'] ?? data);
171
+ return {
172
+ id: randomUUID(),
173
+ type: 'raid',
174
+ platform: PLATFORM,
175
+ channel,
176
+ timestamp: new Date(),
177
+ raw: data,
178
+ data: {
179
+ from: {
180
+ username: String(e['name'] ?? ''),
181
+ displayName: String(e['displayName'] ?? e['name'] ?? ''),
182
+ },
183
+ viewerCount: Number(e['amount'] ?? 0),
184
+ },
185
+ };
186
+ }
187
+ normalizeFollow(data, channel) {
188
+ const e = (data['event'] ?? data);
189
+ return {
190
+ id: randomUUID(),
191
+ type: 'follow',
192
+ platform: PLATFORM,
193
+ channel,
194
+ timestamp: new Date(String(e['createdAt'] ?? Date.now())),
195
+ raw: data,
196
+ data: {
197
+ username: String(e['name'] ?? ''),
198
+ displayName: String(e['displayName'] ?? e['name'] ?? ''),
199
+ },
200
+ };
201
+ }
202
+ normalizeCheer(data, channel) {
203
+ const e = (data['event'] ?? data);
204
+ return {
205
+ id: randomUUID(),
206
+ type: 'redemption',
207
+ platform: PLATFORM,
208
+ channel,
209
+ timestamp: new Date(),
210
+ raw: data,
211
+ data: {
212
+ username: String(e['name'] ?? ''),
213
+ displayName: String(e['displayName'] ?? e['name'] ?? ''),
214
+ currency: {
215
+ kind: 'bits',
216
+ amount: Number(e['amount'] ?? 0),
217
+ },
218
+ ...(e['message'] ? { message: String(e['message']) } : {}),
219
+ },
220
+ };
221
+ }
222
+ setState(state, detail) {
223
+ this._state = state;
224
+ const info = {
225
+ state,
226
+ ...(detail?.reason !== undefined && { reason: detail.reason }),
227
+ ...(detail?.message !== undefined && { message: detail.message }),
228
+ };
229
+ this.stateHandler?.(info);
230
+ }
231
+ }
232
+ //# sourceMappingURL=SEAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SEAdapter.js","sourceRoot":"","sources":["../src/SEAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { AdapterRestClient, Platform, TopDonor } from '@overlive/core';
2
+ export declare class SERestClient implements AdapterRestClient {
3
+ private readonly jwt;
4
+ private readonly channelId;
5
+ readonly platform: Platform;
6
+ constructor(jwt: string, channelId: string);
7
+ private get;
8
+ getTopDonors(options?: {
9
+ limit?: number;
10
+ period?: 'session' | 'week' | 'month' | 'alltime';
11
+ }): Promise<TopDonor[]>;
12
+ getSessionData(): Promise<Record<string, unknown>>;
13
+ getUserPoints(username: string): Promise<{
14
+ points: number;
15
+ rank: number;
16
+ } | null>;
17
+ getTopPoints(limit?: number): Promise<Array<{
18
+ username: string;
19
+ points: number;
20
+ rank: number;
21
+ }>>;
22
+ getStoreItems(): Promise<Array<{
23
+ id: string;
24
+ name: string;
25
+ cost: number;
26
+ enabled: boolean;
27
+ }>>;
28
+ }
29
+ //# sourceMappingURL=SERestClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SERestClient.d.ts","sourceRoot":"","sources":["../src/SERestClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAI3E,qBAAa,YAAa,YAAW,iBAAiB;IAIlD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAmB;gBAG3B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM;YAGtB,GAAG;IAiBX,YAAY,CAAC,OAAO,GAAE;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;KAC7C,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBtB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAMlD,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAcjF,YAAY,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAiB5F,aAAa,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAapG"}
@@ -0,0 +1,81 @@
1
+ const SE_API = 'https://api.streamelements.com/kappa/v2';
2
+ export class SERestClient {
3
+ jwt;
4
+ channelId;
5
+ platform = 'streamelements';
6
+ constructor(jwt, channelId) {
7
+ this.jwt = jwt;
8
+ this.channelId = channelId;
9
+ }
10
+ async get(path) {
11
+ const res = await fetch(`${SE_API}${path}`, {
12
+ headers: {
13
+ Authorization: `Bearer ${this.jwt}`,
14
+ Accept: 'application/json',
15
+ },
16
+ });
17
+ if (!res.ok) {
18
+ throw new Error(`SE API error: ${res.status} ${res.statusText} (${path})`);
19
+ }
20
+ return res.json();
21
+ }
22
+ // ─── Top donors ───────────────────────────────────────────────────────────
23
+ async getTopDonors(options = {}) {
24
+ const period = options.period ?? 'alltime';
25
+ const limit = options.limit ?? 10;
26
+ const data = await this.get(`/tips/${this.channelId}/leaderboard?limit=${limit}&period=${period}`);
27
+ return data.docs.map((d) => {
28
+ const doc = d;
29
+ const user = (doc['user'] ?? {});
30
+ return {
31
+ username: String(user['username'] ?? ''),
32
+ displayName: String(user['displayName'] ?? user['username'] ?? ''),
33
+ amount: Number(doc['amount'] ?? 0),
34
+ currency: String(doc['currency'] ?? 'USD'),
35
+ platform: 'streamelements',
36
+ };
37
+ });
38
+ }
39
+ // ─── Session data ─────────────────────────────────────────────────────────
40
+ async getSessionData() {
41
+ return this.get(`/sessions/${this.channelId}`);
42
+ }
43
+ // ─── Points / loyalty ─────────────────────────────────────────────────────
44
+ async getUserPoints(username) {
45
+ try {
46
+ const data = await this.get(`/points/${this.channelId}/${username}`);
47
+ return {
48
+ points: Number(data['points'] ?? 0),
49
+ rank: Number(data['rank'] ?? 0),
50
+ };
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ async getTopPoints(limit = 10) {
57
+ const data = await this.get(`/points/${this.channelId}/top?limit=${limit}`);
58
+ return data.users.map((u, i) => {
59
+ const user = u;
60
+ return {
61
+ username: String(user['username'] ?? ''),
62
+ points: Number(user['points'] ?? 0),
63
+ rank: i + 1,
64
+ };
65
+ });
66
+ }
67
+ // ─── Store / redemptions ──────────────────────────────────────────────────
68
+ async getStoreItems() {
69
+ const data = await this.get(`/store/${this.channelId}/items`);
70
+ return data.items.map((item) => {
71
+ const i = item;
72
+ return {
73
+ id: String(i['_id'] ?? ''),
74
+ name: String(i['name'] ?? ''),
75
+ cost: Number(i['cost'] ?? 0),
76
+ enabled: Boolean(i['enabled']),
77
+ };
78
+ });
79
+ }
80
+ }
81
+ //# sourceMappingURL=SERestClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SERestClient.js","sourceRoot":"","sources":["../src/SERestClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { SEAdapter } from './SEAdapter.js';
2
+ export type { SEAdapterConfig } from './SEAdapter.js';
3
+ export { SERestClient } from './SERestClient.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { SEAdapter } from './SEAdapter.js';
2
+ export { SERestClient } from './SERestClient.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@overlive/se",
3
+ "version": "0.1.0",
4
+ "description": "StreamElements adapter for the Overlive SDK",
5
+ "license": "UNLICENSED",
6
+ "author": "fennsorenn",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/fennsorenn/overlive.git",
10
+ "directory": "packages/se"
11
+ },
12
+ "type": "module",
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.cjs",
20
+ "types": "./dist/index.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "dependencies": {
28
+ "socket.io-client": "^4.7.0",
29
+ "@overlive/core": "0.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.4.0",
33
+ "vitest": "^1.6.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "dev": "tsc -p tsconfig.json --watch",
38
+ "test": "vitest run",
39
+ "test:watch": "vitest",
40
+ "typecheck": "tsc --noEmit",
41
+ "clean": "rm -rf dist"
42
+ }
43
+ }