@qping/plugin-bus 0.8.0 → 0.10.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/dist/bootstrap.mjs +0 -12
- package/dist/i18n.mjs +1 -1
- package/dist/node.mjs +0 -12
- package/dist/search.d.ts +3 -0
- package/dist/search.mjs +24413 -3
- package/dist/webClient.mjs +1 -1
- package/package.json +3 -2
- package/src/bootstrap.ts +0 -15
- package/src/search.ts +55 -22
package/dist/webClient.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qping/plugin-bus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "v3 message-bus runtime for MyTools plugins (named-pipe transport).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"./package.json": "./package.json"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"i18next": "^26.4.0"
|
|
49
|
+
"i18next": "^26.4.0",
|
|
50
|
+
"pinyin-pro": "3.29.4"
|
|
50
51
|
},
|
|
51
52
|
"scripts": {
|
|
52
53
|
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
package/src/bootstrap.ts
CHANGED
|
@@ -46,25 +46,11 @@ export async function runPlugin(handlers: PluginHandlers): Promise<PluginRuntime
|
|
|
46
46
|
const router = new HandlerRouter({ send: (env: Envelope) => transport.send(env) });
|
|
47
47
|
router.setIdentity(identity);
|
|
48
48
|
|
|
49
|
-
// Passive host-liveness watchdog: exit if Host stops sending bus.ping (orphan process).
|
|
50
|
-
// Threshold is well above the host ping interval (~2s) to tolerate brief host stalls.
|
|
51
|
-
const HOST_LOST_MS = 15_000;
|
|
52
|
-
let lastPingAt = Date.now();
|
|
53
|
-
const watchdog = setInterval(() => {
|
|
54
|
-
if (Date.now() - lastPingAt > HOST_LOST_MS) {
|
|
55
|
-
clearInterval(watchdog);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
}, 1_000);
|
|
59
|
-
watchdog.unref?.();
|
|
60
|
-
|
|
61
49
|
transport.onDisconnect(() => {
|
|
62
|
-
clearInterval(watchdog);
|
|
63
50
|
process.exit(1);
|
|
64
51
|
});
|
|
65
52
|
|
|
66
53
|
transport.onMessage((env) => {
|
|
67
|
-
if (env.route === Routes.Bus.Ping) lastPingAt = Date.now();
|
|
68
54
|
router.dispatch(env);
|
|
69
55
|
});
|
|
70
56
|
|
|
@@ -76,7 +62,6 @@ export async function runPlugin(handlers: PluginHandlers): Promise<PluginRuntime
|
|
|
76
62
|
transport,
|
|
77
63
|
router,
|
|
78
64
|
close: async () => {
|
|
79
|
-
clearInterval(watchdog);
|
|
80
65
|
await transport.close();
|
|
81
66
|
},
|
|
82
67
|
};
|
package/src/search.ts
CHANGED
|
@@ -1,22 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { pinyin } from "pinyin-pro";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns whether every character in `pattern` occurs in `target` in the same order.
|
|
5
|
+
* Matching is case-insensitive and characters do not need to be adjacent.
|
|
6
|
+
*
|
|
7
|
+
* @example isSubsequence("gthb", "GitHub") // true
|
|
8
|
+
*/
|
|
9
|
+
export function isSubsequence(pattern: string, target: string): boolean {
|
|
10
|
+
if (!pattern) return true;
|
|
11
|
+
if (!target) return false;
|
|
12
|
+
|
|
13
|
+
const needle = normalizeSearchText(pattern);
|
|
14
|
+
const haystack = normalizeSearchText(target);
|
|
15
|
+
let patternIndex = 0;
|
|
16
|
+
|
|
17
|
+
for (let targetIndex = 0; targetIndex < haystack.length && patternIndex < needle.length; targetIndex += 1) {
|
|
18
|
+
if (haystack[targetIndex] === needle[patternIndex]) {
|
|
19
|
+
patternIndex += 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return patternIndex === needle.length;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function normalizeSearchText(text: string): string {
|
|
27
|
+
return text.normalize(searchNormalizationForm).toLowerCase().replace(/\s+/gu, normalizedWordSeparator).trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const titleVariantCacheLimit = 4096;
|
|
31
|
+
const searchNormalizationForm = "NFKC";
|
|
32
|
+
const normalizedWordSeparator = " ";
|
|
33
|
+
const pinyinOptions = { toneType: "none", type: "array" } as const;
|
|
34
|
+
|
|
35
|
+
const titleVariants = new Map<string, string[]>();
|
|
36
|
+
|
|
37
|
+
/** Compatible title recall: original text, multiword, pinyin and initials. */
|
|
38
|
+
export function matchesSearchText(query: string, title: string): boolean {
|
|
39
|
+
const needle = normalizeSearchText(query);
|
|
40
|
+
const target = normalizeSearchText(title);
|
|
41
|
+
if (!needle) return true;
|
|
42
|
+
if (isSubsequence(needle, target)) return true;
|
|
43
|
+
const terms = needle.split(normalizedWordSeparator);
|
|
44
|
+
if (terms.length > 1 && terms.every(term => target.includes(term))) return true;
|
|
45
|
+
let variants = titleVariants.get(target);
|
|
46
|
+
if (!variants) {
|
|
47
|
+
if (titleVariants.size > titleVariantCacheLimit) titleVariants.clear();
|
|
48
|
+
// Convert each character to agree with the host's character-based pinyin conversion.
|
|
49
|
+
const syllables = Array.from(target, c => pinyin(c, pinyinOptions).join(""));
|
|
50
|
+
variants = [syllables.join(""), syllables.map(s => s[0] ?? "").join(""),
|
|
51
|
+
(target.match(/[\p{L}\p{N}]+/gu) ?? []).map(word => word[0]).join("")];
|
|
52
|
+
titleVariants.set(target, variants);
|
|
53
|
+
}
|
|
54
|
+
return variants.some(variant => isSubsequence(needle, variant));
|
|
55
|
+
}
|