@mtkruto/node 0.1.134 → 0.1.136
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/esm/0_deps.d.ts +1 -1
- package/esm/0_deps.js +1 -1
- package/esm/4_constants.d.ts +1 -1
- package/esm/4_constants.js +1 -1
- package/esm/client/0_utilities.d.ts +32 -23
- package/esm/client/0_utilities.js +27 -0
- package/esm/client/1_composer.d.ts +4 -4
- package/esm/client/1_composer.js +3 -29
- package/esm/client/4_client.d.ts +4 -4
- package/esm/client/4_client.js +3 -29
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.d.ts +2 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.js +2 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/mutex.d.ts +26 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/mutex.js +32 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/semaphore.d.ts +41 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/mutex/main/semaphore.js +113 -0
- package/esm/storage/1_storage_local_storage.js +2 -2
- package/esm/storage/1_storage_session_storage.js +2 -2
- package/esm/types/6_update.d.ts +70 -8
- package/package.json +1 -2
- package/script/0_deps.d.ts +1 -1
- package/script/0_deps.js +6 -6
- package/script/4_constants.d.ts +1 -1
- package/script/4_constants.js +1 -1
- package/script/client/0_utilities.d.ts +32 -23
- package/script/client/0_utilities.js +29 -1
- package/script/client/1_composer.d.ts +4 -4
- package/script/client/1_composer.js +3 -29
- package/script/client/4_client.d.ts +4 -4
- package/script/client/4_client.js +2 -28
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.d.ts +2 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.js +18 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/mutex.d.ts +26 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/mutex.js +36 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/semaphore.d.ts +41 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/mutex/main/semaphore.js +117 -0
- package/script/storage/1_storage_local_storage.js +2 -2
- package/script/storage/1_storage_session_storage.js +2 -2
- package/script/types/6_update.d.ts +70 -8
package/esm/0_deps.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { contentType } from "./deps/deno.land/std@0.210.0/media_types/content_ty
|
|
|
5
5
|
export declare function extension(mimeType: string): string;
|
|
6
6
|
export { ctr256, factorize, ige256Decrypt, ige256Encrypt, init as initTgCrypto } from "./deps/deno.land/x/tgcrypto@0.3.3/mod.js";
|
|
7
7
|
export { gunzip, gzip } from "./deps/raw.githubusercontent.com/MTKruto/compress/main/gzip/gzip.js";
|
|
8
|
-
export { Mutex
|
|
8
|
+
export { Mutex } from "./deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.js";
|
|
9
9
|
export { Parser } from "./deps/deno.land/x/html_parser@v0.1.3/src/mod.js";
|
|
10
10
|
import { debug as debug_ } from "./deps/raw.githubusercontent.com/MTKruto/debug/main/mod.js";
|
|
11
11
|
export declare const debug: typeof debug_;
|
package/esm/0_deps.js
CHANGED
|
@@ -13,7 +13,7 @@ export function extension(mimeType) {
|
|
|
13
13
|
}
|
|
14
14
|
export { ctr256, factorize, ige256Decrypt, ige256Encrypt, init as initTgCrypto } from "./deps/deno.land/x/tgcrypto@0.3.3/mod.js";
|
|
15
15
|
export { gunzip, gzip } from "./deps/raw.githubusercontent.com/MTKruto/compress/main/gzip/gzip.js";
|
|
16
|
-
export { Mutex } from "
|
|
16
|
+
export { Mutex } from "./deps/raw.githubusercontent.com/MTKruto/mutex/main/mod.js";
|
|
17
17
|
export { Parser } from "./deps/deno.land/x/html_parser@v0.1.3/src/mod.js";
|
|
18
18
|
import { debug as debug_ } from "./deps/raw.githubusercontent.com/MTKruto/debug/main/mod.js";
|
|
19
19
|
export const debug = (v) => debug_(v);
|
package/esm/4_constants.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type PublicKeys = readonly [bigint, [bigint, bigint]][];
|
|
|
4
4
|
export declare const PUBLIC_KEYS: PublicKeys;
|
|
5
5
|
export declare const INITIAL_DC: DC;
|
|
6
6
|
export declare const LAYER = 169;
|
|
7
|
-
export declare const APP_VERSION = "MTKruto 0.1.
|
|
7
|
+
export declare const APP_VERSION = "MTKruto 0.1.136";
|
|
8
8
|
export declare const DEVICE_MODEL: string;
|
|
9
9
|
export declare const LANG_CODE: string;
|
|
10
10
|
export declare const LANG_PACK = "";
|
package/esm/4_constants.js
CHANGED
|
@@ -53,7 +53,7 @@ export const PUBLIC_KEYS = Object.freeze([
|
|
|
53
53
|
]);
|
|
54
54
|
export const INITIAL_DC = "2";
|
|
55
55
|
export const LAYER = 169;
|
|
56
|
-
export const APP_VERSION = "MTKruto 0.1.
|
|
56
|
+
export const APP_VERSION = "MTKruto 0.1.136";
|
|
57
57
|
// @ts-ignore: lib
|
|
58
58
|
export const DEVICE_MODEL = typeof dntShim.Deno === "undefined" ? typeof navigator === "undefined" ? typeof process === "undefined" ? "Unknown" : process.platform + "-" + process.arch : navigator.userAgent.split(" ")[0] : dntShim.Deno.build.os + "-" + dntShim.Deno.build.arch;
|
|
59
59
|
export const LANG_CODE = typeof navigator === "undefined" ? "en" : navigator.language.split("-")[0];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { enums, types } from "../2_tl.js";
|
|
2
|
-
import { ChatP,
|
|
2
|
+
import { ChatP, MessageTypes, UpdateMap, User } from "../3_types.js";
|
|
3
3
|
export declare const resolve: () => Promise<void>;
|
|
4
4
|
export type With<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
5
5
|
export declare function isPtsUpdate(v: enums.Update): v is types.UpdateNewMessage | types.UpdateDeleteMessages | types.UpdateReadHistoryInbox | types.UpdateReadHistoryOutbox | types.UpdatePinnedChannelMessages | types.UpdatePinnedMessages | types.UpdateFolderPeers | types.UpdateChannelWebPage | types.UpdateEditMessage | types.UpdateReadMessagesContents | types.UpdateWebPage;
|
|
@@ -12,29 +12,38 @@ export declare function getFileContents(source: FileSource, fileName?: string):
|
|
|
12
12
|
export declare function isHttpUrl(string: string): boolean;
|
|
13
13
|
export declare function getUsername(string: string): string;
|
|
14
14
|
export declare function getChatListId(chatList: string): 0 | 1;
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
type AnyLevel1 = keyof UpdateMap;
|
|
16
|
+
type GetLevel1Type<L1 extends AnyLevel1> = UpdateMap[L1];
|
|
17
|
+
type GetAnyLevel2<L1 extends AnyLevel1> = L1 extends "message" | "editedMessage" ? keyof MessageTypes : never;
|
|
18
|
+
type AnyLevel2<L1 extends AnyLevel1 = AnyLevel1> = L1 extends unknown ? `${L1 extends "message" | "editedMessage" ? L1 | "" : L1}:${GetAnyLevel2<L1>}` : never;
|
|
19
|
+
type GetLevel2Type<L1 extends string, L2 extends string> = L2 extends keyof MessageTypes ? L1 extends "" ? {
|
|
20
|
+
[P in "message" | "editedMessage"]?: MessageTypes[L2];
|
|
21
|
+
} : L1 extends "message" | "editedMessage" ? {
|
|
22
|
+
[P in L1]: MessageTypes[L2];
|
|
23
|
+
} : never : never;
|
|
24
|
+
type AnyLevelX = AnyLevel1 | AnyLevel2;
|
|
25
|
+
type FilterCore<Q extends AnyLevelX = AnyLevelX> = Q extends AnyLevel1 ? GetLevel1Type<Q> : Q extends `${infer L1}:${infer L2}` ? GetLevel2Type<L1, L2> : 1;
|
|
26
|
+
type Chat<T> = "msg" extends keyof T ? T & {
|
|
25
27
|
chat: ChatP;
|
|
26
|
-
} :
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
} : T;
|
|
29
|
+
type Msg<T> = "message" extends keyof T ? T & {
|
|
30
|
+
msg: NonNullable<T["message"]>;
|
|
31
|
+
} : "editedMessage" extends keyof T ? T & {
|
|
32
|
+
msg: NonNullable<T["editedMessage"]>;
|
|
33
|
+
} : "callbackQuery" extends keyof T ? "message" extends keyof T["callbackQuery"] ? T & {
|
|
34
|
+
msg: T["callbackQuery"]["message"];
|
|
35
|
+
} : T : T;
|
|
36
|
+
type From<T> = "callbackQuery" | "inlineQuery" extends keyof T ? T & {
|
|
30
37
|
from: User;
|
|
31
|
-
} : {
|
|
38
|
+
} : "message" | "editedMessage" extends keyof T ? {
|
|
32
39
|
from?: User;
|
|
33
|
-
};
|
|
34
|
-
type
|
|
35
|
-
|
|
36
|
-
} :
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export type
|
|
40
|
+
} : T;
|
|
41
|
+
type SenderChat<T> = "message" | "editedMessage" extends keyof T ? {
|
|
42
|
+
senderChat?: ChatP;
|
|
43
|
+
} : T;
|
|
44
|
+
type Shortcuts<T> = SenderChat<From<Chat<Msg<T>>>>;
|
|
45
|
+
type Filter<Q extends AnyLevelX> = Shortcuts<FilterCore<Q>>;
|
|
46
|
+
export type FilterQuery = AnyLevelX;
|
|
47
|
+
export type WithFilter<T, Q extends FilterQuery> = T & Filter<Q>;
|
|
48
|
+
export declare function match<Q extends FilterQuery, T extends object>(filter: Q, value: T): boolean;
|
|
40
49
|
export {};
|
|
@@ -145,3 +145,30 @@ export function getChatListId(chatList) {
|
|
|
145
145
|
UNREACHABLE();
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
export function match(filter, value) {
|
|
149
|
+
let [type, ...other] = filter.split(":");
|
|
150
|
+
if (type != "" && !(type in value)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if (type == "") {
|
|
154
|
+
if (other.length != 1) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if ("message" in value) {
|
|
158
|
+
type = "message";
|
|
159
|
+
}
|
|
160
|
+
else if ("editedMessage" in value) {
|
|
161
|
+
type = "editedMessage";
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const field = other[0];
|
|
168
|
+
if (field) {
|
|
169
|
+
if (!(field in value[type])) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Update, UpdateIntersection, User } from "../3_types.js";
|
|
2
|
+
import { FilterQuery, WithFilter } from "./0_utilities.js";
|
|
3
3
|
type MaybePromise<T> = T | Promise<T>;
|
|
4
4
|
export type NextFunction = () => Promise<void>;
|
|
5
5
|
export type MiddlewareFn<C> = (ctx: C, next: NextFunction) => MaybePromise<unknown>;
|
|
@@ -21,10 +21,10 @@ export declare class Composer<C extends {
|
|
|
21
21
|
branch(predicate: (ctx: UpdateIntersection<C>) => MaybePromise<boolean>, trueHandler_: Middleware<UpdateIntersection<C>>, falseHandler_: Middleware<UpdateIntersection<C>>): Composer<UpdateIntersection<C>>;
|
|
22
22
|
filter<D extends C>(predicate: (ctx: UpdateIntersection<C>) => ctx is D, ...middleware: Middleware<D>[]): Composer<D>;
|
|
23
23
|
filter(predicate: (ctx: UpdateIntersection<C>) => MaybePromise<boolean>, ...middleware: Middleware<UpdateIntersection<C>>[]): Composer<C>;
|
|
24
|
-
on<
|
|
24
|
+
on<Q extends FilterQuery>(filter: Q, ...middleawre: Middleware<WithFilter<C, Q>>[]): Composer<UpdateIntersection<WithFilter<C, Q>>>;
|
|
25
25
|
command(commands: string | RegExp | (string | RegExp)[] | {
|
|
26
26
|
names: string | RegExp | (string | RegExp)[];
|
|
27
27
|
prefixes: string | string[];
|
|
28
|
-
}, ...middleawre: Middleware<
|
|
28
|
+
}, ...middleawre: Middleware<WithFilter<C, "message:text">>[]): Composer<UpdateIntersection<WithFilter<C, "message:text">>>;
|
|
29
29
|
}
|
|
30
30
|
export {};
|
package/esm/client/1_composer.js
CHANGED
|
@@ -10,7 +10,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
12
|
var _Composer_handle, _Composer_prefixes;
|
|
13
|
-
import {
|
|
13
|
+
import { match } from "./0_utilities.js";
|
|
14
14
|
export function flatten(mw) {
|
|
15
15
|
return typeof mw === "function" ? mw : (ctx, next) => mw.middleware()(ctx, next);
|
|
16
16
|
}
|
|
@@ -69,34 +69,8 @@ export class Composer {
|
|
|
69
69
|
return composer;
|
|
70
70
|
}
|
|
71
71
|
on(filter, ...middleawre) {
|
|
72
|
-
const type = typeof filter === "string" ? filter : filter[0];
|
|
73
|
-
let keys = Array.isArray(filter) ? filter.slice(1) : [];
|
|
74
|
-
let messageType = null;
|
|
75
|
-
if (type == "message") {
|
|
76
|
-
messageType = keys[0];
|
|
77
|
-
keys = keys.slice(1);
|
|
78
|
-
}
|
|
79
72
|
return this.filter((ctx) => {
|
|
80
|
-
|
|
81
|
-
if (messageType != null) {
|
|
82
|
-
// deno-lint-ignore ban-ts-comment
|
|
83
|
-
// @ts-ignore
|
|
84
|
-
assertMessageType(ctx[type], messageType);
|
|
85
|
-
}
|
|
86
|
-
if (keys.length > 0) {
|
|
87
|
-
for (const key of keys) {
|
|
88
|
-
// deno-lint-ignore ban-ts-comment
|
|
89
|
-
// @ts-ignore
|
|
90
|
-
if (!(key in ctx[type])) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
73
|
+
return match(filter, ctx);
|
|
100
74
|
}, ...middleawre);
|
|
101
75
|
}
|
|
102
76
|
command(commands, ...middleawre) {
|
|
@@ -114,7 +88,7 @@ export class Composer {
|
|
|
114
88
|
}
|
|
115
89
|
}
|
|
116
90
|
}
|
|
117
|
-
return this.on(
|
|
91
|
+
return this.on("message:text").filter((ctx) => {
|
|
118
92
|
const prefixes_ = prefixes.length == 0 ? [!ctx.me?.isBot ? "\\" : "/"] : prefixes;
|
|
119
93
|
if (prefixes_.length == 0) {
|
|
120
94
|
return false;
|
package/esm/client/4_client.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { MaybePromise } from "../1_utilities.js";
|
|
|
2
2
|
import { functions, ReadObject, types } from "../2_tl.js";
|
|
3
3
|
import { Storage } from "../3_storage.js";
|
|
4
4
|
import { DC } from "../3_transport.js";
|
|
5
|
-
import { BotCommand, Chat, ChatAction, ChatID, ChatP, Document, InlineQueryResult, Message, MessageAnimation, MessageAudio, MessageContact, MessageDice, MessageDocument, MessageLocation, MessagePhoto, MessagePoll, MessageText,
|
|
5
|
+
import { BotCommand, Chat, ChatAction, ChatID, ChatP, Document, InlineQueryResult, Message, MessageAnimation, MessageAudio, MessageContact, MessageDice, MessageDocument, MessageLocation, MessagePhoto, MessagePoll, MessageText, MessageVenue, MessageVideo, MessageVideoNote, MessageVoice, NetworkStatistics, ParseMode, Reaction, Update, UpdateIntersection, User } from "../3_types.js";
|
|
6
6
|
import { Migrate } from "../4_errors.js";
|
|
7
7
|
import { ClientAbstract } from "./0_client_abstract.js";
|
|
8
|
-
import { FileSource,
|
|
8
|
+
import { FileSource, FilterQuery, WithFilter } from "./0_utilities.js";
|
|
9
9
|
import { Composer, Middleware } from "./1_composer.js";
|
|
10
10
|
import { AddReactionParams, AnswerCallbackQueryParams, AnswerInlineQueryParams, AuthorizeUserParams, ClientParams, DeleteMessageParams, DeleteMessagesParams, DownloadParams, EditMessageParams, ForwardMessagesParams, GetChatsParams, GetHistoryParams, GetMyCommandsParams, ReplyParams, SendAnimationParams, SendAudioParams, SendContactParams, SendDiceParams, SendDocumentParams, SendLocationParams, SendMessageParams, SendPhotoParams, SendPollParams, SendVenueParams, SendVideoNoteParams, SendVideoParams, SendVoiceParams, SetMyCommandsParams, SetReactionsParams, UploadParams } from "./3_params.js";
|
|
11
11
|
export type NextFn<T = void> = () => Promise<T>;
|
|
@@ -339,11 +339,11 @@ export declare class Client<C extends Context = Context> extends ClientAbstract
|
|
|
339
339
|
branch(predicate: (ctx: UpdateIntersection<C>) => MaybePromise<boolean>, trueHandler_: Middleware<UpdateIntersection<C>>, falseHandler_: Middleware<UpdateIntersection<C>>): Composer<UpdateIntersection<C>>;
|
|
340
340
|
filter<D extends C>(predicate: (ctx: UpdateIntersection<C>) => ctx is D, ...middleware: Middleware<D>[]): Composer<D>;
|
|
341
341
|
filter(predicate: (ctx: UpdateIntersection<C>) => MaybePromise<boolean>, ...middleware: Middleware<UpdateIntersection<C>>[]): Composer<C>;
|
|
342
|
-
on<
|
|
342
|
+
on<Q extends FilterQuery>(filter: Q, ...middleawre: Middleware<WithFilter<C, Q>>[]): Composer<UpdateIntersection<WithFilter<C, Q>>>;
|
|
343
343
|
command(commands: string | RegExp | (string | RegExp)[] | {
|
|
344
344
|
names: string | RegExp | (string | RegExp)[];
|
|
345
345
|
prefixes: string | string[];
|
|
346
|
-
}, ...middleawre: Middleware<
|
|
346
|
+
}, ...middleawre: Middleware<WithFilter<C, "message:text">>[]): Composer<UpdateIntersection<WithFilter<C, "message:text">>>;
|
|
347
347
|
/**
|
|
348
348
|
* Set the bot's description in the given language. Bot-only.
|
|
349
349
|
*
|
package/esm/client/4_client.js
CHANGED
|
@@ -21,7 +21,7 @@ import { ClientAbstract } from "./0_client_abstract.js";
|
|
|
21
21
|
import { parseHtml } from "./0_html.js";
|
|
22
22
|
import { decryptMessage, encryptMessage, getMessageId } from "./0_message.js";
|
|
23
23
|
import { checkPassword } from "./0_password.js";
|
|
24
|
-
import { getChatListId, getFileContents, getUsername, isChannelPtsUpdate, isHttpUrl, isPtsUpdate, resolve } from "./0_utilities.js";
|
|
24
|
+
import { getChatListId, getFileContents, getUsername, isChannelPtsUpdate, isHttpUrl, isPtsUpdate, match, resolve } from "./0_utilities.js";
|
|
25
25
|
import { Composer, concat, flatten, skip } from "./1_composer.js";
|
|
26
26
|
import { ClientPlain } from "./2_client_plain.js";
|
|
27
27
|
const d = debug("Client");
|
|
@@ -2231,34 +2231,8 @@ export class Client extends ClientAbstract {
|
|
|
2231
2231
|
return composer;
|
|
2232
2232
|
}
|
|
2233
2233
|
on(filter, ...middleawre) {
|
|
2234
|
-
const type = typeof filter === "string" ? filter : filter[0];
|
|
2235
|
-
let keys = Array.isArray(filter) ? filter.slice(1) : [];
|
|
2236
|
-
let messageType = null;
|
|
2237
|
-
if (type == "message") {
|
|
2238
|
-
messageType = keys[0];
|
|
2239
|
-
keys = keys.slice(1);
|
|
2240
|
-
}
|
|
2241
2234
|
return this.filter((ctx) => {
|
|
2242
|
-
|
|
2243
|
-
if (messageType != null) {
|
|
2244
|
-
// deno-lint-ignore ban-ts-comment
|
|
2245
|
-
// @ts-ignore
|
|
2246
|
-
assertMessageType(ctx[type], messageType);
|
|
2247
|
-
}
|
|
2248
|
-
if (keys.length > 0) {
|
|
2249
|
-
for (const key of keys) {
|
|
2250
|
-
// deno-lint-ignore ban-ts-comment
|
|
2251
|
-
// @ts-ignore
|
|
2252
|
-
if (!(key in ctx[type])) {
|
|
2253
|
-
return false;
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
return true;
|
|
2258
|
-
}
|
|
2259
|
-
else {
|
|
2260
|
-
return false;
|
|
2261
|
-
}
|
|
2235
|
+
return match(filter, ctx);
|
|
2262
2236
|
}, ...middleawre);
|
|
2263
2237
|
}
|
|
2264
2238
|
command(commands, ...middleawre) {
|
|
@@ -2276,7 +2250,7 @@ export class Client extends ClientAbstract {
|
|
|
2276
2250
|
}
|
|
2277
2251
|
}
|
|
2278
2252
|
}
|
|
2279
|
-
return this.on(
|
|
2253
|
+
return this.on("message:text").filter((ctx) => {
|
|
2280
2254
|
const prefixes_ = prefixes.length == 0 ? [!ctx.me?.isBot ? "\\" : "/"] : prefixes;
|
|
2281
2255
|
if (prefixes_.length == 0) {
|
|
2282
2256
|
return false;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface MutexInterface {
|
|
2
|
+
acquire(): Promise<MutexInterface.Releaser>;
|
|
3
|
+
runExclusive<T>(callback: MutexInterface.Worker<T>): Promise<T>;
|
|
4
|
+
waitForUnlock(): Promise<void>;
|
|
5
|
+
isLocked(): boolean;
|
|
6
|
+
release(): void;
|
|
7
|
+
cancel(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare namespace MutexInterface {
|
|
10
|
+
interface Releaser {
|
|
11
|
+
(): void;
|
|
12
|
+
}
|
|
13
|
+
interface Worker<T> {
|
|
14
|
+
(): Promise<T> | T;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export declare class Mutex implements MutexInterface {
|
|
18
|
+
constructor(cancelError?: Error);
|
|
19
|
+
acquire(): Promise<MutexInterface.Releaser>;
|
|
20
|
+
runExclusive<T>(callback: MutexInterface.Worker<T>): Promise<T>;
|
|
21
|
+
isLocked(): boolean;
|
|
22
|
+
waitForUnlock(): Promise<void>;
|
|
23
|
+
release(): void;
|
|
24
|
+
cancel(): void;
|
|
25
|
+
private _semaphore;
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Semaphore } from "./semaphore.js";
|
|
2
|
+
export class Mutex {
|
|
3
|
+
constructor(cancelError) {
|
|
4
|
+
Object.defineProperty(this, "_semaphore", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true,
|
|
8
|
+
value: void 0
|
|
9
|
+
});
|
|
10
|
+
this._semaphore = new Semaphore(1, cancelError);
|
|
11
|
+
}
|
|
12
|
+
async acquire() {
|
|
13
|
+
const [, releaser] = await this._semaphore.acquire();
|
|
14
|
+
return releaser;
|
|
15
|
+
}
|
|
16
|
+
runExclusive(callback) {
|
|
17
|
+
return this._semaphore.runExclusive(() => callback());
|
|
18
|
+
}
|
|
19
|
+
isLocked() {
|
|
20
|
+
return this._semaphore.isLocked();
|
|
21
|
+
}
|
|
22
|
+
waitForUnlock() {
|
|
23
|
+
return this._semaphore.waitForUnlock();
|
|
24
|
+
}
|
|
25
|
+
release() {
|
|
26
|
+
if (this._semaphore.isLocked())
|
|
27
|
+
this._semaphore.release();
|
|
28
|
+
}
|
|
29
|
+
cancel() {
|
|
30
|
+
return this._semaphore.cancel();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const E_CANCELED: Error;
|
|
2
|
+
export interface SemaphoreInterface {
|
|
3
|
+
acquire(weight?: number): Promise<[number, SemaphoreInterface.Releaser]>;
|
|
4
|
+
runExclusive<T>(callback: SemaphoreInterface.Worker<T>, weight?: number): Promise<T>;
|
|
5
|
+
waitForUnlock(weight?: number): Promise<void>;
|
|
6
|
+
isLocked(): boolean;
|
|
7
|
+
getValue(): number;
|
|
8
|
+
setValue(value: number): void;
|
|
9
|
+
release(weight?: number): void;
|
|
10
|
+
cancel(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare namespace SemaphoreInterface {
|
|
13
|
+
interface Releaser {
|
|
14
|
+
(): void;
|
|
15
|
+
}
|
|
16
|
+
interface Worker<T> {
|
|
17
|
+
(value: number): Promise<T> | T;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export interface QueueEntry {
|
|
21
|
+
resolve(result: [number, SemaphoreInterface.Releaser]): void;
|
|
22
|
+
reject(error: unknown): void;
|
|
23
|
+
}
|
|
24
|
+
export declare class Semaphore implements SemaphoreInterface {
|
|
25
|
+
private _value;
|
|
26
|
+
private _cancelError;
|
|
27
|
+
constructor(_value: number, _cancelError?: Error);
|
|
28
|
+
acquire(weight?: number): Promise<[number, SemaphoreInterface.Releaser]>;
|
|
29
|
+
runExclusive<T>(callback: SemaphoreInterface.Worker<T>, weight?: number): Promise<T>;
|
|
30
|
+
waitForUnlock(weight?: number): Promise<void>;
|
|
31
|
+
isLocked(): boolean;
|
|
32
|
+
getValue(): number;
|
|
33
|
+
setValue(value: number): void;
|
|
34
|
+
release(weight?: number): void;
|
|
35
|
+
cancel(): void;
|
|
36
|
+
private _dispatch;
|
|
37
|
+
private _newReleaser;
|
|
38
|
+
private _drainUnlockWaiters;
|
|
39
|
+
private _weightedQueues;
|
|
40
|
+
private _weightedWaiters;
|
|
41
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export const E_CANCELED = new Error("request for lock canceled");
|
|
2
|
+
export class Semaphore {
|
|
3
|
+
constructor(_value, _cancelError = E_CANCELED) {
|
|
4
|
+
Object.defineProperty(this, "_value", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true,
|
|
8
|
+
value: _value
|
|
9
|
+
});
|
|
10
|
+
Object.defineProperty(this, "_cancelError", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: _cancelError
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(this, "_weightedQueues", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: []
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "_weightedWaiters", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: []
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
acquire(weight = 1) {
|
|
30
|
+
if (weight <= 0) {
|
|
31
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
if (!this._weightedQueues[weight - 1]) {
|
|
35
|
+
this._weightedQueues[weight - 1] = [];
|
|
36
|
+
}
|
|
37
|
+
this._weightedQueues[weight - 1].push({ resolve, reject });
|
|
38
|
+
this._dispatch();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async runExclusive(callback, weight = 1) {
|
|
42
|
+
const [value, release] = await this.acquire(weight);
|
|
43
|
+
try {
|
|
44
|
+
return await callback(value);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
release();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
waitForUnlock(weight = 1) {
|
|
51
|
+
if (weight <= 0) {
|
|
52
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
53
|
+
}
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
if (!this._weightedWaiters[weight - 1]) {
|
|
56
|
+
this._weightedWaiters[weight - 1] = [];
|
|
57
|
+
}
|
|
58
|
+
this._weightedWaiters[weight - 1].push(resolve);
|
|
59
|
+
this._dispatch();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
isLocked() {
|
|
63
|
+
return this._value <= 0;
|
|
64
|
+
}
|
|
65
|
+
getValue() {
|
|
66
|
+
return this._value;
|
|
67
|
+
}
|
|
68
|
+
setValue(value) {
|
|
69
|
+
this._value = value;
|
|
70
|
+
this._dispatch();
|
|
71
|
+
}
|
|
72
|
+
release(weight = 1) {
|
|
73
|
+
if (weight <= 0) {
|
|
74
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
75
|
+
}
|
|
76
|
+
this._value += weight;
|
|
77
|
+
this._dispatch();
|
|
78
|
+
}
|
|
79
|
+
cancel() {
|
|
80
|
+
this._weightedQueues.forEach((queue) => queue.forEach((entry) => entry.reject(this._cancelError)));
|
|
81
|
+
this._weightedQueues = [];
|
|
82
|
+
}
|
|
83
|
+
_dispatch() {
|
|
84
|
+
for (let weight = this._value; weight > 0; weight--) {
|
|
85
|
+
const queueEntry = this._weightedQueues[weight - 1]?.shift();
|
|
86
|
+
if (!queueEntry)
|
|
87
|
+
continue;
|
|
88
|
+
const previousValue = this._value;
|
|
89
|
+
const previousWeight = weight;
|
|
90
|
+
this._value -= weight;
|
|
91
|
+
weight = this._value + 1;
|
|
92
|
+
queueEntry.resolve([previousValue, this._newReleaser(previousWeight)]);
|
|
93
|
+
}
|
|
94
|
+
this._drainUnlockWaiters();
|
|
95
|
+
}
|
|
96
|
+
_newReleaser(weight) {
|
|
97
|
+
let called = false;
|
|
98
|
+
return () => {
|
|
99
|
+
if (called)
|
|
100
|
+
return;
|
|
101
|
+
called = true;
|
|
102
|
+
this.release(weight);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
_drainUnlockWaiters() {
|
|
106
|
+
for (let weight = this._value; weight > 0; weight--) {
|
|
107
|
+
if (!this._weightedWaiters[weight - 1])
|
|
108
|
+
continue;
|
|
109
|
+
this._weightedWaiters[weight - 1].forEach((waiter) => waiter());
|
|
110
|
+
this._weightedWaiters[weight - 1] = [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -56,7 +56,7 @@ export class StorageLocalStorage extends Storage {
|
|
|
56
56
|
if (params?.limit !== undefined) {
|
|
57
57
|
entries = entries.slice(0, params.limit <= 0 ? 1 : params.limit);
|
|
58
58
|
}
|
|
59
|
-
for (let [key, value] of entries) {
|
|
59
|
+
entries: for (let [key, value] of entries) {
|
|
60
60
|
if (key.startsWith(this.prefix)) {
|
|
61
61
|
key = key.slice(this.prefix.length);
|
|
62
62
|
}
|
|
@@ -65,7 +65,7 @@ export class StorageLocalStorage extends Storage {
|
|
|
65
65
|
if ("prefix" in filter) {
|
|
66
66
|
for (const [i, p] of filter.prefix.entries()) {
|
|
67
67
|
if (toString(p) != toString(parts[i])) {
|
|
68
|
-
continue;
|
|
68
|
+
continue entries;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -56,7 +56,7 @@ export class StorageSessionStorage extends Storage {
|
|
|
56
56
|
if (params?.limit !== undefined) {
|
|
57
57
|
entries = entries.slice(0, params.limit <= 0 ? 1 : params.limit);
|
|
58
58
|
}
|
|
59
|
-
for (let [key, value] of entries) {
|
|
59
|
+
entries: for (let [key, value] of entries) {
|
|
60
60
|
if (key.startsWith(this.prefix)) {
|
|
61
61
|
key = key.slice(this.prefix.length);
|
|
62
62
|
}
|
|
@@ -65,7 +65,7 @@ export class StorageSessionStorage extends Storage {
|
|
|
65
65
|
if ("prefix" in filter) {
|
|
66
66
|
for (const [i, p] of filter.prefix.entries()) {
|
|
67
67
|
if (toString(p) != toString(parts[i])) {
|
|
68
|
-
continue;
|
|
68
|
+
continue entries;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
}
|