@interactive-inc/flume 0.3.0 → 0.4.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 +67 -53
- package/dist/connection-error-HUO3PC3G.js +16 -0
- package/dist/discord.d.ts +10 -85
- package/dist/discord.js +473 -183
- package/dist/github.d.ts +9 -48
- package/dist/github.js +391 -135
- package/dist/{http-error-BtXonO-W.js → http-error-CPSKoSie.js} +1 -1
- package/dist/index.d.ts +76 -34
- package/dist/index.js +225 -57
- package/dist/safe-invoke-callback-EpWXwfwp.js +170 -0
- package/dist/safe-read-text-DgrJ4Uhl.js +20 -0
- package/dist/safe-stringify-BWS-uXZP.js +172 -0
- package/dist/serial-queue-B9LoBc64.js +162 -0
- package/dist/slack.d.ts +10 -62
- package/dist/slack.js +376 -139
- package/dist/{types-Bm9uKUQz.d.ts → types-D-tO-Mh2.d.ts} +32 -21
- package/package.json +21 -18
- package/dist/connection-error-BOk97djj.d.ts +0 -6
- package/dist/http-error-K-Ym4lfK.d.ts +0 -11
- package/dist/logger-CpGB9WO_.js +0 -49
- package/dist/parse-error-BAiCLRmk.d.ts +0 -6
- package/dist/reconnector-BDoJ1xNX.js +0 -67
- package/dist/safe-fetch-30ZzOKHL.js +0 -20
- package/dist/safe-json-parse-BWlzGOLl.js +0 -41
- package/dist/serial-queue-ExmlnpzQ.js +0 -16
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { l as safeErrorMessage } from "./safe-invoke-callback-EpWXwfwp.js";
|
|
2
|
+
import { t as FlumeHttpError } from "./http-error-CPSKoSie.js";
|
|
3
|
+
//#region lib/utils/safe-read-text.ts
|
|
4
|
+
/**
|
|
5
|
+
* `response.text()` を保護する。body 読み取り中の reject (接続切断 / 解凍失敗 / 二重消費) を
|
|
6
|
+
* `FlumeHttpError` (status / cause 保持) に変換する。log には書かない (呼び出し側で書く)
|
|
7
|
+
*/
|
|
8
|
+
async function safeReadText(props) {
|
|
9
|
+
try {
|
|
10
|
+
return await props.response.text();
|
|
11
|
+
} catch (err) {
|
|
12
|
+
return new FlumeHttpError({
|
|
13
|
+
message: `${props.context}: failed to read body: ${safeErrorMessage({ error: err })}`,
|
|
14
|
+
status: props.response.status,
|
|
15
|
+
cause: err
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { safeReadText as t };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { l as safeErrorMessage, s as attempt, t as safeInvokeCallback } from "./safe-invoke-callback-EpWXwfwp.js";
|
|
2
|
+
import { t as FlumeConnectionError } from "./connection-error-HUO3PC3G.js";
|
|
3
|
+
//#region lib/utils/safe-random.ts
|
|
4
|
+
/**
|
|
5
|
+
* `deps.random()` を保護する。throw / 範囲外値 / 非数値が返った場合は 0.5 を返す。
|
|
6
|
+
* 0 以上 1 未満 (Math.random と同等) の値のみそのまま透過
|
|
7
|
+
*/
|
|
8
|
+
function safeRandom(props) {
|
|
9
|
+
try {
|
|
10
|
+
const value = props.deps.random();
|
|
11
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return .5;
|
|
12
|
+
if (value < 0 || value >= 1) return .5;
|
|
13
|
+
return value;
|
|
14
|
+
} catch {
|
|
15
|
+
return .5;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region lib/reconnector.ts
|
|
20
|
+
/**
|
|
21
|
+
* 指数バックオフ + ジッタ付きの再接続スケジューラ。
|
|
22
|
+
* `schedule()` の戻り値: 正の delay = 予約成功 / -1 = 試行上限到達 / 0 = cancel 済み or 内部 timer 拒否。
|
|
23
|
+
* setTimeout コールバック内のユーザー fn が throw / reject しても reconnect ループは止めない
|
|
24
|
+
*/
|
|
25
|
+
var FlumeReconnector = class {
|
|
26
|
+
props;
|
|
27
|
+
currentAttempt = 0;
|
|
28
|
+
isAborted = false;
|
|
29
|
+
timer = null;
|
|
30
|
+
constructor(props) {
|
|
31
|
+
this.props = props;
|
|
32
|
+
}
|
|
33
|
+
get attempt() {
|
|
34
|
+
return this.currentAttempt;
|
|
35
|
+
}
|
|
36
|
+
get aborted() {
|
|
37
|
+
return this.isAborted;
|
|
38
|
+
}
|
|
39
|
+
schedule(fn) {
|
|
40
|
+
if (this.isAborted) return 0;
|
|
41
|
+
if (this.currentAttempt >= this.props.maxAttempts) return -1;
|
|
42
|
+
this.clearTimer();
|
|
43
|
+
const delay = this.nextDelay();
|
|
44
|
+
const timerResult = attempt(() => this.props.deps.setTimeout(() => this.runRetry(fn), delay));
|
|
45
|
+
if (timerResult instanceof Error) {
|
|
46
|
+
this.props.log.error({
|
|
47
|
+
action: "reconnect.timer.schedule.error",
|
|
48
|
+
message: safeErrorMessage({ error: timerResult }),
|
|
49
|
+
error: timerResult
|
|
50
|
+
});
|
|
51
|
+
this.timer = null;
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
this.timer = timerResult;
|
|
55
|
+
return delay;
|
|
56
|
+
}
|
|
57
|
+
reset() {
|
|
58
|
+
this.currentAttempt = 0;
|
|
59
|
+
}
|
|
60
|
+
cancel() {
|
|
61
|
+
this.isAborted = true;
|
|
62
|
+
this.clearTimer();
|
|
63
|
+
}
|
|
64
|
+
runRetry(fn) {
|
|
65
|
+
this.timer = null;
|
|
66
|
+
safeInvokeCallback({
|
|
67
|
+
fn,
|
|
68
|
+
onError: (error) => {
|
|
69
|
+
this.props.log.error({
|
|
70
|
+
action: "reconnect.timer.error",
|
|
71
|
+
message: safeErrorMessage({ error }),
|
|
72
|
+
error
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
clearTimer() {
|
|
78
|
+
if (this.timer === null) return;
|
|
79
|
+
const handle = this.timer;
|
|
80
|
+
const result = attempt(() => this.props.deps.clearTimeout(handle));
|
|
81
|
+
if (result instanceof Error) this.props.log.error({
|
|
82
|
+
action: "reconnect.timer.clear.error",
|
|
83
|
+
message: safeErrorMessage({ error: result }),
|
|
84
|
+
error: result
|
|
85
|
+
});
|
|
86
|
+
this.timer = null;
|
|
87
|
+
}
|
|
88
|
+
nextDelay() {
|
|
89
|
+
const jitter = Math.min(this.props.baseDelay * 2 ** this.currentAttempt, this.props.maxDelay) * (.5 + safeRandom({ deps: this.props.deps }) * .5);
|
|
90
|
+
this.currentAttempt++;
|
|
91
|
+
return jitter;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region lib/reconnect-config.ts
|
|
96
|
+
const DEFAULTS = {
|
|
97
|
+
maxAttempts: Infinity,
|
|
98
|
+
baseDelay: 1e3,
|
|
99
|
+
maxDelay: 3e4
|
|
100
|
+
};
|
|
101
|
+
function resolveFlumeReconnectConfig(input) {
|
|
102
|
+
if (input === false || input === void 0) return null;
|
|
103
|
+
if (input === true) return { ...DEFAULTS };
|
|
104
|
+
return {
|
|
105
|
+
...DEFAULTS,
|
|
106
|
+
...input
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region lib/schedule-reconnect.ts
|
|
111
|
+
/**
|
|
112
|
+
* 接続が落ちた際の共通再接続スケジューラ。
|
|
113
|
+
* 再接続の設定状況 (無効 / 中止 / 試行尽き) を見極めてからステータス遷移する。
|
|
114
|
+
* - reconnector が無ければ reconnect.disabled を info ログし disconnected へ
|
|
115
|
+
* - cancel 済みなら reconnect.aborted を info ログし disconnected へ
|
|
116
|
+
* - schedule() が -1 を返したら reconnect.exhausted を error ログし disconnected へ
|
|
117
|
+
* - それ以外は reconnecting へ遷移し reconnect.scheduled を info ログ
|
|
118
|
+
*/
|
|
119
|
+
function scheduleFlumeReconnect(props) {
|
|
120
|
+
if (!props.reconnector) {
|
|
121
|
+
props.log.info({
|
|
122
|
+
action: "reconnect.disabled",
|
|
123
|
+
message: "reconnect is disabled, staying disconnected"
|
|
124
|
+
});
|
|
125
|
+
props.setStatus("disconnected");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (props.reconnector.aborted) {
|
|
129
|
+
props.log.info({
|
|
130
|
+
action: "reconnect.aborted",
|
|
131
|
+
message: "reconnector cancelled, staying disconnected"
|
|
132
|
+
});
|
|
133
|
+
props.setStatus("disconnected");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const delay = props.reconnector.schedule(props.retry);
|
|
137
|
+
if (delay === -1) {
|
|
138
|
+
const error = new FlumeConnectionError(`reconnect exhausted after ${props.reconnector.attempt} attempts`);
|
|
139
|
+
props.log.error({
|
|
140
|
+
action: "reconnect.exhausted",
|
|
141
|
+
message: safeErrorMessage({ error }),
|
|
142
|
+
error
|
|
143
|
+
});
|
|
144
|
+
props.setStatus("disconnected");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
props.setStatus("reconnecting");
|
|
148
|
+
props.log.info({
|
|
149
|
+
action: "reconnect.scheduled",
|
|
150
|
+
message: `next attempt in ${Math.round(delay)}ms`,
|
|
151
|
+
detail: {
|
|
152
|
+
attempt: props.reconnector.attempt,
|
|
153
|
+
delayMs: Math.round(delay)
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region lib/utils/is-record.ts
|
|
159
|
+
function isRecord(value) {
|
|
160
|
+
return typeof value === "object" && value !== null;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region lib/utils/safe-stringify.ts
|
|
164
|
+
/**
|
|
165
|
+
* `JSON.stringify` を `string | Error` に変換するだけのラッパ。
|
|
166
|
+
* cyclic / BigInt / throwing toJSON など標準が throw するケースを Error として返す
|
|
167
|
+
*/
|
|
168
|
+
function safeStringify(value) {
|
|
169
|
+
return attempt(() => JSON.stringify(value));
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
172
|
+
export { FlumeReconnector as a, resolveFlumeReconnectConfig as i, isRecord as n, safeRandom as o, scheduleFlumeReconnect as r, safeStringify as t };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { a as FlumeParseError, c as safeNormalizeError, l as safeErrorMessage, s as attempt, t as safeInvokeCallback } from "./safe-invoke-callback-EpWXwfwp.js";
|
|
2
|
+
//#region lib/utils/safe-json-parse.ts
|
|
3
|
+
function safeJsonParse(raw) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(raw);
|
|
6
|
+
} catch (error) {
|
|
7
|
+
return new FlumeParseError(error instanceof Error ? `invalid JSON: ${error.message}` : "invalid JSON", { cause: error });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region lib/source-helpers/flume-signal-registry.ts
|
|
12
|
+
/**
|
|
13
|
+
* Source 群に共通する AbortSignal の登録・解除・abort 判定を集約する。
|
|
14
|
+
* 異常な polyfill / poisoned getter / 凍結 signal を吸収するため境界呼び出しは全て try/catch で
|
|
15
|
+
* 包み、失敗時はログに流して握り潰す
|
|
16
|
+
*/
|
|
17
|
+
var FlumeSignalRegistry = class {
|
|
18
|
+
props;
|
|
19
|
+
signals = [];
|
|
20
|
+
constructor(props) {
|
|
21
|
+
this.props = props;
|
|
22
|
+
}
|
|
23
|
+
isAnyAborted(extra) {
|
|
24
|
+
if (this.isAborted(extra)) return true;
|
|
25
|
+
for (const signal of this.signals) if (this.isAborted(signal)) return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
register(signal) {
|
|
29
|
+
if (!signal) return;
|
|
30
|
+
const result = attempt(() => signal.addEventListener("abort", this.props.onAbort, { once: true }));
|
|
31
|
+
if (result instanceof Error) {
|
|
32
|
+
const error = safeNormalizeError({ value: result });
|
|
33
|
+
this.props.log.error({
|
|
34
|
+
action: "signal.addListener.failed",
|
|
35
|
+
message: safeErrorMessage({ error }),
|
|
36
|
+
error
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.signals.push(signal);
|
|
41
|
+
}
|
|
42
|
+
unregisterAll() {
|
|
43
|
+
for (const signal of this.signals) {
|
|
44
|
+
const result = attempt(() => signal.removeEventListener("abort", this.props.onAbort));
|
|
45
|
+
if (result instanceof Error) {
|
|
46
|
+
const error = safeNormalizeError({ value: result });
|
|
47
|
+
this.props.log.error({
|
|
48
|
+
action: "signal.removeListener.failed",
|
|
49
|
+
message: safeErrorMessage({ error }),
|
|
50
|
+
error
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.signals.length = 0;
|
|
55
|
+
}
|
|
56
|
+
get size() {
|
|
57
|
+
return this.signals.length;
|
|
58
|
+
}
|
|
59
|
+
isAborted(signal) {
|
|
60
|
+
if (!signal) return false;
|
|
61
|
+
const result = attempt(() => signal.aborted === true);
|
|
62
|
+
return result instanceof Error ? true : result;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region lib/source-helpers/flume-status-emitter.ts
|
|
67
|
+
/**
|
|
68
|
+
* Source の `currentStatus` と `onStatus` 通知を集約する。
|
|
69
|
+
* 同一 (status, detail) の連続遷移は冪等に握り潰し、ユーザーコールバックは `safeInvokeCallback`
|
|
70
|
+
* 経由で例外を隔離する
|
|
71
|
+
*/
|
|
72
|
+
var FlumeStatusEmitter = class {
|
|
73
|
+
props;
|
|
74
|
+
currentStatus = "disconnected";
|
|
75
|
+
currentDetail = null;
|
|
76
|
+
constructor(props) {
|
|
77
|
+
this.props = props;
|
|
78
|
+
}
|
|
79
|
+
get value() {
|
|
80
|
+
return this.currentStatus;
|
|
81
|
+
}
|
|
82
|
+
set(next, detail) {
|
|
83
|
+
const normalizedDetail = detail ?? null;
|
|
84
|
+
if (this.currentStatus === next && this.currentDetail === normalizedDetail) return;
|
|
85
|
+
const prev = this.currentStatus;
|
|
86
|
+
const suffix = detail ? ` (${detail})` : "";
|
|
87
|
+
this.props.log.info({
|
|
88
|
+
action: "status",
|
|
89
|
+
message: `${prev} → ${next}${suffix}`,
|
|
90
|
+
detail: {
|
|
91
|
+
from: prev,
|
|
92
|
+
to: next,
|
|
93
|
+
reason: normalizedDetail
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
this.currentStatus = next;
|
|
97
|
+
this.currentDetail = normalizedDetail;
|
|
98
|
+
const onStatus = this.props.onStatus;
|
|
99
|
+
if (!onStatus) return;
|
|
100
|
+
safeInvokeCallback({
|
|
101
|
+
fn: detail !== void 0 ? () => onStatus(next, detail) : () => onStatus(next),
|
|
102
|
+
onError: (error) => {
|
|
103
|
+
this.props.log.error({
|
|
104
|
+
action: "onStatus.error",
|
|
105
|
+
message: safeErrorMessage({ error }),
|
|
106
|
+
error
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region lib/utils/serial-queue.ts
|
|
114
|
+
/**
|
|
115
|
+
* 投入順を保ったまま task を直列実行する。各 task は前の完了を待ってから走る。
|
|
116
|
+
* task が throw しても後続には伝播しない (キュー自体は止まらない)。
|
|
117
|
+
* maxDepth を超えた場合は新規 task を drop し onOverflow に通知。
|
|
118
|
+
* cancel() 後の add() は no-op となり drain() は即時 resolve する
|
|
119
|
+
*/
|
|
120
|
+
var FlumeSerialQueue = class {
|
|
121
|
+
props;
|
|
122
|
+
chain = Promise.resolve();
|
|
123
|
+
depth = 0;
|
|
124
|
+
cancelled = false;
|
|
125
|
+
constructor(props = {}) {
|
|
126
|
+
this.props = props;
|
|
127
|
+
}
|
|
128
|
+
add(task) {
|
|
129
|
+
if (this.cancelled) return;
|
|
130
|
+
if (this.props.maxDepth !== void 0 && this.depth >= this.props.maxDepth) {
|
|
131
|
+
this.props.onOverflow?.({
|
|
132
|
+
dropped: 1,
|
|
133
|
+
depth: this.depth
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.depth++;
|
|
138
|
+
this.chain = this.chain.then(async () => {
|
|
139
|
+
try {
|
|
140
|
+
await task();
|
|
141
|
+
} catch {} finally {
|
|
142
|
+
this.depth--;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async drain() {
|
|
147
|
+
await this.chain;
|
|
148
|
+
}
|
|
149
|
+
cancel() {
|
|
150
|
+
this.cancelled = true;
|
|
151
|
+
this.depth = 0;
|
|
152
|
+
this.chain = Promise.resolve();
|
|
153
|
+
}
|
|
154
|
+
size() {
|
|
155
|
+
return this.depth;
|
|
156
|
+
}
|
|
157
|
+
isCancelled() {
|
|
158
|
+
return this.cancelled;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
//#endregion
|
|
162
|
+
export { safeJsonParse as i, FlumeStatusEmitter as n, FlumeSignalRegistry as r, FlumeSerialQueue as t };
|
package/dist/slack.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { t as FlumeConnectionError } from "./connection-error-BOk97djj.js";
|
|
3
|
-
import { t as FlumeHttpError } from "./http-error-K-Ym4lfK.js";
|
|
1
|
+
import { C as FlumeSourceStartOptions, T as FlumeStatus, _ as FlumeSlackEnvelope, c as FlumeHandler, y as FlumeSlackSourceOptions } from "./types-D-tO-Mh2.js";
|
|
4
2
|
|
|
5
3
|
//#region lib/slack/slack-source.d.ts
|
|
6
4
|
declare class FlumeSlackSource {
|
|
@@ -9,76 +7,26 @@ declare class FlumeSlackSource {
|
|
|
9
7
|
private socket;
|
|
10
8
|
private reconnector;
|
|
11
9
|
private handler;
|
|
12
|
-
private
|
|
10
|
+
private internalController;
|
|
13
11
|
private readonly log;
|
|
14
12
|
private readonly deps;
|
|
15
13
|
private readonly queue;
|
|
16
14
|
private readonly seen;
|
|
15
|
+
private readonly signals;
|
|
16
|
+
private readonly statusEmitter;
|
|
17
|
+
private readonly onSignalAbort;
|
|
17
18
|
constructor(options: FlumeSlackSourceOptions);
|
|
18
|
-
start(handler: FlumeHandler): Promise<
|
|
19
|
+
start(handler: FlumeHandler, options?: FlumeSourceStartOptions): Promise<Error | null>;
|
|
19
20
|
stop(): Promise<void>;
|
|
20
21
|
status(): FlumeStatus;
|
|
22
|
+
private hasWebSocket;
|
|
21
23
|
private connectInternal;
|
|
22
24
|
private handleMessage;
|
|
25
|
+
private safeExtractMeta;
|
|
23
26
|
private scheduleReconnect;
|
|
24
|
-
private setStatus;
|
|
25
27
|
}
|
|
26
28
|
//#endregion
|
|
27
29
|
//#region lib/slack/extract-slack-meta.d.ts
|
|
28
|
-
declare function
|
|
30
|
+
declare function flumeExtractSlackMeta(envelope: FlumeSlackEnvelope): Record<string, string>;
|
|
29
31
|
//#endregion
|
|
30
|
-
|
|
31
|
-
type Deps = Pick<FlumeRuntimeDeps, "WebSocket" | "fetch" | "now">;
|
|
32
|
-
type Props$2 = {
|
|
33
|
-
appToken: string;
|
|
34
|
-
onMessage: (envelope: FlumeSlackEnvelope) => void;
|
|
35
|
-
onConnected: () => void;
|
|
36
|
-
onDisconnected: () => void;
|
|
37
|
-
onLog?: FlumeLogHandler;
|
|
38
|
-
deps: Deps;
|
|
39
|
-
};
|
|
40
|
-
declare class FlumeSlackSocketMode {
|
|
41
|
-
private readonly props;
|
|
42
|
-
private readonly log;
|
|
43
|
-
private ws;
|
|
44
|
-
stopped: boolean;
|
|
45
|
-
private pendingResolve;
|
|
46
|
-
private pendingResolved;
|
|
47
|
-
constructor(props: Props$2);
|
|
48
|
-
connect(): Promise<FlumeConnectionError | FlumeHttpError | null>;
|
|
49
|
-
disconnect(): void;
|
|
50
|
-
isConnected(): boolean;
|
|
51
|
-
private openSocket;
|
|
52
|
-
private completeConnect;
|
|
53
|
-
private onMessage;
|
|
54
|
-
private onClose;
|
|
55
|
-
private onError;
|
|
56
|
-
}
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region lib/slack/slack-seen-cache.d.ts
|
|
59
|
-
type Props$1 = {
|
|
60
|
-
maxSize: number;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Slack envelope_id の LRU 風キャッシュ。Slack は ack 失敗時に同じ envelope を再送するため、
|
|
64
|
-
* source レイヤで handler への重複配送を防ぐ
|
|
65
|
-
*/
|
|
66
|
-
declare class FlumeSlackSeenCache {
|
|
67
|
-
private readonly props;
|
|
68
|
-
private seen;
|
|
69
|
-
constructor(props: Props$1);
|
|
70
|
-
has(envelopeId: string): boolean;
|
|
71
|
-
add(envelopeId: string): void;
|
|
72
|
-
trim(): void;
|
|
73
|
-
get size(): number;
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region lib/slack/obtain-slack-url.d.ts
|
|
77
|
-
type Props = {
|
|
78
|
-
appToken: string;
|
|
79
|
-
onLog?: FlumeLogHandler;
|
|
80
|
-
deps: Pick<FlumeRuntimeDeps, "fetch" | "now">;
|
|
81
|
-
};
|
|
82
|
-
declare function obtainSlackUrl(props: Props): Promise<string | FlumeHttpError>;
|
|
83
|
-
//#endregion
|
|
84
|
-
export { FlumeSlackConnectionResponseSchema, FlumeSlackEnvelopeSchema, FlumeSlackSeenCache, FlumeSlackSocketMode, FlumeSlackSource, extractSlackMeta, obtainSlackUrl };
|
|
32
|
+
export { FlumeSlackSource, flumeExtractSlackMeta };
|