webmcpx 0.0.0-stage → 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 +41 -2
- package/package.json +45 -4
- package/src/auto.js +4 -0
- package/src/generated.js +19 -0
- package/src/index.d.ts +42 -0
- package/src/index.js +139 -0
- package/wasm/webmcpx_wasm.js +264 -0
- package/wasm/webmcpx_wasm_bg.wasm +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The webmcpx contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# webmcpx
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Make your site agent-ready with one script tag.** webmcpx registers standard
|
|
4
|
+
[WebMCP](https://webmachinelearning.github.io/webmcp/) tools on any page, so AI agents in the browser
|
|
5
|
+
call a function instead of reading and clicking through the page.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/webmcpx/src/auto.js"></script>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or from npm (`npm i webmcpx`):
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { register } from "webmcpx";
|
|
15
|
+
|
|
16
|
+
const { registered, dispose } = await register({
|
|
17
|
+
// Optional: also expose your backend search as `search_site`.
|
|
18
|
+
searchSite: async (query, { limit }) => (await fetch(`/api/search?q=${query}&n=${limit}`)).json(),
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Tool | What the agent gets |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `get_page_context` | Title, URL, language, meta description, heading outline, the user's selection |
|
|
25
|
+
| `search_page` | BM25-ranked passages of the main content, each linked to its section |
|
|
26
|
+
| `fetch_as_markdown` | The main content as Markdown, paged with `cursor` |
|
|
27
|
+
| `search_site` | Your site search, with limits and a uniform result shape (when `searchSite` is given) |
|
|
28
|
+
|
|
29
|
+
- **One result shape.** Every tool resolves with `{ ok, data, truncated?, next_cursor?, hint? }` or
|
|
30
|
+
`{ ok: false, error: { code, message, retryable }, hint? }`.
|
|
31
|
+
- **Output budgets and paging.** Results stay within about 2,000 characters by default.
|
|
32
|
+
- **Annotations set for you:** `readOnlyHint` and `untrustedContentHint`.
|
|
33
|
+
- **Invisible characters stripped** from page text.
|
|
34
|
+
- **A no-op where WebMCP is missing.** Uses `document.modelContext`, with a `navigator.modelContext`
|
|
35
|
+
fallback.
|
|
36
|
+
- **About 2.7 KB brotli on page load.** The WebAssembly engine loads on the first tool call.
|
|
37
|
+
|
|
38
|
+
Check your own tools with the [`webmcpx` linter](https://crates.io/crates/webmcpx), and scan any site at
|
|
39
|
+
[webmcpx.dev](https://webmcpx.dev).
|
|
40
|
+
|
|
41
|
+
WebMCP is a W3C Community Group draft, not a W3C standard. MIT licensed;
|
|
42
|
+
[source and docs](https://github.com/webmcpx/webmcpx).
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webmcpx",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Standard WebMCP tools for any website: one script tag, zero config.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://webmcpx.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/webmcpx/webmcpx.git",
|
|
11
|
+
"directory": "packages/webmcpx"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"webmcp",
|
|
15
|
+
"mcp",
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"model-context",
|
|
18
|
+
"wasm"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./src/index.d.ts",
|
|
23
|
+
"default": "./src/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./auto": "./src/auto.js"
|
|
26
|
+
},
|
|
27
|
+
"types": "./src/index.d.ts",
|
|
28
|
+
"files": [
|
|
29
|
+
"src",
|
|
30
|
+
"wasm/webmcpx_wasm.js",
|
|
31
|
+
"wasm/webmcpx_wasm_bg.wasm",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./src/auto.js"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "node --test"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"linkedom": "0.18.15"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/webmcpx/webmcpx/issues"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/auto.js
ADDED
package/src/generated.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// @generated by `just gen` from crates/webmcpx-std. Do not edit.
|
|
2
|
+
|
|
3
|
+
export const TOOLS = {
|
|
4
|
+
get_page_context: {"name":"get_page_context","title":"Get page context","description":"Describe the page the user is on: title, URL, language, meta description, heading outline and the text the user has selected. Use it for the page's structure or the user's selection; to find a fact on the page, call search_page instead.","inputSchema":{"type":"object","properties":{},"additionalProperties":false},"annotations":{"readOnlyHint":true,"untrustedContentHint":true}},
|
|
5
|
+
search_page: {"name":"search_page","title":"Search this page","description":"Find passages on the current page that match a query. Returns up to `limit` passages ranked by relevance, each with its section heading and a link to it. Prefer it to reading the whole page when looking for something specific.","inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Words to look for."},"limit":{"type":"integer","minimum":1,"maximum":20,"default":5,"description":"Maximum passages to return."}},"required":["query"],"additionalProperties":false},"annotations":{"readOnlyHint":true,"untrustedContentHint":true}},
|
|
6
|
+
fetch_as_markdown: {"name":"fetch_as_markdown","title":"Read page as Markdown","description":"Return the main content of the current page as Markdown. Long pages come in parts: when `truncated` is true, call again with `cursor` set to `next_cursor`.","inputSchema":{"type":"object","properties":{"cursor":{"type":"string","description":"The next_cursor value from a previous call."},"max_chars":{"type":"integer","minimum":100,"maximum":20000,"default":2000,"description":"Maximum characters to return."}},"additionalProperties":false},"annotations":{"readOnlyHint":true,"untrustedContentHint":true}},
|
|
7
|
+
search_site: {"name":"search_site","title":"Search this website","description":"Search the whole website and return matching pages with title, URL and a short snippet. Use it to find pages other than the current one.","inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Words to look for."},"limit":{"type":"integer","minimum":1,"maximum":20,"default":5,"description":"Maximum pages to return."}},"required":["query"],"additionalProperties":false},"annotations":{"readOnlyHint":true,"untrustedContentHint":true}},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Error code -> retryable. */
|
|
11
|
+
export const CODES = {
|
|
12
|
+
INVALID_INPUT: false,
|
|
13
|
+
NOT_FOUND: false,
|
|
14
|
+
RESULT_TOO_LARGE: false,
|
|
15
|
+
REFUSED: false,
|
|
16
|
+
RATE_LIMITED: true,
|
|
17
|
+
REQUIRES_USER: false,
|
|
18
|
+
UNAVAILABLE: true,
|
|
19
|
+
};
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type ToolName = "get_page_context" | "search_page" | "fetch_as_markdown" | "search_site";
|
|
2
|
+
|
|
3
|
+
export interface SiteSearchResult {
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
snippet?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Options {
|
|
10
|
+
/** Tools to register. Default: get_page_context, search_page, fetch_as_markdown (+ search_site when `searchSite` is set). */
|
|
11
|
+
tools?: ToolName[];
|
|
12
|
+
/** Element (or selector) holding the main content. Default: `main`, `[role=main]`, `article`, else `body`. */
|
|
13
|
+
root?: Element | string;
|
|
14
|
+
/** Backend search for `search_site`. Return results best first. */
|
|
15
|
+
searchSite?: (query: string, options: { limit: number; signal?: AbortSignal }) => Promise<SiteSearchResult[]>;
|
|
16
|
+
/** Where to load the WebAssembly module from (URL, Response or bytes). Default: next to the loader. */
|
|
17
|
+
wasm?: string | URL | Response | BufferSource | WebAssembly.Module;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Registration {
|
|
21
|
+
registered: ToolName[];
|
|
22
|
+
failed: { name: string; error: string }[];
|
|
23
|
+
/** Unregisters every tool registered by this call. */
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Registers webmcpx standard tools. A no-op (empty `registered`) where WebMCP is unavailable. */
|
|
28
|
+
export function register(options?: Options): Promise<Registration>;
|
|
29
|
+
|
|
30
|
+
/** The tool contracts (name, title, description, inputSchema, annotations). */
|
|
31
|
+
export const TOOLS: Record<ToolName, {
|
|
32
|
+
name: ToolName;
|
|
33
|
+
title: string;
|
|
34
|
+
description: string;
|
|
35
|
+
inputSchema: object;
|
|
36
|
+
annotations: Record<string, boolean>;
|
|
37
|
+
}>;
|
|
38
|
+
|
|
39
|
+
/** What every tool resolves with (as a JSON string). */
|
|
40
|
+
export type Envelope<T = unknown> =
|
|
41
|
+
| { ok: true; data: T; truncated?: true; next_cursor?: string; hint?: string }
|
|
42
|
+
| { ok: false; error: { code: string; message: string; retryable: boolean }; hint?: string };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// webmcpx loader: registers the standard WebMCP tools. Owns the DOM and registerTool();
|
|
2
|
+
// all text processing runs in a WebAssembly module loaded on the first tool call.
|
|
3
|
+
import { CODES, TOOLS } from "./generated.js";
|
|
4
|
+
|
|
5
|
+
const RECORD = "\x1e";
|
|
6
|
+
const FIELD = "\x1f";
|
|
7
|
+
const KINDS = {
|
|
8
|
+
H1: "h1", H2: "h2", H3: "h3", H4: "h4", H5: "h5", H6: "h6",
|
|
9
|
+
P: "p", LI: "li", PRE: "pre", BLOCKQUOTE: "quote",
|
|
10
|
+
DT: "p", DD: "p", FIGCAPTION: "p", SUMMARY: "p",
|
|
11
|
+
};
|
|
12
|
+
const SKIP = new Set(["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE", "SVG", "NAV", "FOOTER", "ASIDE"]);
|
|
13
|
+
const DEFAULT_TOOLS = ["get_page_context", "search_page", "fetch_as_markdown"];
|
|
14
|
+
|
|
15
|
+
const envelope = (body) => JSON.stringify(body);
|
|
16
|
+
const ok = (data) => envelope({ ok: true, data });
|
|
17
|
+
const err = (code, message, hint) =>
|
|
18
|
+
envelope({ ok: false, error: { code, message, retryable: CODES[code] }, ...(hint && { hint }) });
|
|
19
|
+
|
|
20
|
+
let wasm;
|
|
21
|
+
const engine = (source) =>
|
|
22
|
+
(wasm ??= import("../wasm/webmcpx_wasm.js")
|
|
23
|
+
.then(async (m) => (await m.default(source ? { module_or_path: source } : undefined), m))
|
|
24
|
+
.catch((e) => {
|
|
25
|
+
wasm = undefined;
|
|
26
|
+
throw e;
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
const pageUrl = () => location.href.split("#")[0];
|
|
30
|
+
const text = (s) => (s ?? "").replace(/\s+/g, " ").trim();
|
|
31
|
+
|
|
32
|
+
const skipped = (el) => SKIP.has(el.tagName) || el.hasAttribute("hidden") || el.getAttribute("aria-hidden") === "true";
|
|
33
|
+
|
|
34
|
+
/** Serializes readable content of `root` as a block stream (see webmcpx-std `blocks`). */
|
|
35
|
+
function blocks(root) {
|
|
36
|
+
let out = "";
|
|
37
|
+
let anchor = "";
|
|
38
|
+
const base = pageUrl();
|
|
39
|
+
const visit = (el) => {
|
|
40
|
+
for (const child of el.children) {
|
|
41
|
+
if (skipped(child)) continue;
|
|
42
|
+
if (child.id) anchor = `${base}#${child.id}`;
|
|
43
|
+
// A table row is one block ("Monday | Closed"), so search keeps a value next to its label.
|
|
44
|
+
const row = child.tagName === "TR" && [...child.children].filter((c) => !skipped(c)).map((c) => text(c.textContent)).join(" | ");
|
|
45
|
+
const kind = row ? "p" : KINDS[child.tagName] ?? (child.children.length === 0 && "p");
|
|
46
|
+
if (kind) out += kind + FIELD + (row || child.textContent) + FIELD + anchor + RECORD;
|
|
47
|
+
else visit(child);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
visit(root);
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function contentRoot(root) {
|
|
55
|
+
if (typeof root === "string") return document.querySelector(root) ?? document.body;
|
|
56
|
+
return root ?? document.querySelector("main, [role=main], article") ?? document.body;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function pageContext() {
|
|
60
|
+
const base = pageUrl();
|
|
61
|
+
return ok({
|
|
62
|
+
title: document.title,
|
|
63
|
+
url: location.href,
|
|
64
|
+
lang: document.documentElement.lang || undefined,
|
|
65
|
+
description: document.querySelector('meta[name="description"]')?.getAttribute("content") || undefined,
|
|
66
|
+
headings: [...document.querySelectorAll("h1, h2, h3")].slice(0, 30).map((h) => ({
|
|
67
|
+
level: Number(h.tagName[1]),
|
|
68
|
+
text: text(h.textContent).slice(0, 120),
|
|
69
|
+
url: h.id ? `${base}#${h.id}` : undefined,
|
|
70
|
+
})),
|
|
71
|
+
selection: text(globalThis.getSelection?.()?.toString()).slice(0, 1000) || undefined,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function executors(options) {
|
|
76
|
+
const withEngine = (run) => async (input) => {
|
|
77
|
+
let m;
|
|
78
|
+
try {
|
|
79
|
+
m = await engine(options.wasm);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return err("UNAVAILABLE", `WebAssembly could not load: ${e?.message ?? e}`,
|
|
82
|
+
"If the page sets a Content-Security-Policy, add 'wasm-unsafe-eval' to script-src.");
|
|
83
|
+
}
|
|
84
|
+
return run(m, blocks(contentRoot(options.root)), input);
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
get_page_context: async () => pageContext(),
|
|
88
|
+
search_page: withEngine((m, page, { query, limit }) =>
|
|
89
|
+
typeof query === "string" ? m.search(page, query, limit ?? 0) : err("INVALID_INPUT", "`query` must be a string")),
|
|
90
|
+
fetch_as_markdown: withEngine((m, page, { cursor, max_chars }) => m.markdown(page, String(cursor ?? ""), max_chars ?? 0)),
|
|
91
|
+
search_site: async ({ query, limit = 5 }, { signal } = {}) => {
|
|
92
|
+
if (typeof query !== "string" || !query.trim()) return err("INVALID_INPUT", "`query` must be a non-empty string");
|
|
93
|
+
const found = await options.searchSite(query, { limit, signal });
|
|
94
|
+
if (!found?.length) return err("NOT_FOUND", "no page matches the query", "Try fewer or different words.");
|
|
95
|
+
return ok({ results: found.slice(0, limit).map(({ title, url, snippet }) => ({ title, url, snippet })) });
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Tools resolve with an envelope and never reject: hosts drop rejection reasons (webmcp#282). */
|
|
101
|
+
const guard = (run) => async (input, client) => {
|
|
102
|
+
try {
|
|
103
|
+
return await run(typeof input === "string" ? JSON.parse(input || "{}") : input ?? {}, client);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return err("UNAVAILABLE", String(e?.message ?? e));
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Registers webmcpx standard tools on the current document.
|
|
111
|
+
* @param {import("./index").Options} [options]
|
|
112
|
+
* @returns {Promise<import("./index").Registration>}
|
|
113
|
+
*/
|
|
114
|
+
export async function register(options = {}) {
|
|
115
|
+
const mc = globalThis.document?.modelContext ?? globalThis.navigator?.modelContext;
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
const result = { registered: [], failed: [], dispose: () => controller.abort() };
|
|
118
|
+
if (typeof mc?.registerTool !== "function") return result;
|
|
119
|
+
|
|
120
|
+
const run = executors(options);
|
|
121
|
+
const names = options.tools ?? [...DEFAULT_TOOLS, ...(options.searchSite ? ["search_site"] : [])];
|
|
122
|
+
await Promise.all(names.map(async (name) => {
|
|
123
|
+
if (!TOOLS[name]) return result.failed.push({ name, error: "unknown tool" });
|
|
124
|
+
if (name === "search_site" && !options.searchSite) {
|
|
125
|
+
return result.failed.push({ name, error: "search_site needs options.searchSite" });
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
// Never assign onto `mc`: some agent browsers expose a frozen object (webmcp#293).
|
|
129
|
+
await mc.registerTool({ ...TOOLS[name], execute: guard(run[name]) }, { signal: controller.signal });
|
|
130
|
+
result.registered.push(name);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
result.failed.push({ name, error: String(e?.message ?? e) });
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
result.registered.sort();
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { TOOLS };
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fetch_as_markdown` over a block stream.
|
|
3
|
+
* @param {string} blocks
|
|
4
|
+
* @param {string} cursor
|
|
5
|
+
* @param {number} max_chars
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function markdown(blocks, cursor, max_chars) {
|
|
9
|
+
let deferred4_0;
|
|
10
|
+
let deferred4_1;
|
|
11
|
+
try {
|
|
12
|
+
const val3 = +max_chars;
|
|
13
|
+
let ptr0, len0, ptr1, len1;
|
|
14
|
+
try {
|
|
15
|
+
ptr0 = passStringToWasm0(blocks, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
16
|
+
len0 = WASM_VECTOR_LEN;
|
|
17
|
+
ptr1 = passStringToWasm0(cursor, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
18
|
+
len1 = WASM_VECTOR_LEN;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
if (ptr1) { wasm.__wbindgen_free(ptr1, len1 * 1, 1); }
|
|
21
|
+
if (ptr0) { wasm.__wbindgen_free(ptr0, len0 * 1, 1); }
|
|
22
|
+
throw e;
|
|
23
|
+
}
|
|
24
|
+
const ret = wasm.markdown(ptr0, len0, ptr1, len1, val3);
|
|
25
|
+
deferred4_0 = ret[0];
|
|
26
|
+
deferred4_1 = ret[1];
|
|
27
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
28
|
+
} finally {
|
|
29
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* `search_page` over a block stream.
|
|
35
|
+
* @param {string} blocks
|
|
36
|
+
* @param {string} query
|
|
37
|
+
* @param {number} limit
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
export function search(blocks, query, limit) {
|
|
41
|
+
let deferred4_0;
|
|
42
|
+
let deferred4_1;
|
|
43
|
+
try {
|
|
44
|
+
const val3 = +limit;
|
|
45
|
+
let ptr0, len0, ptr1, len1;
|
|
46
|
+
try {
|
|
47
|
+
ptr0 = passStringToWasm0(blocks, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
48
|
+
len0 = WASM_VECTOR_LEN;
|
|
49
|
+
ptr1 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
50
|
+
len1 = WASM_VECTOR_LEN;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
if (ptr1) { wasm.__wbindgen_free(ptr1, len1 * 1, 1); }
|
|
53
|
+
if (ptr0) { wasm.__wbindgen_free(ptr0, len0 * 1, 1); }
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
const ret = wasm.search(ptr0, len0, ptr1, len1, val3);
|
|
57
|
+
deferred4_0 = ret[0];
|
|
58
|
+
deferred4_1 = ret[1];
|
|
59
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
60
|
+
} finally {
|
|
61
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function __wbg_get_imports() {
|
|
65
|
+
const import0 = {
|
|
66
|
+
__proto__: null,
|
|
67
|
+
__wbindgen_init_externref_table: function() {
|
|
68
|
+
const table = wasm.__wbindgen_externrefs;
|
|
69
|
+
table.set(0, undefined);
|
|
70
|
+
table.set(1024, undefined);
|
|
71
|
+
table.set(1025, null);
|
|
72
|
+
table.set(1026, true);
|
|
73
|
+
table.set(1027, false);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
__proto__: null,
|
|
78
|
+
"./webmcpx_wasm_bg.js": import0,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getStringFromWasm0(ptr, len) {
|
|
83
|
+
ptr = ptr >>> 0;
|
|
84
|
+
return decodeText(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let cachedUint8ArrayMemory0 = null;
|
|
88
|
+
function getUint8ArrayMemory0() {
|
|
89
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
90
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
91
|
+
}
|
|
92
|
+
return cachedUint8ArrayMemory0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
96
|
+
if (realloc === undefined) {
|
|
97
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
98
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
99
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
100
|
+
WASM_VECTOR_LEN = buf.length;
|
|
101
|
+
return ptr;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let len = arg.length;
|
|
105
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
106
|
+
|
|
107
|
+
const mem = getUint8ArrayMemory0();
|
|
108
|
+
|
|
109
|
+
let offset = 0;
|
|
110
|
+
|
|
111
|
+
for (; offset < len; offset++) {
|
|
112
|
+
const code = arg.charCodeAt(offset);
|
|
113
|
+
if (code > 0x7F) break;
|
|
114
|
+
mem[ptr + offset] = code;
|
|
115
|
+
}
|
|
116
|
+
if (offset !== len) {
|
|
117
|
+
if (offset !== 0) {
|
|
118
|
+
arg = arg.slice(offset);
|
|
119
|
+
}
|
|
120
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
121
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
122
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
123
|
+
|
|
124
|
+
offset += ret.written;
|
|
125
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
WASM_VECTOR_LEN = offset;
|
|
129
|
+
return ptr;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true });
|
|
133
|
+
cachedTextDecoder.decode();
|
|
134
|
+
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
135
|
+
let numBytesDecoded = 0;
|
|
136
|
+
function decodeText(bytes) {
|
|
137
|
+
numBytesDecoded += bytes.length;
|
|
138
|
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
139
|
+
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true });
|
|
140
|
+
cachedTextDecoder.decode();
|
|
141
|
+
numBytesDecoded = bytes.length;
|
|
142
|
+
}
|
|
143
|
+
return cachedTextDecoder.decode(bytes);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const cachedTextEncoder = new TextEncoder();
|
|
147
|
+
|
|
148
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
149
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
150
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
151
|
+
view.set(buf);
|
|
152
|
+
return {
|
|
153
|
+
read: arg.length,
|
|
154
|
+
written: buf.length
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let WASM_VECTOR_LEN = 0;
|
|
160
|
+
|
|
161
|
+
let wasmModule, wasmInstance, wasm;
|
|
162
|
+
function __wbg_finalize_init(instance, module) {
|
|
163
|
+
wasmInstance = instance;
|
|
164
|
+
wasm = instance.exports;
|
|
165
|
+
wasmModule = module;
|
|
166
|
+
cachedUint8ArrayMemory0 = null;
|
|
167
|
+
wasm.__wbindgen_start();
|
|
168
|
+
return wasm;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function __wbg_load(module, imports) {
|
|
172
|
+
if (typeof Response === 'function' && module instanceof Response) {
|
|
173
|
+
if (!module.ok) {
|
|
174
|
+
throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
|
178
|
+
try {
|
|
179
|
+
return await WebAssembly.instantiateStreaming(module, imports);
|
|
180
|
+
} catch (e) {
|
|
181
|
+
const validResponse = expectedResponseType(module.type);
|
|
182
|
+
|
|
183
|
+
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
|
|
184
|
+
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
|
185
|
+
|
|
186
|
+
} else { throw e; }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const bytes = await module.arrayBuffer();
|
|
191
|
+
return await WebAssembly.instantiate(bytes, imports);
|
|
192
|
+
} else {
|
|
193
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
194
|
+
|
|
195
|
+
if (instance instanceof WebAssembly.Instance) {
|
|
196
|
+
return { instance, module };
|
|
197
|
+
} else {
|
|
198
|
+
return instance;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function expectedResponseType(type) {
|
|
203
|
+
switch (type) {
|
|
204
|
+
case 'basic': case 'cors': case 'default': return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function initSync(module) {
|
|
211
|
+
if (wasm !== undefined) return wasm;
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if (module !== undefined) {
|
|
215
|
+
if (Object.getPrototypeOf(module) === Object.prototype) {
|
|
216
|
+
({module} = module)
|
|
217
|
+
} else {
|
|
218
|
+
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const imports = __wbg_get_imports();
|
|
223
|
+
if (!(module instanceof WebAssembly.Module)) {
|
|
224
|
+
module = new WebAssembly.Module(module);
|
|
225
|
+
}
|
|
226
|
+
const instance = new WebAssembly.Instance(module, imports);
|
|
227
|
+
return __wbg_finalize_init(instance, module);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let __wbg_init_promise;
|
|
231
|
+
async function __wbg_init(module_or_path) {
|
|
232
|
+
if (wasm !== undefined) return wasm;
|
|
233
|
+
if (__wbg_init_promise === undefined) {
|
|
234
|
+
__wbg_init_promise = __wbg_init_once(module_or_path);
|
|
235
|
+
__wbg_init_promise.catch(() => { __wbg_init_promise = undefined; });
|
|
236
|
+
}
|
|
237
|
+
return __wbg_init_promise;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function __wbg_init_once(module_or_path) {
|
|
241
|
+
|
|
242
|
+
if (module_or_path !== undefined) {
|
|
243
|
+
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
|
244
|
+
({module_or_path} = module_or_path)
|
|
245
|
+
} else {
|
|
246
|
+
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (module_or_path === undefined) {
|
|
251
|
+
module_or_path = new URL('webmcpx_wasm_bg.wasm', import.meta.url);
|
|
252
|
+
}
|
|
253
|
+
const imports = __wbg_get_imports();
|
|
254
|
+
|
|
255
|
+
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
|
256
|
+
module_or_path = fetch(module_or_path);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
|
260
|
+
|
|
261
|
+
return __wbg_finalize_init(instance, module);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export { initSync, __wbg_init as default };
|
|
Binary file
|