@helyx/bot 0.4.9 → 0.4.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/CHANGELOG.md +33 -0
- package/dist/cloud-control-dispatcher.js +2 -1
- package/dist/control-server.d.ts +5 -0
- package/dist/control-server.js +104 -13
- package/dist/events.d.ts +64 -1
- package/dist/events.js +699 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +69 -19
- package/dist/interactions.js +79 -16
- package/dist/management-module.js +42 -10
- package/dist/message-classification.d.ts +5 -0
- package/dist/message-classification.js +75 -0
- package/dist/modules.js +9 -0
- package/dist/numeric-write-behind-proxy.d.ts +62 -0
- package/dist/numeric-write-behind-proxy.js +313 -0
- package/dist/numeric-write-behind-redis.d.ts +123 -0
- package/dist/numeric-write-behind-redis.js +1281 -0
- package/dist/numeric-write-behind.d.ts +5 -0
- package/dist/numeric-write-behind.js +37 -0
- package/dist/shard-contracts.d.ts +486 -0
- package/dist/shard-contracts.js +245 -1
- package/dist/shard-supervisor.d.ts +2 -1
- package/dist/shard-supervisor.js +208 -1
- package/dist/shard-worker.d.ts +1 -0
- package/dist/shard-worker.js +42 -5
- package/package.json +9 -9
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {} from "@helyx/sdk";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { assertShardMessageSize, SHARD_CONTROL_TIMEOUT_MS, shardNumericCommittedSchema, shardNumericResponseSchema, } from "./shard-contracts.js";
|
|
4
|
+
export class WorkerNumericWriteBehindProxy {
|
|
5
|
+
#identity;
|
|
6
|
+
#pending = new Map();
|
|
7
|
+
#subscribers = new Map();
|
|
8
|
+
#onMessage = (raw) => {
|
|
9
|
+
const response = shardNumericResponseSchema.safeParse(raw);
|
|
10
|
+
if (response.success) {
|
|
11
|
+
const pending = this.#pending.get(response.data.requestId);
|
|
12
|
+
if (!pending)
|
|
13
|
+
return;
|
|
14
|
+
this.#pending.delete(response.data.requestId);
|
|
15
|
+
clearTimeout(pending.timer);
|
|
16
|
+
pending.resolve(response.data);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const committed = shardNumericCommittedSchema.safeParse(raw);
|
|
20
|
+
if (!committed.success ||
|
|
21
|
+
!sameIdentity(committed.data.identity, this.#identity))
|
|
22
|
+
return;
|
|
23
|
+
void this.#handleCommitted(committed.data);
|
|
24
|
+
};
|
|
25
|
+
constructor(identity) {
|
|
26
|
+
this.#identity = identity;
|
|
27
|
+
process.on("message", this.#onMessage);
|
|
28
|
+
}
|
|
29
|
+
async enqueue(input) {
|
|
30
|
+
try {
|
|
31
|
+
const result = await this.#call({
|
|
32
|
+
kind: "enqueue",
|
|
33
|
+
...scope(input),
|
|
34
|
+
guildId: input.guildId,
|
|
35
|
+
subjectId: input.subjectId,
|
|
36
|
+
occurredAt: input.occurredAt.toISOString(),
|
|
37
|
+
cooldownSeconds: input.cooldownSeconds,
|
|
38
|
+
identity: encodeRecord(input.identity),
|
|
39
|
+
insert: encodeRecord(input.insert),
|
|
40
|
+
increments: input.increments,
|
|
41
|
+
...(input.maxima
|
|
42
|
+
? {
|
|
43
|
+
maxima: Object.fromEntries(Object.entries(input.maxima).map(([field, value]) => [
|
|
44
|
+
field,
|
|
45
|
+
value.toISOString(),
|
|
46
|
+
])),
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
});
|
|
50
|
+
if (typeof result !== "object" ||
|
|
51
|
+
result === null ||
|
|
52
|
+
!("outcome" in result) ||
|
|
53
|
+
![
|
|
54
|
+
"accepted",
|
|
55
|
+
"cooldown",
|
|
56
|
+
"suppressed",
|
|
57
|
+
"paused",
|
|
58
|
+
"capacity",
|
|
59
|
+
"unavailable",
|
|
60
|
+
].includes(String(result.outcome)))
|
|
61
|
+
throw new Error("Shard numeric enqueue response is invalid");
|
|
62
|
+
return {
|
|
63
|
+
outcome: result.outcome,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { outcome: "unavailable" };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async pendingMemberSnapshot(input) {
|
|
71
|
+
const result = await this.#call({ kind: "pending.member", ...input });
|
|
72
|
+
return decodeIpcValue(result);
|
|
73
|
+
}
|
|
74
|
+
async flushMember(input) {
|
|
75
|
+
await this.#call({ kind: "flush.member", ...input });
|
|
76
|
+
}
|
|
77
|
+
async flushGuild(input) {
|
|
78
|
+
await this.#call({ kind: "flush.guild", ...input });
|
|
79
|
+
}
|
|
80
|
+
async flushSubject(input) {
|
|
81
|
+
await this.#call({ kind: "flush.subject", ...input });
|
|
82
|
+
}
|
|
83
|
+
async flushModule(input) {
|
|
84
|
+
await this.#call({ kind: "flush.module", ...input });
|
|
85
|
+
}
|
|
86
|
+
runMemberBarrier(input, operation) {
|
|
87
|
+
return this.#barrier("member", input, operation);
|
|
88
|
+
}
|
|
89
|
+
runGuildBarrier(input, operation) {
|
|
90
|
+
return this.#barrier("guild", input, operation);
|
|
91
|
+
}
|
|
92
|
+
runSubjectBarrier(input, operation) {
|
|
93
|
+
return this.#barrier("subject", input, operation);
|
|
94
|
+
}
|
|
95
|
+
async suppressSubject(input) {
|
|
96
|
+
return (await this.#call({
|
|
97
|
+
kind: "suppress.subject",
|
|
98
|
+
...scope(input),
|
|
99
|
+
subjectId: input.subjectId,
|
|
100
|
+
cutoff: input.cutoff.toISOString(),
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
async suppressGuild(input) {
|
|
104
|
+
return (await this.#call({
|
|
105
|
+
kind: "suppress.guild",
|
|
106
|
+
...input,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
async releaseGuild(input) {
|
|
110
|
+
return (await this.#call({
|
|
111
|
+
kind: "release.guild",
|
|
112
|
+
...input,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
async releaseSubject(input) {
|
|
116
|
+
return (await this.#call({
|
|
117
|
+
kind: "release.subject",
|
|
118
|
+
...input,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
async clearMemberCooldown(input) {
|
|
122
|
+
await this.#call({ kind: "cooldown.member.clear", ...input });
|
|
123
|
+
}
|
|
124
|
+
async clearSubjectCooldown(input) {
|
|
125
|
+
await this.#call({ kind: "cooldown.subject.clear", ...input });
|
|
126
|
+
}
|
|
127
|
+
subscribeCommitted(input, handler) {
|
|
128
|
+
const key = scopeKey(input);
|
|
129
|
+
const subscribers = this.#subscribers.get(key) ?? new Set();
|
|
130
|
+
subscribers.add(handler);
|
|
131
|
+
this.#subscribers.set(key, subscribers);
|
|
132
|
+
return () => {
|
|
133
|
+
subscribers.delete(handler);
|
|
134
|
+
if (subscribers.size === 0)
|
|
135
|
+
this.#subscribers.delete(key);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
stop() {
|
|
139
|
+
process.off("message", this.#onMessage);
|
|
140
|
+
for (const [requestId, pending] of this.#pending) {
|
|
141
|
+
this.#pending.delete(requestId);
|
|
142
|
+
clearTimeout(pending.timer);
|
|
143
|
+
pending.resolve({
|
|
144
|
+
version: 1,
|
|
145
|
+
type: "helyx.numeric.response",
|
|
146
|
+
requestId,
|
|
147
|
+
ok: false,
|
|
148
|
+
safeCode: "proxy_stopped",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async #barrier(barrierType, input, operation) {
|
|
153
|
+
const acquired = (await this.#call({
|
|
154
|
+
kind: "barrier.acquire",
|
|
155
|
+
...scope(input),
|
|
156
|
+
barrierType,
|
|
157
|
+
...(input.guildId ? { guildId: input.guildId } : {}),
|
|
158
|
+
...(input.subjectId ? { subjectId: input.subjectId } : {}),
|
|
159
|
+
}));
|
|
160
|
+
let renewalFailure;
|
|
161
|
+
const renew = setInterval(() => {
|
|
162
|
+
void this.#call({
|
|
163
|
+
kind: "barrier.renew",
|
|
164
|
+
...scope(input),
|
|
165
|
+
barrierType,
|
|
166
|
+
...(input.guildId ? { guildId: input.guildId } : {}),
|
|
167
|
+
...(input.subjectId ? { subjectId: input.subjectId } : {}),
|
|
168
|
+
barrierId: acquired.barrierId,
|
|
169
|
+
}).catch((error) => {
|
|
170
|
+
renewalFailure =
|
|
171
|
+
error instanceof Error
|
|
172
|
+
? error
|
|
173
|
+
: new Error("Numeric barrier renewal failed");
|
|
174
|
+
});
|
|
175
|
+
}, 20_000);
|
|
176
|
+
renew.unref();
|
|
177
|
+
try {
|
|
178
|
+
if (barrierType === "member")
|
|
179
|
+
await this.flushMember(input);
|
|
180
|
+
else if (barrierType === "guild")
|
|
181
|
+
await this.flushGuild(input);
|
|
182
|
+
else
|
|
183
|
+
await this.flushSubject(input);
|
|
184
|
+
const result = await operation();
|
|
185
|
+
if (renewalFailure)
|
|
186
|
+
throw renewalFailure;
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
clearInterval(renew);
|
|
191
|
+
await this.#call({
|
|
192
|
+
kind: "barrier.release",
|
|
193
|
+
...scope(input),
|
|
194
|
+
barrierType,
|
|
195
|
+
...(input.guildId ? { guildId: input.guildId } : {}),
|
|
196
|
+
...(input.subjectId ? { subjectId: input.subjectId } : {}),
|
|
197
|
+
barrierId: acquired.barrierId,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async #handleCommitted(committed) {
|
|
202
|
+
let response;
|
|
203
|
+
try {
|
|
204
|
+
if (new Date(committed.deadlineAt).getTime() <= Date.now())
|
|
205
|
+
throw new Error("Numeric committed notification expired");
|
|
206
|
+
const batch = decodeIpcValue(committed.payload);
|
|
207
|
+
for (const subscriber of this.#subscribers.get(scopeKey(committed.scope)) ?? [])
|
|
208
|
+
await subscriber(batch);
|
|
209
|
+
response = {
|
|
210
|
+
version: 1,
|
|
211
|
+
type: "helyx.numeric.committed.response",
|
|
212
|
+
requestId: committed.requestId,
|
|
213
|
+
identity: this.#identity,
|
|
214
|
+
ok: true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
response = {
|
|
219
|
+
version: 1,
|
|
220
|
+
type: "helyx.numeric.committed.response",
|
|
221
|
+
requestId: committed.requestId,
|
|
222
|
+
identity: this.#identity,
|
|
223
|
+
ok: false,
|
|
224
|
+
safeCode: "handler_failed",
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
assertShardMessageSize(response);
|
|
228
|
+
if (process.connected)
|
|
229
|
+
process.send?.(response);
|
|
230
|
+
}
|
|
231
|
+
#call(operation) {
|
|
232
|
+
if (!process.send)
|
|
233
|
+
return Promise.reject(new Error("Shard numeric supervisor IPC is unavailable"));
|
|
234
|
+
const requestId = randomUUID();
|
|
235
|
+
const request = {
|
|
236
|
+
version: 1,
|
|
237
|
+
type: "helyx.numeric.request",
|
|
238
|
+
requestId,
|
|
239
|
+
deadlineAt: new Date(Date.now() + SHARD_CONTROL_TIMEOUT_MS).toISOString(),
|
|
240
|
+
identity: this.#identity,
|
|
241
|
+
operation,
|
|
242
|
+
};
|
|
243
|
+
assertShardMessageSize(request);
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
const timer = setTimeout(() => {
|
|
246
|
+
this.#pending.delete(requestId);
|
|
247
|
+
reject(new Error("Shard numeric supervisor request timed out"));
|
|
248
|
+
}, SHARD_CONTROL_TIMEOUT_MS);
|
|
249
|
+
timer.unref();
|
|
250
|
+
this.#pending.set(requestId, {
|
|
251
|
+
timer,
|
|
252
|
+
resolve: (response) => {
|
|
253
|
+
if (response.ok)
|
|
254
|
+
resolve(response.result);
|
|
255
|
+
else
|
|
256
|
+
reject(new Error(`Shard numeric supervisor rejected request: ${response.safeCode}`));
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
process.send?.(request);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function scope(input) {
|
|
264
|
+
return { moduleId: input.moduleId, collection: input.collection };
|
|
265
|
+
}
|
|
266
|
+
function scopeKey(input) {
|
|
267
|
+
return `${input.moduleId}\u0000${input.collection}`;
|
|
268
|
+
}
|
|
269
|
+
function encodeRecord(input) {
|
|
270
|
+
const result = {};
|
|
271
|
+
for (const [field, value] of Object.entries(input)) {
|
|
272
|
+
if (value instanceof Date)
|
|
273
|
+
result[field] = { type: "date", value: value.toISOString() };
|
|
274
|
+
else if (typeof value === "string")
|
|
275
|
+
result[field] = { type: "string", value };
|
|
276
|
+
else if (typeof value === "boolean")
|
|
277
|
+
result[field] = { type: "boolean", value };
|
|
278
|
+
else
|
|
279
|
+
result[field] = { type: "number", value };
|
|
280
|
+
}
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
function decodeIpcValue(input) {
|
|
284
|
+
if (Array.isArray(input))
|
|
285
|
+
return input.map(decodeIpcValue);
|
|
286
|
+
if (typeof input !== "object" || input === null)
|
|
287
|
+
return input;
|
|
288
|
+
if ("__helyxDate" in input &&
|
|
289
|
+
typeof input.__helyxDate === "string")
|
|
290
|
+
return new Date(input.__helyxDate);
|
|
291
|
+
return Object.fromEntries(Object.entries(input).map(([key, value]) => [key, decodeIpcValue(value)]));
|
|
292
|
+
}
|
|
293
|
+
export function encodeNumericIpcValue(input) {
|
|
294
|
+
if (input instanceof Date)
|
|
295
|
+
return { __helyxDate: input.toISOString() };
|
|
296
|
+
if (Array.isArray(input))
|
|
297
|
+
return input.map(encodeNumericIpcValue);
|
|
298
|
+
if (typeof input !== "object" || input === null)
|
|
299
|
+
return input;
|
|
300
|
+
return Object.fromEntries(Object.entries(input).map(([key, value]) => [
|
|
301
|
+
key,
|
|
302
|
+
encodeNumericIpcValue(value),
|
|
303
|
+
]));
|
|
304
|
+
}
|
|
305
|
+
function sameIdentity(left, right) {
|
|
306
|
+
return (left.generation === right.generation &&
|
|
307
|
+
left.deploymentOrder === right.deploymentOrder &&
|
|
308
|
+
left.supervisorId === right.supervisorId &&
|
|
309
|
+
left.shardId === right.shardId &&
|
|
310
|
+
left.shardCount === right.shardCount &&
|
|
311
|
+
left.fencingToken === right.fencingToken);
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=numeric-write-behind-proxy.js.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type NumericWriteBehindCommittedBatch, type NumericWriteBehindControl, type NumericWriteBehindEnqueueInput, type NumericWriteBehindHealth, type NumericWriteBehindMemberScope, type NumericWriteBehindScope, type NumericWriteBehindService } from "@helyx/sdk";
|
|
2
|
+
import { type NumericBatchWriter, type NumericWriteBehindRegistration } from "@helyx/platform";
|
|
3
|
+
import type { ShardIdentity, ShardNumericRequest } from "./shard-contracts.js";
|
|
4
|
+
interface RedisEvalClient {
|
|
5
|
+
connect(): Promise<unknown>;
|
|
6
|
+
quit(): Promise<unknown>;
|
|
7
|
+
eval(script: string, options: {
|
|
8
|
+
keys: readonly string[];
|
|
9
|
+
arguments: readonly string[];
|
|
10
|
+
}): Promise<unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface RedisNumericWriteBehindOptions {
|
|
13
|
+
redisUrl: string;
|
|
14
|
+
namespace: string;
|
|
15
|
+
writer: NumericBatchWriter;
|
|
16
|
+
registrations: readonly NumericWriteBehindRegistration[];
|
|
17
|
+
client?: RedisEvalClient;
|
|
18
|
+
flushIntervalMs?: number;
|
|
19
|
+
capacity?: number;
|
|
20
|
+
onError?: (error: Error) => void;
|
|
21
|
+
supervisorId?: string;
|
|
22
|
+
shardLeaseKeyPrefix?: string;
|
|
23
|
+
barrierLeaseMs?: number;
|
|
24
|
+
suppressionDrainTimeoutMs?: number;
|
|
25
|
+
suppressionPollMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class RedisNumericWriteBehindService implements NumericWriteBehindService, NumericWriteBehindControl {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(options: RedisNumericWriteBehindOptions);
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
enqueue(input: NumericWriteBehindEnqueueInput): Promise<{
|
|
32
|
+
outcome: "accepted" | "cooldown" | "suppressed" | "paused" | "capacity" | "unavailable";
|
|
33
|
+
}>;
|
|
34
|
+
enqueueFenced(input: NumericWriteBehindEnqueueInput, fence: {
|
|
35
|
+
shardId: number;
|
|
36
|
+
leaseKey: string;
|
|
37
|
+
leaseValue: string;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
outcome: "accepted" | "cooldown" | "suppressed" | "paused" | "capacity" | "unavailable";
|
|
40
|
+
}>;
|
|
41
|
+
pendingMemberSnapshot(input: NumericWriteBehindMemberScope): Promise<{
|
|
42
|
+
increments: Readonly<Record<string, number>>;
|
|
43
|
+
maxima: Readonly<Record<string, Date>>;
|
|
44
|
+
oldestAcceptedAt: Date | null;
|
|
45
|
+
}>;
|
|
46
|
+
flushMember(input: NumericWriteBehindMemberScope): Promise<void>;
|
|
47
|
+
flushGuild(input: NumericWriteBehindScope & {
|
|
48
|
+
guildId: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
flushSubject(input: NumericWriteBehindScope & {
|
|
51
|
+
subjectId: string;
|
|
52
|
+
}): Promise<void>;
|
|
53
|
+
flushModule(input: NumericWriteBehindScope): Promise<void>;
|
|
54
|
+
runMemberBarrier<Result>(input: NumericWriteBehindMemberScope, operation: () => Promise<Result>): Promise<Result>;
|
|
55
|
+
runGuildBarrier<Result>(input: NumericWriteBehindScope & {
|
|
56
|
+
guildId: string;
|
|
57
|
+
}, operation: () => Promise<Result>): Promise<Result>;
|
|
58
|
+
runSubjectBarrier<Result>(input: NumericWriteBehindScope & {
|
|
59
|
+
subjectId: string;
|
|
60
|
+
}, operation: () => Promise<Result>): Promise<Result>;
|
|
61
|
+
suppressSubject(input: NumericWriteBehindScope & {
|
|
62
|
+
subjectId: string;
|
|
63
|
+
cutoff: Date;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
suppressionId: string;
|
|
66
|
+
discarded: number;
|
|
67
|
+
}>;
|
|
68
|
+
suppressGuild(input: NumericWriteBehindScope & {
|
|
69
|
+
guildId: string;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
suppressionId: string;
|
|
72
|
+
discarded: number;
|
|
73
|
+
}>;
|
|
74
|
+
releaseGuild(input: NumericWriteBehindScope & {
|
|
75
|
+
guildId: string;
|
|
76
|
+
suppressionId: string;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
released: boolean;
|
|
79
|
+
}>;
|
|
80
|
+
releaseSubject(input: NumericWriteBehindScope & {
|
|
81
|
+
subjectId: string;
|
|
82
|
+
suppressionId: string;
|
|
83
|
+
}): Promise<{
|
|
84
|
+
released: boolean;
|
|
85
|
+
}>;
|
|
86
|
+
clearMemberCooldown(input: NumericWriteBehindMemberScope): Promise<void>;
|
|
87
|
+
clearSubjectCooldown(input: NumericWriteBehindScope & {
|
|
88
|
+
subjectId: string;
|
|
89
|
+
}): Promise<void>;
|
|
90
|
+
subscribeCommitted(input: NumericWriteBehindScope, handler: (batch: NumericWriteBehindCommittedBatch) => void | Promise<void>): () => void;
|
|
91
|
+
health(): NumericWriteBehindHealth;
|
|
92
|
+
acquireBarrier(input: {
|
|
93
|
+
scope: NumericWriteBehindScope;
|
|
94
|
+
barrierType: "member" | "guild" | "subject";
|
|
95
|
+
guildId?: string;
|
|
96
|
+
subjectId?: string;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
barrierId: string;
|
|
99
|
+
}>;
|
|
100
|
+
releaseBarrier(input: {
|
|
101
|
+
scope: NumericWriteBehindScope;
|
|
102
|
+
barrierType: "member" | "guild" | "subject";
|
|
103
|
+
guildId?: string;
|
|
104
|
+
subjectId?: string;
|
|
105
|
+
barrierId: string;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
renewBarrier(input: {
|
|
108
|
+
scope: NumericWriteBehindScope;
|
|
109
|
+
barrierType: "member" | "guild" | "subject";
|
|
110
|
+
guildId?: string;
|
|
111
|
+
subjectId?: string;
|
|
112
|
+
barrierId: string;
|
|
113
|
+
}): Promise<void>;
|
|
114
|
+
stop(timeoutMs?: number): Promise<{
|
|
115
|
+
drained: boolean;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
118
|
+
export declare function executeRedisNumericOperation(service: RedisNumericWriteBehindService, operation: ShardNumericRequest["operation"], fence?: {
|
|
119
|
+
identity: ShardIdentity;
|
|
120
|
+
shardLeaseKeyPrefix: string;
|
|
121
|
+
}): Promise<unknown>;
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=numeric-write-behind-redis.d.ts.map
|