kjarni-wasm 0.1.4 → 0.1.5
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 -14
- package/package.json +1 -1
- package/pkg/kjarni_wasm.d.ts +25 -2
- package/pkg/kjarni_wasm.js +72 -7
- package/pkg/kjarni_wasm_bg.wasm +0 -0
- package/pkg/kjarni_wasm_bg.wasm.d.ts +5 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# kjarni-wasm
|
|
2
2
|
|
|
3
|
-
Local AI inference in the browser. Embeddings, classification, reranking
|
|
4
|
-
running in a Web Worker so the page never freezes.
|
|
3
|
+
Local AI inference in the browser. Embeddings, classification, reranking, semantic
|
|
4
|
+
search and chat, running in a Web Worker so the page never freezes.
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
7
|
npm i kjarni-wasm
|
|
@@ -20,7 +20,9 @@ Or without a bundler, straight from a CDN:
|
|
|
20
20
|
```ts
|
|
21
21
|
import { Kjarni } from "kjarni-wasm";
|
|
22
22
|
|
|
23
|
-
const kjarni = await Kjarni.load({
|
|
23
|
+
const kjarni = await Kjarni.load({
|
|
24
|
+
encoder: "https://huggingface.co/olafuraron/all-MiniLM-L6-v2-q8/resolve/main/all-MiniLM-L6-v2-q8.kjq",
|
|
25
|
+
});
|
|
24
26
|
|
|
25
27
|
const [doctor, physician] = await kjarni.encode(["doctor", "physician"]);
|
|
26
28
|
console.log(Kjarni.cosine(doctor, physician)); // 0.8598
|
|
@@ -29,6 +31,8 @@ console.log(Kjarni.cosine(doctor, physician)); // 0.8598
|
|
|
29
31
|
console.log(await kjarni.similarity("doctor", "physician"));
|
|
30
32
|
```
|
|
31
33
|
|
|
34
|
+
That URL is a real, public 23 MB file. It downloads once, the browser caches it, and nothing else leaves the machine. See [Models](#models) for the rest, and serve them from your own origin in production rather than hotlinking.
|
|
35
|
+
|
|
32
36
|
Every method returns a promise and the work happens on a worker thread. A model
|
|
33
37
|
loads or a reply generates while the page keeps painting.
|
|
34
38
|
|
|
@@ -48,9 +52,9 @@ Models are `.kjq` files: config, tokenizer and int8 weights in one download.
|
|
|
48
52
|
|
|
49
53
|
```ts
|
|
50
54
|
const kjarni = await Kjarni.load({
|
|
51
|
-
encoder: "
|
|
52
|
-
classifier: "
|
|
53
|
-
reranker: "
|
|
55
|
+
encoder: model("all-MiniLM-L6-v2-q8"),
|
|
56
|
+
classifier: model("distilbert-sentiment-q8"),
|
|
57
|
+
reranker: model("ms-marco-MiniLM-L-6-v2-q8"),
|
|
54
58
|
onProgress: (capability, loaded, total) => {
|
|
55
59
|
console.log(`${capability}: ${Math.round((loaded / total) * 100)}%`);
|
|
56
60
|
},
|
|
@@ -85,22 +89,32 @@ for (const { index, score } of ranked) console.log(score, documents[index]);
|
|
|
85
89
|
|
|
86
90
|
## Chat
|
|
87
91
|
|
|
92
|
+
A 0.5B language model runs in the tab, and tokens arrive as they are decoded.
|
|
93
|
+
|
|
88
94
|
```ts
|
|
89
95
|
const kjarni = await Kjarni.load({
|
|
90
|
-
chat: "
|
|
96
|
+
chat: model("qwen05b-q8"),
|
|
91
97
|
chatModelId: "qwen2.5-0.5b-instruct",
|
|
92
98
|
});
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
100
|
+
let out = "";
|
|
101
|
+
for await (const piece of kjarni.chat("Explain RAG in one sentence.")) out += piece;
|
|
97
102
|
```
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
This works because the weights stay block-quantised in memory. wasm32 caps a
|
|
105
|
+
single allocation at `isize::MAX`, which is 2 GB, and Qwen2.5 0.5B expanded to f32
|
|
106
|
+
needs 1.98 GB, so a loader that dequantises up front traps on load. The `.kjq`
|
|
107
|
+
container carries block-quantised weights the engine reads in place, which is
|
|
108
|
+
500 MB rather than 1.98 GB, and decodes faster than f32 rather than slower.
|
|
109
|
+
|
|
110
|
+
Expect a few tokens per second on a laptop CPU. Run it in a Web Worker: generation
|
|
111
|
+
occupies the thread until it returns, so on the main thread the tab stops painting
|
|
112
|
+
for the whole reply.
|
|
102
113
|
|
|
103
|
-
`
|
|
114
|
+
`chat()` completes a prompt; it does not keep turns. Multi-turn conversation, where
|
|
115
|
+
the model's own chat template is applied and earlier turns are remembered, exists
|
|
116
|
+
on `WasmChat` (`send_stream`, `clear_history`) and is not yet surfaced through this
|
|
117
|
+
wrapper.
|
|
104
118
|
|
|
105
119
|
## Cleaning up
|
|
106
120
|
|
|
@@ -116,6 +130,45 @@ reference leaks the weights. `close()` frees the models and stops the worker.
|
|
|
116
130
|
A browser with WebAssembly and module workers: Chrome and Edge 80+, Firefox 114+,
|
|
117
131
|
Safari 15+. No WebGPU required, inference runs on the CPU.
|
|
118
132
|
|
|
133
|
+
## Models
|
|
134
|
+
|
|
135
|
+
`.kjq` is a single file holding config, tokenizer and int8 weights. These are
|
|
136
|
+
public and hosted on Hugging Face, one repository per model, with the repository
|
|
137
|
+
and file names matching:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const model = (name: string) =>
|
|
141
|
+
`https://huggingface.co/olafuraron/${name}/resolve/main/${name}.kjq`;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
| Pass as | Name | Size | What it does |
|
|
145
|
+
| ------- | ---- | ---- | ------------ |
|
|
146
|
+
| `encoder` | `all-MiniLM-L6-v2-q8` | 23 MB | embeddings, similarity, search |
|
|
147
|
+
| `reranker` | `ms-marco-MiniLM-L-6-v2-q8` | 23 MB | cross-encoder reranking |
|
|
148
|
+
| `classifier` | `distilbert-sentiment-q8` | 68 MB | positive / negative sentiment |
|
|
149
|
+
| `chat` | `qwen05b-q8` | 508 MB | a local language model, block-quantised so it fits |
|
|
150
|
+
|
|
151
|
+
Hugging Face serves these with permissive CORS, so a browser can fetch them from
|
|
152
|
+
any origin. For production, copy what you need and serve it from your own origin:
|
|
153
|
+
you control caching, and your page does not depend on someone else's uptime.
|
|
154
|
+
|
|
155
|
+
Load only what you use, and wire `onProgress` to something visible: these are real
|
|
156
|
+
downloads, and a silent minute reads as a broken page.
|
|
157
|
+
|
|
158
|
+
## The same engine elsewhere
|
|
159
|
+
|
|
160
|
+
Kjarni is one Rust engine behind several packages. The browser is one target; if
|
|
161
|
+
you need the server half of the same product:
|
|
162
|
+
|
|
163
|
+
- **[Live demo](https://kjarni.ai/demo/)**: this package, running in a page
|
|
164
|
+
- **[Kjarni](https://www.nuget.org/packages/Kjarni)** and
|
|
165
|
+
**[Kjarni.Extensions.AI](https://www.nuget.org/packages/Kjarni.Extensions.AI)**
|
|
166
|
+
on NuGet for C#, including `IEmbeddingGenerator` and `IChatClient`
|
|
167
|
+
- **[Go](https://pkg.go.dev/github.com/olafurjohannsson/kjarni-go)**,
|
|
168
|
+
**[C++](https://github.com/olafurjohannsson/kjarni/tree/main/crates/kjarni-ffi/examples/cpp)**
|
|
169
|
+
and a CLI that reads stdin and writes JSON
|
|
170
|
+
- **[Source and issues](https://github.com/olafurjohannsson/kjarni)**
|
|
171
|
+
|
|
119
172
|
## Making your own `.kjq`
|
|
120
173
|
|
|
121
174
|
See [the format guide](../scripts/README.md). Any BERT-family encoder,
|
package/package.json
CHANGED
package/pkg/kjarni_wasm.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export class WasmChat {
|
|
|
18
18
|
private constructor();
|
|
19
19
|
free(): void;
|
|
20
20
|
[Symbol.dispose](): void;
|
|
21
|
+
/**
|
|
22
|
+
* Drops the conversation, keeping the system prompt.
|
|
23
|
+
*/
|
|
24
|
+
clear_history(): void;
|
|
21
25
|
/**
|
|
22
26
|
* The model's context window, in tokens.
|
|
23
27
|
*/
|
|
@@ -41,6 +45,10 @@ export class WasmChat {
|
|
|
41
45
|
* itself is in `generate_stream_core`, which builds and is tested natively.
|
|
42
46
|
*/
|
|
43
47
|
generate_stream(prompt: string, max_new_tokens: number, temperature: number, on_token: Function): string;
|
|
48
|
+
/**
|
|
49
|
+
* Number of messages held, system prompt included.
|
|
50
|
+
*/
|
|
51
|
+
history_len(): number;
|
|
44
52
|
/**
|
|
45
53
|
* Load a decoder model from a `.kjq` container.
|
|
46
54
|
*
|
|
@@ -48,6 +56,18 @@ export class WasmChat {
|
|
|
48
56
|
* one the model still generates, but its turn markers will not be applied.
|
|
49
57
|
*/
|
|
50
58
|
static load(data: Uint8Array, model_id?: string | null): WasmChat;
|
|
59
|
+
/**
|
|
60
|
+
* Sends a message in an ongoing conversation, streaming the reply.
|
|
61
|
+
*
|
|
62
|
+
* Unlike `generate_stream`, which completes raw text, this keeps the turns so
|
|
63
|
+
* far and formats them with the model's own chat template, so an instruct
|
|
64
|
+
* model answers instead of continuing the sentence. The reply is appended to
|
|
65
|
+
* the history, so the next call sees it.
|
|
66
|
+
*
|
|
67
|
+
* Browser-only: `js_sys::Function` has no native equivalent. The work is in
|
|
68
|
+
* `send_stream_core`, which builds and is tested natively.
|
|
69
|
+
*/
|
|
70
|
+
send_stream(message: string, max_new_tokens: number, temperature: number, on_token: Function): string;
|
|
51
71
|
}
|
|
52
72
|
|
|
53
73
|
/**
|
|
@@ -190,10 +210,13 @@ export interface InitOutput {
|
|
|
190
210
|
readonly __wbg_wasmindexbuilder_free: (a: number, b: number) => void;
|
|
191
211
|
readonly __wbg_wasmmodel_free: (a: number, b: number) => void;
|
|
192
212
|
readonly set_debug_logging: (a: number) => void;
|
|
213
|
+
readonly wasmchat_clear_history: (a: number) => void;
|
|
193
214
|
readonly wasmchat_context_size: (a: number) => number;
|
|
194
215
|
readonly wasmchat_generate: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
195
216
|
readonly wasmchat_generate_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
217
|
+
readonly wasmchat_history_len: (a: number) => number;
|
|
196
218
|
readonly wasmchat_load: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
219
|
+
readonly wasmchat_send_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
197
220
|
readonly wasmclassifier_classify: (a: number, b: number, c: number, d: number) => void;
|
|
198
221
|
readonly wasmclassifier_classify_batch: (a: number, b: number, c: number, d: number) => void;
|
|
199
222
|
readonly wasmclassifier_labels: (a: number, b: number) => void;
|
|
@@ -225,8 +248,8 @@ export interface InitOutput {
|
|
|
225
248
|
readonly wasmsearch_add_chunk: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
|
|
226
249
|
readonly __wbg_wasmreranker_free: (a: number, b: number) => void;
|
|
227
250
|
readonly __wbg_wasmsearch_free: (a: number, b: number) => void;
|
|
228
|
-
readonly
|
|
229
|
-
readonly
|
|
251
|
+
readonly __wasm_bindgen_func_elem_5449: (a: number, b: number, c: number, d: number) => void;
|
|
252
|
+
readonly __wasm_bindgen_func_elem_5465: (a: number, b: number, c: number, d: number) => void;
|
|
230
253
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
231
254
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
232
255
|
readonly __wbindgen_export3: (a: number) => void;
|
package/pkg/kjarni_wasm.js
CHANGED
|
@@ -30,6 +30,12 @@ export class WasmChat {
|
|
|
30
30
|
const ptr = this.__destroy_into_raw();
|
|
31
31
|
wasm.__wbg_wasmchat_free(ptr, 0);
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Drops the conversation, keeping the system prompt.
|
|
35
|
+
*/
|
|
36
|
+
clear_history() {
|
|
37
|
+
wasm.wasmchat_clear_history(this.__wbg_ptr);
|
|
38
|
+
}
|
|
33
39
|
/**
|
|
34
40
|
* The model's context window, in tokens.
|
|
35
41
|
* @returns {number}
|
|
@@ -117,6 +123,14 @@ export class WasmChat {
|
|
|
117
123
|
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
118
124
|
}
|
|
119
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Number of messages held, system prompt included.
|
|
128
|
+
* @returns {number}
|
|
129
|
+
*/
|
|
130
|
+
history_len() {
|
|
131
|
+
const ret = wasm.wasmchat_history_len(this.__wbg_ptr);
|
|
132
|
+
return ret >>> 0;
|
|
133
|
+
}
|
|
120
134
|
/**
|
|
121
135
|
* Load a decoder model from a `.kjq` container.
|
|
122
136
|
*
|
|
@@ -145,6 +159,49 @@ export class WasmChat {
|
|
|
145
159
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
146
160
|
}
|
|
147
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Sends a message in an ongoing conversation, streaming the reply.
|
|
164
|
+
*
|
|
165
|
+
* Unlike `generate_stream`, which completes raw text, this keeps the turns so
|
|
166
|
+
* far and formats them with the model's own chat template, so an instruct
|
|
167
|
+
* model answers instead of continuing the sentence. The reply is appended to
|
|
168
|
+
* the history, so the next call sees it.
|
|
169
|
+
*
|
|
170
|
+
* Browser-only: `js_sys::Function` has no native equivalent. The work is in
|
|
171
|
+
* `send_stream_core`, which builds and is tested natively.
|
|
172
|
+
* @param {string} message
|
|
173
|
+
* @param {number} max_new_tokens
|
|
174
|
+
* @param {number} temperature
|
|
175
|
+
* @param {Function} on_token
|
|
176
|
+
* @returns {string}
|
|
177
|
+
*/
|
|
178
|
+
send_stream(message, max_new_tokens, temperature, on_token) {
|
|
179
|
+
let deferred3_0;
|
|
180
|
+
let deferred3_1;
|
|
181
|
+
try {
|
|
182
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
183
|
+
const ptr0 = passStringToWasm0(message, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
184
|
+
const len0 = WASM_VECTOR_LEN;
|
|
185
|
+
wasm.wasmchat_send_stream(retptr, this.__wbg_ptr, ptr0, len0, max_new_tokens, temperature, addBorrowedObject(on_token));
|
|
186
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
187
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
188
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
189
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
190
|
+
var ptr2 = r0;
|
|
191
|
+
var len2 = r1;
|
|
192
|
+
if (r3) {
|
|
193
|
+
ptr2 = 0; len2 = 0;
|
|
194
|
+
throw takeObject(r2);
|
|
195
|
+
}
|
|
196
|
+
deferred3_0 = ptr2;
|
|
197
|
+
deferred3_1 = len2;
|
|
198
|
+
return getStringFromWasm0(ptr2, len2);
|
|
199
|
+
} finally {
|
|
200
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
201
|
+
heap[stack_pointer++] = undefined;
|
|
202
|
+
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
148
205
|
}
|
|
149
206
|
if (Symbol.dispose) WasmChat.prototype[Symbol.dispose] = WasmChat.prototype.free;
|
|
150
207
|
|
|
@@ -1035,7 +1092,7 @@ function __wbg_get_imports() {
|
|
|
1035
1092
|
const a = state0.a;
|
|
1036
1093
|
state0.a = 0;
|
|
1037
1094
|
try {
|
|
1038
|
-
return
|
|
1095
|
+
return __wasm_bindgen_func_elem_5465(a, state0.b, arg0, arg1);
|
|
1039
1096
|
} finally {
|
|
1040
1097
|
state0.a = a;
|
|
1041
1098
|
}
|
|
@@ -1058,6 +1115,14 @@ function __wbg_get_imports() {
|
|
|
1058
1115
|
const ret = Date.now();
|
|
1059
1116
|
return ret;
|
|
1060
1117
|
},
|
|
1118
|
+
__wbg_now_e7c6795a7f81e10f: function(arg0) {
|
|
1119
|
+
const ret = getObject(arg0).now();
|
|
1120
|
+
return ret;
|
|
1121
|
+
},
|
|
1122
|
+
__wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
|
|
1123
|
+
const ret = getObject(arg0).performance;
|
|
1124
|
+
return addHeapObject(ret);
|
|
1125
|
+
},
|
|
1061
1126
|
__wbg_process_44c7a14e11e9f69e: function(arg0) {
|
|
1062
1127
|
const ret = getObject(arg0).process;
|
|
1063
1128
|
return addHeapObject(ret);
|
|
@@ -1141,8 +1206,8 @@ function __wbg_get_imports() {
|
|
|
1141
1206
|
return addHeapObject(ret);
|
|
1142
1207
|
},
|
|
1143
1208
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
1144
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
1145
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
1209
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 2043, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
1210
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_5449);
|
|
1146
1211
|
return addHeapObject(ret);
|
|
1147
1212
|
},
|
|
1148
1213
|
__wbindgen_cast_0000000000000002: function(arg0) {
|
|
@@ -1179,10 +1244,10 @@ function __wbg_get_imports() {
|
|
|
1179
1244
|
};
|
|
1180
1245
|
}
|
|
1181
1246
|
|
|
1182
|
-
function
|
|
1247
|
+
function __wasm_bindgen_func_elem_5449(arg0, arg1, arg2) {
|
|
1183
1248
|
try {
|
|
1184
1249
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
1185
|
-
wasm.
|
|
1250
|
+
wasm.__wasm_bindgen_func_elem_5449(retptr, arg0, arg1, addHeapObject(arg2));
|
|
1186
1251
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
1187
1252
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
1188
1253
|
if (r1) {
|
|
@@ -1193,8 +1258,8 @@ function __wasm_bindgen_func_elem_5410(arg0, arg1, arg2) {
|
|
|
1193
1258
|
}
|
|
1194
1259
|
}
|
|
1195
1260
|
|
|
1196
|
-
function
|
|
1197
|
-
wasm.
|
|
1261
|
+
function __wasm_bindgen_func_elem_5465(arg0, arg1, arg2, arg3) {
|
|
1262
|
+
wasm.__wasm_bindgen_func_elem_5465(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
1198
1263
|
}
|
|
1199
1264
|
|
|
1200
1265
|
const WasmChatFinalization = (typeof FinalizationRegistry === 'undefined')
|
package/pkg/kjarni_wasm_bg.wasm
CHANGED
|
Binary file
|
|
@@ -7,10 +7,13 @@ export const __wbg_wasmencoder_free: (a: number, b: number) => void;
|
|
|
7
7
|
export const __wbg_wasmindexbuilder_free: (a: number, b: number) => void;
|
|
8
8
|
export const __wbg_wasmmodel_free: (a: number, b: number) => void;
|
|
9
9
|
export const set_debug_logging: (a: number) => void;
|
|
10
|
+
export const wasmchat_clear_history: (a: number) => void;
|
|
10
11
|
export const wasmchat_context_size: (a: number) => number;
|
|
11
12
|
export const wasmchat_generate: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
12
13
|
export const wasmchat_generate_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
14
|
+
export const wasmchat_history_len: (a: number) => number;
|
|
13
15
|
export const wasmchat_load: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
16
|
+
export const wasmchat_send_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
14
17
|
export const wasmclassifier_classify: (a: number, b: number, c: number, d: number) => void;
|
|
15
18
|
export const wasmclassifier_classify_batch: (a: number, b: number, c: number, d: number) => void;
|
|
16
19
|
export const wasmclassifier_labels: (a: number, b: number) => void;
|
|
@@ -42,8 +45,8 @@ export const wasmsearch_doc_count: (a: number) => number;
|
|
|
42
45
|
export const wasmsearch_add_chunk: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
|
|
43
46
|
export const __wbg_wasmreranker_free: (a: number, b: number) => void;
|
|
44
47
|
export const __wbg_wasmsearch_free: (a: number, b: number) => void;
|
|
45
|
-
export const
|
|
46
|
-
export const
|
|
48
|
+
export const __wasm_bindgen_func_elem_5449: (a: number, b: number, c: number, d: number) => void;
|
|
49
|
+
export const __wasm_bindgen_func_elem_5465: (a: number, b: number, c: number, d: number) => void;
|
|
47
50
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
48
51
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
49
52
|
export const __wbindgen_export3: (a: number) => void;
|