@interactive-inc/flume 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.
- package/LICENSE +21 -0
- package/README.md +244 -0
- package/dist/discord-source-Q4JRIbNs.js +525 -0
- package/dist/discord.d.ts +24 -0
- package/dist/discord.js +2 -0
- package/dist/github-source-D7Z1RUbe.js +280 -0
- package/dist/github.d.ts +19 -0
- package/dist/github.js +2 -0
- package/dist/index.d.ts +278 -0
- package/dist/index.js +66 -0
- package/dist/logger-B9E8zvgj.js +69 -0
- package/dist/safe-json-parse-D8t_4Vm_.js +81 -0
- package/dist/slack-source-CszepStG.js +400 -0
- package/dist/slack.d.ts +23 -0
- package/dist/slack.js +2 -0
- package/dist/types-BVQSU336.d.ts +112 -0
- package/package.json +77 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { r as FlumeGitHubNotificationSchema, t as FlumeLogger } from "./logger-B9E8zvgj.js";
|
|
2
|
+
//#region lib/github/github-seen-cache.ts
|
|
3
|
+
var FlumeGitHubSeenCache = class {
|
|
4
|
+
props;
|
|
5
|
+
seen = /* @__PURE__ */ new Map();
|
|
6
|
+
constructor(props) {
|
|
7
|
+
this.props = props;
|
|
8
|
+
}
|
|
9
|
+
has(id, updatedAt) {
|
|
10
|
+
return this.seen.get(id) === updatedAt;
|
|
11
|
+
}
|
|
12
|
+
add(id, updatedAt) {
|
|
13
|
+
this.seen.set(id, updatedAt);
|
|
14
|
+
}
|
|
15
|
+
trim() {
|
|
16
|
+
if (this.seen.size <= this.props.maxSize) return;
|
|
17
|
+
const entries = [...this.seen.entries()];
|
|
18
|
+
this.seen = new Map(entries.slice(entries.length - this.props.maxSize));
|
|
19
|
+
}
|
|
20
|
+
get size() {
|
|
21
|
+
return this.seen.size;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region lib/github/github-poller.ts
|
|
26
|
+
var FlumeGitHubPoller = class {
|
|
27
|
+
props;
|
|
28
|
+
log;
|
|
29
|
+
cache = new FlumeGitHubSeenCache({ maxSize: 5e3 });
|
|
30
|
+
timer = null;
|
|
31
|
+
since = null;
|
|
32
|
+
bootstrapped = false;
|
|
33
|
+
stopped = false;
|
|
34
|
+
consecutiveErrors = 0;
|
|
35
|
+
constructor(props) {
|
|
36
|
+
this.props = props;
|
|
37
|
+
this.log = new FlumeLogger({
|
|
38
|
+
source: "github.poller",
|
|
39
|
+
handler: props.onLog,
|
|
40
|
+
deps: props.deps
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async start() {
|
|
44
|
+
this.stopped = false;
|
|
45
|
+
this.log.info({
|
|
46
|
+
action: "start",
|
|
47
|
+
message: `polling every ${this.props.interval}s`
|
|
48
|
+
});
|
|
49
|
+
await this.poll();
|
|
50
|
+
this.timer = this.props.deps.setInterval(() => {
|
|
51
|
+
this.poll().catch((err) => {
|
|
52
|
+
this.log.error({
|
|
53
|
+
action: "poll.unhandled",
|
|
54
|
+
message: "unexpected error in poll loop",
|
|
55
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}, this.props.interval * 1e3);
|
|
59
|
+
}
|
|
60
|
+
stop() {
|
|
61
|
+
this.log.info({
|
|
62
|
+
action: "stop",
|
|
63
|
+
message: "stopping poller"
|
|
64
|
+
});
|
|
65
|
+
this.stopped = true;
|
|
66
|
+
if (this.timer !== null) {
|
|
67
|
+
this.props.deps.clearInterval(this.timer);
|
|
68
|
+
this.timer = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async poll() {
|
|
72
|
+
const params = new URLSearchParams({ all: "false" });
|
|
73
|
+
if (this.since) params.set("since", this.since);
|
|
74
|
+
const url = `https://api.github.com/notifications?${params}`;
|
|
75
|
+
this.log.debug({
|
|
76
|
+
action: "http.request",
|
|
77
|
+
message: `GET ${url}`
|
|
78
|
+
});
|
|
79
|
+
const response = await this.safeFetch(url);
|
|
80
|
+
if (response instanceof Error) return;
|
|
81
|
+
this.log.debug({
|
|
82
|
+
action: "http.response",
|
|
83
|
+
message: `GET ${response.status}`,
|
|
84
|
+
detail: {
|
|
85
|
+
status: response.status,
|
|
86
|
+
url
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
this.consecutiveErrors++;
|
|
91
|
+
this.log.error({
|
|
92
|
+
action: "http.error",
|
|
93
|
+
message: `HTTP ${response.status} (consecutive=${this.consecutiveErrors})`
|
|
94
|
+
});
|
|
95
|
+
if (this.consecutiveErrors >= 3) this.props.onDisconnected(`HTTP ${response.status}`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.consecutiveErrors = 0;
|
|
99
|
+
const body = await response.json();
|
|
100
|
+
if (!Array.isArray(body)) {
|
|
101
|
+
this.log.warn({
|
|
102
|
+
action: "http.body",
|
|
103
|
+
message: "response body is not an array, dropping",
|
|
104
|
+
detail: { bodyType: typeof body }
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.processNotifications(body);
|
|
109
|
+
}
|
|
110
|
+
processNotifications(raw) {
|
|
111
|
+
let dropped = 0;
|
|
112
|
+
const notifications = raw.flatMap((item) => {
|
|
113
|
+
const parsed = FlumeGitHubNotificationSchema.safeParse(item);
|
|
114
|
+
if (!parsed.success) {
|
|
115
|
+
dropped++;
|
|
116
|
+
this.log.warn({
|
|
117
|
+
action: "parse.skip",
|
|
118
|
+
message: "notification did not match schema",
|
|
119
|
+
detail: { issues: parsed.error.issues.map((i) => ({
|
|
120
|
+
path: i.path,
|
|
121
|
+
message: i.message
|
|
122
|
+
})) }
|
|
123
|
+
});
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
return [parsed.data];
|
|
127
|
+
});
|
|
128
|
+
if (dropped > 0) this.log.warn({
|
|
129
|
+
action: "parse.summary",
|
|
130
|
+
message: `${dropped}/${raw.length} notifications dropped by schema`
|
|
131
|
+
});
|
|
132
|
+
if (!this.bootstrapped) {
|
|
133
|
+
this.bootstrapped = true;
|
|
134
|
+
for (const notification of notifications) this.cache.add(notification.id, notification.updated_at);
|
|
135
|
+
this.since = new Date(this.props.deps.now()).toISOString();
|
|
136
|
+
this.log.info({
|
|
137
|
+
action: "bootstrap",
|
|
138
|
+
message: `seeded ${notifications.length} existing notifications`
|
|
139
|
+
});
|
|
140
|
+
this.props.onConnected();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const fresh = [];
|
|
144
|
+
for (const notification of notifications) {
|
|
145
|
+
if (this.cache.has(notification.id, notification.updated_at)) continue;
|
|
146
|
+
this.cache.add(notification.id, notification.updated_at);
|
|
147
|
+
fresh.push(notification);
|
|
148
|
+
}
|
|
149
|
+
this.cache.trim();
|
|
150
|
+
this.since = new Date(this.props.deps.now()).toISOString();
|
|
151
|
+
if (fresh.length > 0) {
|
|
152
|
+
this.log.info({
|
|
153
|
+
action: "poll.fresh",
|
|
154
|
+
message: `${fresh.length} new notifications`
|
|
155
|
+
});
|
|
156
|
+
this.props.onNotifications(fresh);
|
|
157
|
+
} else this.log.debug({
|
|
158
|
+
action: "poll.idle",
|
|
159
|
+
message: "0 new notifications"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
async safeFetch(url) {
|
|
163
|
+
try {
|
|
164
|
+
return await this.props.deps.fetch(url, { headers: {
|
|
165
|
+
Authorization: `Bearer ${this.props.token}`,
|
|
166
|
+
Accept: "application/vnd.github+json",
|
|
167
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
168
|
+
} });
|
|
169
|
+
} catch (error) {
|
|
170
|
+
this.consecutiveErrors++;
|
|
171
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
172
|
+
this.log.error({
|
|
173
|
+
action: "http.error",
|
|
174
|
+
message: `network error (consecutive=${this.consecutiveErrors})`,
|
|
175
|
+
error: err
|
|
176
|
+
});
|
|
177
|
+
if (this.consecutiveErrors >= 3) this.props.onDisconnected("network error");
|
|
178
|
+
return err;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region lib/github/github-source.ts
|
|
184
|
+
var FlumeGitHubSource = class FlumeGitHubSource {
|
|
185
|
+
options;
|
|
186
|
+
poller = null;
|
|
187
|
+
currentStatus = "disconnected";
|
|
188
|
+
log;
|
|
189
|
+
deps;
|
|
190
|
+
constructor(options) {
|
|
191
|
+
this.options = options;
|
|
192
|
+
this.deps = options.deps;
|
|
193
|
+
this.log = new FlumeLogger({
|
|
194
|
+
source: "github",
|
|
195
|
+
handler: options.onLog,
|
|
196
|
+
deps: this.deps
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
async start(handler) {
|
|
200
|
+
if (this.options.signal?.aborted) return;
|
|
201
|
+
this.options.signal?.addEventListener("abort", () => this.stop(), { once: true });
|
|
202
|
+
this.log.info({
|
|
203
|
+
action: "start",
|
|
204
|
+
message: "starting GitHub source"
|
|
205
|
+
});
|
|
206
|
+
this.setStatus("connecting");
|
|
207
|
+
this.poller = new FlumeGitHubPoller({
|
|
208
|
+
token: this.options.token,
|
|
209
|
+
interval: this.options.pollInterval ?? 60,
|
|
210
|
+
onLog: this.options.onLog,
|
|
211
|
+
deps: this.deps,
|
|
212
|
+
onNotifications: (notifications) => this.handleNotifications(handler, notifications),
|
|
213
|
+
onConnected: () => this.setStatus("connected"),
|
|
214
|
+
onDisconnected: (detail) => this.setStatus("disconnected", detail)
|
|
215
|
+
});
|
|
216
|
+
try {
|
|
217
|
+
await this.poller.start();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
220
|
+
this.log.error({
|
|
221
|
+
action: "start.failed",
|
|
222
|
+
message: err.message,
|
|
223
|
+
error: err
|
|
224
|
+
});
|
|
225
|
+
this.setStatus("disconnected");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async stop() {
|
|
229
|
+
this.log.info({
|
|
230
|
+
action: "stop",
|
|
231
|
+
message: "stopping GitHub source"
|
|
232
|
+
});
|
|
233
|
+
this.poller?.stop();
|
|
234
|
+
this.poller = null;
|
|
235
|
+
this.setStatus("disconnected");
|
|
236
|
+
}
|
|
237
|
+
status() {
|
|
238
|
+
return this.currentStatus;
|
|
239
|
+
}
|
|
240
|
+
handleNotifications(handler, notifications) {
|
|
241
|
+
for (const notification of notifications) {
|
|
242
|
+
const event = {
|
|
243
|
+
source: "github",
|
|
244
|
+
type: "notification",
|
|
245
|
+
data: notification,
|
|
246
|
+
meta: FlumeGitHubSource.extractMeta(notification),
|
|
247
|
+
receivedAt: this.deps.now()
|
|
248
|
+
};
|
|
249
|
+
try {
|
|
250
|
+
handler(event);
|
|
251
|
+
} catch (err) {
|
|
252
|
+
this.log.error({
|
|
253
|
+
action: "handler.error",
|
|
254
|
+
message: "user handler threw",
|
|
255
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
setStatus(next, detail) {
|
|
261
|
+
if (this.currentStatus === next) return;
|
|
262
|
+
this.log.info({
|
|
263
|
+
action: "status",
|
|
264
|
+
message: `${this.currentStatus} → ${next}${detail ? ` (${detail})` : ""}`
|
|
265
|
+
});
|
|
266
|
+
this.currentStatus = next;
|
|
267
|
+
this.options.onStatus?.(next, detail);
|
|
268
|
+
}
|
|
269
|
+
static extractMeta(notification) {
|
|
270
|
+
return {
|
|
271
|
+
event_type: "notification",
|
|
272
|
+
reason: notification.reason,
|
|
273
|
+
subject_type: notification.subject.type,
|
|
274
|
+
repository: notification.repository.full_name,
|
|
275
|
+
thread_id: notification.id
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
//#endregion
|
|
280
|
+
export { FlumeGitHubPoller as n, FlumeGitHubSeenCache as r, FlumeGitHubSource as t };
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { a as FlumeGitHubSourceOptions, i as FlumeGitHubNotification, o as FlumeHandler, y as FlumeStatus } from "./types-BVQSU336.js";
|
|
2
|
+
|
|
3
|
+
//#region lib/github/github-source.d.ts
|
|
4
|
+
declare class FlumeGitHubSource {
|
|
5
|
+
private readonly options;
|
|
6
|
+
private poller;
|
|
7
|
+
private currentStatus;
|
|
8
|
+
private readonly log;
|
|
9
|
+
private readonly deps;
|
|
10
|
+
constructor(options: FlumeGitHubSourceOptions);
|
|
11
|
+
start(handler: FlumeHandler): Promise<void>;
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
status(): FlumeStatus;
|
|
14
|
+
private handleNotifications;
|
|
15
|
+
private setStatus;
|
|
16
|
+
static extractMeta(notification: FlumeGitHubNotification): Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { FlumeGitHubSource };
|
package/dist/github.js
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { C as FlumeGitHubNotificationSchema, S as FlumeGatewayMessageSchema, T as FlumeSlackEnvelopeSchema, _ as FlumeSourceName, a as FlumeGitHubSourceOptions, b as FlumeStatusHandler, c as FlumeLogHandler, d as FlumeReconnectConfig, f as FlumeReconnectOptions, g as FlumeSlackSourceOptions, h as FlumeSlackEnvelope, i as FlumeGitHubNotification, l as FlumeLogInput, m as FlumeSlackConnectionResponse, n as FlumeEvent, o as FlumeHandler, p as FlumeRuntimeDeps, r as FlumeGatewayMessage, s as FlumeLog, t as FlumeDiscordSourceOptions, u as FlumeLogLevel, v as FlumeSourceOptions, w as FlumeSlackConnectionResponseSchema, x as FlumeTimerHandle, y as FlumeStatus } from "./types-BVQSU336.js";
|
|
2
|
+
import { FlumeDiscordSource } from "./discord.js";
|
|
3
|
+
import { FlumeGitHubSource } from "./github.js";
|
|
4
|
+
import { FlumeSlackSource } from "./slack.js";
|
|
5
|
+
|
|
6
|
+
//#region lib/deps.d.ts
|
|
7
|
+
declare function createFlumeDefaultDeps(): FlumeRuntimeDeps;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region lib/errors/connection-error.d.ts
|
|
10
|
+
declare class FlumeConnectionError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region lib/errors/http-error.d.ts
|
|
15
|
+
type Props$10 = {
|
|
16
|
+
message: string;
|
|
17
|
+
status: number;
|
|
18
|
+
};
|
|
19
|
+
declare class FlumeHttpError extends Error {
|
|
20
|
+
readonly status: number;
|
|
21
|
+
constructor(props: Props$10);
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region lib/errors/parse-error.d.ts
|
|
25
|
+
declare class FlumeParseError extends Error {
|
|
26
|
+
constructor(message: string);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region lib/logger.d.ts
|
|
30
|
+
type Props$9 = {
|
|
31
|
+
source: string;
|
|
32
|
+
handler?: FlumeLogHandler;
|
|
33
|
+
deps: Pick<FlumeRuntimeDeps, "now">;
|
|
34
|
+
};
|
|
35
|
+
declare class FlumeLogger {
|
|
36
|
+
private readonly props;
|
|
37
|
+
constructor(props: Props$9);
|
|
38
|
+
debug(entry: FlumeLogInput): void;
|
|
39
|
+
info(entry: FlumeLogInput): void;
|
|
40
|
+
warn(entry: FlumeLogInput): void;
|
|
41
|
+
error(entry: FlumeLogInput): void;
|
|
42
|
+
private emit;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region lib/reconnect-config.d.ts
|
|
46
|
+
declare function resolveFlumeReconnectConfig(input: boolean | FlumeReconnectOptions | undefined): FlumeReconnectConfig | null;
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region lib/reconnector.d.ts
|
|
49
|
+
type Props$8 = {
|
|
50
|
+
maxAttempts: number;
|
|
51
|
+
baseDelay: number;
|
|
52
|
+
maxDelay: number;
|
|
53
|
+
deps: Pick<FlumeRuntimeDeps, "setTimeout" | "clearTimeout" | "random">;
|
|
54
|
+
};
|
|
55
|
+
declare class FlumeReconnector {
|
|
56
|
+
private readonly props;
|
|
57
|
+
attempt: number;
|
|
58
|
+
aborted: boolean;
|
|
59
|
+
private timer;
|
|
60
|
+
constructor(props: Props$8);
|
|
61
|
+
schedule(fn: () => void): number;
|
|
62
|
+
reset(): void;
|
|
63
|
+
cancel(): void;
|
|
64
|
+
private nextDelay;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region lib/flume.d.ts
|
|
68
|
+
type Props$7 = {
|
|
69
|
+
onLog?: FlumeLogHandler;
|
|
70
|
+
onStatus?: FlumeStatusHandler;
|
|
71
|
+
reconnect?: boolean | FlumeReconnectOptions;
|
|
72
|
+
signal?: AbortSignal;
|
|
73
|
+
deps?: Partial<FlumeRuntimeDeps>;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* 共有設定を持つ DI コンテナ。各 Source に共通の deps / logging / reconnect を注入する
|
|
77
|
+
*/
|
|
78
|
+
declare class Flume {
|
|
79
|
+
private readonly props;
|
|
80
|
+
private readonly resolvedDeps;
|
|
81
|
+
constructor(props: Props$7);
|
|
82
|
+
discord(options: {
|
|
83
|
+
token: string;
|
|
84
|
+
intents?: number;
|
|
85
|
+
}): FlumeDiscordSource;
|
|
86
|
+
slack(options: {
|
|
87
|
+
appToken: string;
|
|
88
|
+
botToken?: string;
|
|
89
|
+
}): FlumeSlackSource;
|
|
90
|
+
github(options: {
|
|
91
|
+
token: string;
|
|
92
|
+
pollInterval?: number;
|
|
93
|
+
}): FlumeGitHubSource;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region lib/discord/discord-gateway-intents.d.ts
|
|
97
|
+
declare const FlumeDiscordGatewayIntents: {
|
|
98
|
+
readonly Guilds: number;
|
|
99
|
+
readonly GuildMembers: number;
|
|
100
|
+
readonly GuildModeration: number;
|
|
101
|
+
readonly GuildExpressions: number;
|
|
102
|
+
readonly GuildIntegrations: number;
|
|
103
|
+
readonly GuildWebhooks: number;
|
|
104
|
+
readonly GuildInvites: number;
|
|
105
|
+
readonly GuildVoiceStates: number;
|
|
106
|
+
readonly GuildPresences: number;
|
|
107
|
+
readonly GuildMessages: number;
|
|
108
|
+
readonly GuildMessageReactions: number;
|
|
109
|
+
readonly GuildMessageTyping: number;
|
|
110
|
+
readonly DirectMessages: number;
|
|
111
|
+
readonly DirectMessageReactions: number;
|
|
112
|
+
readonly DirectMessageTyping: number;
|
|
113
|
+
readonly MessageContent: number;
|
|
114
|
+
readonly GuildScheduledEvents: number;
|
|
115
|
+
readonly AutoModerationConfiguration: number;
|
|
116
|
+
readonly AutoModerationExecution: number;
|
|
117
|
+
readonly GuildMessagePolls: number;
|
|
118
|
+
readonly DirectMessagePolls: number;
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region lib/discord/discord-gateway-session.d.ts
|
|
122
|
+
type Props$6 = {
|
|
123
|
+
sessionId: string | null;
|
|
124
|
+
resumeUrl: string | null;
|
|
125
|
+
seq: number | null;
|
|
126
|
+
};
|
|
127
|
+
declare class FlumeDiscordGatewaySession {
|
|
128
|
+
readonly sessionId: string | null;
|
|
129
|
+
readonly resumeUrl: string | null;
|
|
130
|
+
readonly seq: number | null;
|
|
131
|
+
constructor(props: Props$6);
|
|
132
|
+
static empty(): FlumeDiscordGatewaySession;
|
|
133
|
+
canResume(): boolean;
|
|
134
|
+
withSeq(seq: number): FlumeDiscordGatewaySession;
|
|
135
|
+
withReady(sessionId: string, resumeUrl: string): FlumeDiscordGatewaySession;
|
|
136
|
+
withReset(): FlumeDiscordGatewaySession;
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region lib/discord/discord-gateway.d.ts
|
|
140
|
+
type Deps$2 = Pick<FlumeRuntimeDeps, "WebSocket" | "setInterval" | "clearInterval" | "setTimeout" | "random" | "now">;
|
|
141
|
+
type Props$5 = {
|
|
142
|
+
token: string;
|
|
143
|
+
intents: number;
|
|
144
|
+
onDispatch: (event: string, data: Record<string, unknown>) => void;
|
|
145
|
+
onStatus: (status: "connected" | "disconnected") => void;
|
|
146
|
+
onLog?: FlumeLogHandler;
|
|
147
|
+
deps: Deps$2;
|
|
148
|
+
};
|
|
149
|
+
declare class FlumeDiscordGateway {
|
|
150
|
+
private readonly props;
|
|
151
|
+
private readonly log;
|
|
152
|
+
private ws;
|
|
153
|
+
private heartbeat;
|
|
154
|
+
session: FlumeDiscordGatewaySession;
|
|
155
|
+
stopped: boolean;
|
|
156
|
+
private pendingResolve;
|
|
157
|
+
private pendingResolved;
|
|
158
|
+
constructor(props: Props$5);
|
|
159
|
+
connect(url?: string): Promise<FlumeConnectionError | null>;
|
|
160
|
+
disconnect(): void;
|
|
161
|
+
isConnected(): boolean;
|
|
162
|
+
private completeConnect;
|
|
163
|
+
private onMessage;
|
|
164
|
+
private onHello;
|
|
165
|
+
private onHeartbeatAck;
|
|
166
|
+
private onHeartbeatRequest;
|
|
167
|
+
private onReconnectRequest;
|
|
168
|
+
private onInvalidSession;
|
|
169
|
+
private onDispatch;
|
|
170
|
+
private onClose;
|
|
171
|
+
private onError;
|
|
172
|
+
private send;
|
|
173
|
+
private sendIdentify;
|
|
174
|
+
private sendResume;
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region lib/discord/discord-heartbeat.d.ts
|
|
178
|
+
type Props$4 = {
|
|
179
|
+
onSend: () => void;
|
|
180
|
+
onZombie: () => void;
|
|
181
|
+
deps: Pick<FlumeRuntimeDeps, "setInterval" | "clearInterval">;
|
|
182
|
+
};
|
|
183
|
+
declare class FlumeDiscordHeartbeat {
|
|
184
|
+
private readonly props;
|
|
185
|
+
private timer;
|
|
186
|
+
private ackReceived;
|
|
187
|
+
constructor(props: Props$4);
|
|
188
|
+
start(intervalMs: number): void;
|
|
189
|
+
stop(): void;
|
|
190
|
+
ack(): void;
|
|
191
|
+
isRunning(): boolean;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region lib/discord/parse-discord-gateway-message.d.ts
|
|
195
|
+
declare function parseDiscordGatewayMessage(raw: string): FlumeGatewayMessage | FlumeParseError;
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region lib/slack/slack-socket-mode.d.ts
|
|
198
|
+
type Deps$1 = Pick<FlumeRuntimeDeps, "WebSocket" | "fetch" | "now">;
|
|
199
|
+
type Props$3 = {
|
|
200
|
+
appToken: string;
|
|
201
|
+
onMessage: (envelope: FlumeSlackEnvelope) => void;
|
|
202
|
+
onConnected: () => void;
|
|
203
|
+
onDisconnected: () => void;
|
|
204
|
+
onLog?: FlumeLogHandler;
|
|
205
|
+
deps: Deps$1;
|
|
206
|
+
};
|
|
207
|
+
declare class FlumeSlackSocketMode {
|
|
208
|
+
private readonly props;
|
|
209
|
+
private readonly log;
|
|
210
|
+
private ws;
|
|
211
|
+
stopped: boolean;
|
|
212
|
+
private pendingResolve;
|
|
213
|
+
private pendingResolved;
|
|
214
|
+
constructor(props: Props$3);
|
|
215
|
+
connect(): Promise<FlumeConnectionError | FlumeHttpError | null>;
|
|
216
|
+
disconnect(): void;
|
|
217
|
+
isConnected(): boolean;
|
|
218
|
+
private openSocket;
|
|
219
|
+
private completeConnect;
|
|
220
|
+
private onMessage;
|
|
221
|
+
private onClose;
|
|
222
|
+
private onError;
|
|
223
|
+
}
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region lib/slack/obtain-slack-url.d.ts
|
|
226
|
+
type Props$2 = {
|
|
227
|
+
appToken: string;
|
|
228
|
+
onLog?: FlumeLogHandler;
|
|
229
|
+
deps: Pick<FlumeRuntimeDeps, "fetch" | "now">;
|
|
230
|
+
};
|
|
231
|
+
declare function obtainSlackUrl(props: Props$2): Promise<string | FlumeHttpError>;
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region lib/github/github-poller.d.ts
|
|
234
|
+
type Deps = Pick<FlumeRuntimeDeps, "fetch" | "setInterval" | "clearInterval" | "now">;
|
|
235
|
+
type Props$1 = {
|
|
236
|
+
token: string;
|
|
237
|
+
interval: number;
|
|
238
|
+
onNotifications: (notifications: FlumeGitHubNotification[]) => void;
|
|
239
|
+
onConnected: () => void;
|
|
240
|
+
onDisconnected: (detail: string) => void;
|
|
241
|
+
onLog?: FlumeLogHandler;
|
|
242
|
+
deps: Deps;
|
|
243
|
+
};
|
|
244
|
+
declare class FlumeGitHubPoller {
|
|
245
|
+
private readonly props;
|
|
246
|
+
private readonly log;
|
|
247
|
+
private readonly cache;
|
|
248
|
+
private timer;
|
|
249
|
+
private since;
|
|
250
|
+
private bootstrapped;
|
|
251
|
+
stopped: boolean;
|
|
252
|
+
private consecutiveErrors;
|
|
253
|
+
constructor(props: Props$1);
|
|
254
|
+
start(): Promise<void>;
|
|
255
|
+
stop(): void;
|
|
256
|
+
private poll;
|
|
257
|
+
private processNotifications;
|
|
258
|
+
private safeFetch;
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region lib/github/github-seen-cache.d.ts
|
|
262
|
+
type Props = {
|
|
263
|
+
maxSize: number;
|
|
264
|
+
};
|
|
265
|
+
declare class FlumeGitHubSeenCache {
|
|
266
|
+
private readonly props;
|
|
267
|
+
private seen;
|
|
268
|
+
constructor(props: Props);
|
|
269
|
+
has(id: string, updatedAt: string): boolean;
|
|
270
|
+
add(id: string, updatedAt: string): void;
|
|
271
|
+
trim(): void;
|
|
272
|
+
get size(): number;
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region lib/index.d.ts
|
|
276
|
+
type FlumeSource = FlumeDiscordSource | FlumeSlackSource | FlumeGitHubSource;
|
|
277
|
+
//#endregion
|
|
278
|
+
export { Flume, FlumeConnectionError, FlumeDiscordGateway, FlumeDiscordGatewayIntents, FlumeDiscordGatewaySession, FlumeDiscordHeartbeat, FlumeDiscordSource, type FlumeDiscordSourceOptions, type FlumeEvent, type FlumeGatewayMessage, FlumeGatewayMessageSchema, type FlumeGitHubNotification, FlumeGitHubNotificationSchema, FlumeGitHubPoller, FlumeGitHubSeenCache, FlumeGitHubSource, type FlumeGitHubSourceOptions, type FlumeHandler, FlumeHttpError, type FlumeLog, type FlumeLogHandler, type FlumeLogInput, type FlumeLogLevel, FlumeLogger, FlumeParseError, type FlumeReconnectConfig, type FlumeReconnectOptions, FlumeReconnector, type FlumeRuntimeDeps, type FlumeSlackConnectionResponse, FlumeSlackConnectionResponseSchema, type FlumeSlackEnvelope, FlumeSlackEnvelopeSchema, FlumeSlackSocketMode, FlumeSlackSource, type FlumeSlackSourceOptions, FlumeSource, type FlumeSourceName, type FlumeSourceOptions, type FlumeStatus, type FlumeStatusHandler, type FlumeTimerHandle, createFlumeDefaultDeps, obtainSlackUrl, parseDiscordGatewayMessage, resolveFlumeReconnectConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { a as FlumeSlackEnvelopeSchema, i as FlumeSlackConnectionResponseSchema, n as FlumeGatewayMessageSchema, r as FlumeGitHubNotificationSchema, t as FlumeLogger } from "./logger-B9E8zvgj.js";
|
|
2
|
+
import { a as FlumeParseError, i as resolveFlumeReconnectConfig, o as FlumeConnectionError, r as FlumeReconnector } from "./safe-json-parse-D8t_4Vm_.js";
|
|
3
|
+
import { i as FlumeHttpError, n as FlumeSlackSocketMode, r as obtainSlackUrl, t as FlumeSlackSource } from "./slack-source-CszepStG.js";
|
|
4
|
+
import { a as FlumeDiscordGatewaySession, i as parseDiscordGatewayMessage, n as FlumeDiscordGatewayIntents, o as FlumeDiscordHeartbeat, r as FlumeDiscordGateway, t as FlumeDiscordSource } from "./discord-source-Q4JRIbNs.js";
|
|
5
|
+
import { n as FlumeGitHubPoller, r as FlumeGitHubSeenCache, t as FlumeGitHubSource } from "./github-source-D7Z1RUbe.js";
|
|
6
|
+
//#region lib/deps.ts
|
|
7
|
+
function createFlumeDefaultDeps() {
|
|
8
|
+
return {
|
|
9
|
+
fetch: (url, init) => globalThis.fetch(url, init),
|
|
10
|
+
WebSocket: globalThis.WebSocket,
|
|
11
|
+
now: () => Date.now(),
|
|
12
|
+
random: () => Math.random(),
|
|
13
|
+
setTimeout: (fn, ms) => globalThis.setTimeout(fn, ms),
|
|
14
|
+
clearTimeout: (id) => globalThis.clearTimeout(id),
|
|
15
|
+
setInterval: (fn, ms) => globalThis.setInterval(fn, ms),
|
|
16
|
+
clearInterval: (id) => globalThis.clearInterval(id)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region lib/flume.ts
|
|
21
|
+
/**
|
|
22
|
+
* 共有設定を持つ DI コンテナ。各 Source に共通の deps / logging / reconnect を注入する
|
|
23
|
+
*/
|
|
24
|
+
var Flume = class {
|
|
25
|
+
props;
|
|
26
|
+
resolvedDeps;
|
|
27
|
+
constructor(props) {
|
|
28
|
+
this.props = props;
|
|
29
|
+
this.resolvedDeps = {
|
|
30
|
+
...createFlumeDefaultDeps(),
|
|
31
|
+
...props.deps
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
discord(options) {
|
|
35
|
+
return new FlumeDiscordSource({
|
|
36
|
+
onLog: this.props.onLog,
|
|
37
|
+
onStatus: this.props.onStatus,
|
|
38
|
+
reconnect: this.props.reconnect,
|
|
39
|
+
signal: this.props.signal,
|
|
40
|
+
deps: this.resolvedDeps,
|
|
41
|
+
...options
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
slack(options) {
|
|
45
|
+
return new FlumeSlackSource({
|
|
46
|
+
onLog: this.props.onLog,
|
|
47
|
+
onStatus: this.props.onStatus,
|
|
48
|
+
reconnect: this.props.reconnect,
|
|
49
|
+
signal: this.props.signal,
|
|
50
|
+
deps: this.resolvedDeps,
|
|
51
|
+
...options
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
github(options) {
|
|
55
|
+
return new FlumeGitHubSource({
|
|
56
|
+
onLog: this.props.onLog,
|
|
57
|
+
onStatus: this.props.onStatus,
|
|
58
|
+
reconnect: this.props.reconnect,
|
|
59
|
+
signal: this.props.signal,
|
|
60
|
+
deps: this.resolvedDeps,
|
|
61
|
+
...options
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
export { Flume, FlumeConnectionError, FlumeDiscordGateway, FlumeDiscordGatewayIntents, FlumeDiscordGatewaySession, FlumeDiscordHeartbeat, FlumeDiscordSource, FlumeGatewayMessageSchema, FlumeGitHubNotificationSchema, FlumeGitHubPoller, FlumeGitHubSeenCache, FlumeGitHubSource, FlumeHttpError, FlumeLogger, FlumeParseError, FlumeReconnector, FlumeSlackConnectionResponseSchema, FlumeSlackEnvelopeSchema, FlumeSlackSocketMode, FlumeSlackSource, createFlumeDefaultDeps, obtainSlackUrl, parseDiscordGatewayMessage, resolveFlumeReconnectConfig };
|