@muhkoo/connect 0.1.0-alpha.1
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 +365 -0
- package/dist/browser/index.js +5636 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/connect.d.ts +2548 -0
- package/dist/server/index.js +5841 -0
- package/dist/server/index.js.map +1 -0
- package/dist/workers/index.js +2528 -0
- package/dist/workers/index.js.map +1 -0
- package/package.json +127 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Muhkoo
|
|
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
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# @muhkoo/connect
|
|
2
|
+
|
|
3
|
+
Client SDK for the Muhkoo Accelerator. The headline surface is a single
|
|
4
|
+
**`Client`** that hangs everything off three namespaces —
|
|
5
|
+
`client.auth` / `client.storage` / `client.message` — backed by
|
|
6
|
+
end-to-end-encrypted messaging primitives (Double Ratchet + ECDH P-384), a
|
|
7
|
+
turnkey multi-peer `BroadcastChannel`, ZK identity + personal/shared spaces,
|
|
8
|
+
and a Cloudflare-Workers-compatible Groth16 verifier — all bundled from a
|
|
9
|
+
single TypeScript source tree.
|
|
10
|
+
|
|
11
|
+
> Status: alpha. The library is consumed in tree by `../accelerator` and the
|
|
12
|
+
> `../web` SPA.
|
|
13
|
+
|
|
14
|
+
## What's in the box
|
|
15
|
+
|
|
16
|
+
- **`Client`** — the unified entry point. `new Client({ apiKey, baseUrl })`
|
|
17
|
+
exposes `auth` (ZK register/login), `storage` (per-user encrypted KV +
|
|
18
|
+
files), and `message` (pub/sub + E2E direct messages) over one shared
|
|
19
|
+
session. This is the supported surface; everything below is a building block
|
|
20
|
+
it composes.
|
|
21
|
+
|
|
22
|
+
- **`BroadcastChannel`** — multi-peer end-to-end-encrypted "room". Wires
|
|
23
|
+
`WSTransport` (socket lifecycle, reconnect, offline queue) together with
|
|
24
|
+
`EncryptedSession` (per-peer Double Ratchet, handshake fan-out, recipient
|
|
25
|
+
filtering). Drops onto a chat protocol without changing the wire format.
|
|
26
|
+
- **`EncryptedSession`** — transport-agnostic per-peer ratchet manager. Lets you
|
|
27
|
+
bring your own transport.
|
|
28
|
+
- **`WSTransport`** — pure WebSocket lifecycle (connect / auto-reconnect /
|
|
29
|
+
buffered outbound queue / lifecycle events).
|
|
30
|
+
- **`KeyStore`** — singleton holding ECDH + ECDSA P-384 keypairs per identity,
|
|
31
|
+
with dehydrate/hydrate helpers for persistence.
|
|
32
|
+
- **`DoubleRatchet`** + **`DoubleRatchetManager`** — the underlying ratchet
|
|
33
|
+
primitives (browser/server builds only — see below).
|
|
34
|
+
- **`PersonalSpaceClient`** — HTTP client for the accelerator's
|
|
35
|
+
`/api/personal/:commitment/*` ZK-gated KV API. Generates a fresh Groth16
|
|
36
|
+
proof per request using snarkjs and the `preimagePoK` circuit.
|
|
37
|
+
- **`wrapWithPassphrase` / `unwrapWithPassphrase`** — PBKDF2-SHA256 (200k
|
|
38
|
+
iterations) + AES-256-GCM passphrase wrap. Pairs naturally with
|
|
39
|
+
`PersonalSpaceClient` for client-side payload encryption.
|
|
40
|
+
- **`verifyGroth16` / `initBn128Wasm`** — universal Groth16 verifier driven by
|
|
41
|
+
bn128.wasm. Runs anywhere WebAssembly does (Node, browsers, CF Workers).
|
|
42
|
+
Used by the accelerator's `verifyZkAuthProof`.
|
|
43
|
+
- ZK building blocks re-exported from `crypto/ZeroKnowledge` (`Field`,
|
|
44
|
+
`Poseidon`, `PreimagePoK`, `HashKnowledge`, `AuthPublicInput`,
|
|
45
|
+
`verifyHashKnowledge`, `verifyPreimagePoK`, `quickVerify`,
|
|
46
|
+
`compilePrograms`, `initializeCircuits`, `encodeToHex`, `decodeFromHex`).
|
|
47
|
+
- Messaging utilities (`Message`, `Packet`, `SerializeMessage`) and event
|
|
48
|
+
primitives (`EventCore`, `EventCoreEvents`).
|
|
49
|
+
|
|
50
|
+
## Three build targets
|
|
51
|
+
|
|
52
|
+
`yarn build` produces three bundles from one source tree. They are selected via
|
|
53
|
+
the `exports` field in `package.json`:
|
|
54
|
+
|
|
55
|
+
| Target | Entry | Output |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `browser` | `src/browser/index.ts` | `dist/browser/index.js` |
|
|
58
|
+
| `server` | `src/server/index.ts` | `dist/server/index.js` |
|
|
59
|
+
| `workers` | `src/workers/index.ts` | `dist/workers/index.js` |
|
|
60
|
+
|
|
61
|
+
The `workers` build deliberately excludes anything that pulls in
|
|
62
|
+
`snarkjs` / `ffjavascript` transitive deps (which need `URL.createObjectURL`
|
|
63
|
+
and other APIs workerd doesn't expose):
|
|
64
|
+
|
|
65
|
+
- `ZeroKnowledge.ts` — `Field`, `Poseidon`, `PreimagePoK`, `verifyPreimagePoK`,
|
|
66
|
+
etc.
|
|
67
|
+
- `Authenticator.ts`
|
|
68
|
+
- `DoubleRatchetManager.ts`
|
|
69
|
+
- `personal/` — `PersonalSpaceClient`, `wrapWithPassphrase`,
|
|
70
|
+
`unwrapWithPassphrase`
|
|
71
|
+
|
|
72
|
+
The `workers` build keeps `KeyStore`, `DoubleRatchet`, `EncryptedSession`,
|
|
73
|
+
`BroadcastChannel`, `WSTransport`, and the bn128.wasm-driven
|
|
74
|
+
`groth16-verifier` — that last one is the only viable Groth16 path on the edge.
|
|
75
|
+
|
|
76
|
+
Types in `dist/connect.d.ts` (bundled from the flat `src/browser/index.ts`
|
|
77
|
+
entry) include everything from all three runtimes so consumers can reference
|
|
78
|
+
types even when the runtime impl is absent for their target. Calling
|
|
79
|
+
`verifyGroth16` / `initBn128Wasm` works under workerd; importing
|
|
80
|
+
`PersonalSpaceClient` and calling it in a worker will fail at runtime.
|
|
81
|
+
|
|
82
|
+
### Bare specifiers and snarkjs
|
|
83
|
+
|
|
84
|
+
Browser and server builds externalize bare specifiers — the consumer's bundler
|
|
85
|
+
(or an import map for direct browser use) resolves them. The accelerator's
|
|
86
|
+
chat app provides `snarkjs` via an esm.sh import map; Node consumers add
|
|
87
|
+
`snarkjs` as a peer dependency.
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install @muhkoo/connect
|
|
93
|
+
# or: yarn add @muhkoo/connect / pnpm add @muhkoo/connect
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
ESM-only, with bundled type declarations. `snarkjs` is an **optional peer
|
|
97
|
+
dependency** — install it only if you use the ZK-proof features
|
|
98
|
+
(`PersonalSpaceClient`, shared-space writes, client-side proof generation):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install snarkjs
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Quick start
|
|
105
|
+
|
|
106
|
+
### The unified client (recommended)
|
|
107
|
+
|
|
108
|
+
`Client` is the supported entry point. One object, one app key, three
|
|
109
|
+
namespaces — `auth`, `storage`, `message` — all sharing a single session.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { Client } from "@muhkoo/connect";
|
|
113
|
+
|
|
114
|
+
const client = new Client({
|
|
115
|
+
apiKey: "mk_test_pk_…", // app / publishable key
|
|
116
|
+
baseUrl: "https://accelerator.example.dev",
|
|
117
|
+
// circuits default to `${baseUrl}/circuits/build/preimagePoK{.wasm,_0001.zkey}`
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> **`apiKey`** is transitionally optional (auth + storage work without it
|
|
122
|
+
> today) but is becoming **required** as part of productizing the Accelerator:
|
|
123
|
+
> it's how each app authenticates and gets metered/billed, and it authorizes
|
|
124
|
+
> messaging websockets. Always pass one for new integrations.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// (continued)
|
|
128
|
+
|
|
129
|
+
// Auth — deterministic ZK identity derived from (username, password).
|
|
130
|
+
const user = await client.auth.zk.login("alice", "correct horse battery staple");
|
|
131
|
+
// └ { username, commitment }
|
|
132
|
+
|
|
133
|
+
// Storage — per-user persistent KV (collection + id), encrypted at rest.
|
|
134
|
+
await client.storage.set("todos", "t1", { title: "Buy groceries", completed: false });
|
|
135
|
+
const todo = await client.storage.get("todos", "t1");
|
|
136
|
+
const ids = await client.storage.list("todos");
|
|
137
|
+
await client.storage.delete("todos", "t1");
|
|
138
|
+
|
|
139
|
+
// Message — realtime pub/sub + end-to-end-encrypted direct messages.
|
|
140
|
+
const sub = client.message.subscribe("todos", (e) => console.log("update:", e.data));
|
|
141
|
+
await client.message.publish("todos", { id: "t1", done: true });
|
|
142
|
+
await client.message.send("user:abc", { text: "Hello!" });
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`subscribe(subject)` / `publish(subject, data)` are plaintext fan-out to
|
|
146
|
+
everyone on that subject. `send("user:<id>", …)` is an **end-to-end-encrypted**
|
|
147
|
+
direct message (Double Ratchet); the recipient receives it by subscribing to
|
|
148
|
+
their *own* id — `client.message.subscribe("user:<me>", …)`. Both modes ride a
|
|
149
|
+
shared-space room websocket under the hood (opened with a short-lived signed
|
|
150
|
+
ticket); E2E delivery needs both parties online, like any ratchet.
|
|
151
|
+
|
|
152
|
+
For full **group rooms** (multi-peer E2E chat + room-scoped file sharing), use
|
|
153
|
+
`client.message.room(name)` — a shared-space handle exposing the group channel
|
|
154
|
+
(`connect`/`on`/`send`/`announce`/`peers`/`sendRaw`) plus
|
|
155
|
+
`putFile`/`getFile`. `subscribe`/`publish`/`send` are conveniences layered over
|
|
156
|
+
this same room primitive.
|
|
157
|
+
|
|
158
|
+
Auth lifecycle:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
await client.auth.zk.register({ username, password, email }); // signs in by default
|
|
162
|
+
await client.auth.zk.restore(); // re-validate a persisted token on boot
|
|
163
|
+
await client.auth.zk.unlock(password); // re-derive identity for a restored session
|
|
164
|
+
await client.auth.zk.logout();
|
|
165
|
+
client.user; // { username, commitment } | null
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Two credentials ride on every request: the app key (`X-Muhkoo-Key`) and, once
|
|
169
|
+
signed in, the user session token (`X-Muhkoo-Session`). The accelerator
|
|
170
|
+
validates the token and authorizes per-user spaces without a fresh proof per
|
|
171
|
+
call. Persist the token across reloads with a custom `sessionStore` (e.g. a
|
|
172
|
+
`localStorage`-backed one); identity material is never persisted — `unlock()`
|
|
173
|
+
re-derives it from the password when you need to decrypt or message.
|
|
174
|
+
|
|
175
|
+
> The sections below document the lower-level building blocks the client is
|
|
176
|
+
> composed from (`BroadcastChannel`, `EncryptedSession`, `PersonalSpaceClient`,
|
|
177
|
+
> the Groth16 verifier, …). Reach for them directly only when you need control
|
|
178
|
+
> the client doesn't expose.
|
|
179
|
+
|
|
180
|
+
### Multi-peer encrypted room (chat-style)
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { BroadcastChannel, BroadcastChannelEvents } from "@muhkoo/connect";
|
|
184
|
+
|
|
185
|
+
const channel = new BroadcastChannel({
|
|
186
|
+
url: "wss://accelerator.example.dev/room/abc",
|
|
187
|
+
myId: "alice@example.dev",
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
channel.on(BroadcastChannelEvents.MESSAGE, (e) => {
|
|
191
|
+
const { from, text } = e.detail;
|
|
192
|
+
console.log(`${from}: ${text}`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
channel.on(BroadcastChannelEvents.PEER_HANDSHAKE, (e) => {
|
|
196
|
+
console.log("new peer ready:", e.detail.peerId);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
await channel.connect(); // generates keys + opens WS
|
|
200
|
+
await channel.announce(); // broadcast our keyExchange (re-fires on reconnect)
|
|
201
|
+
await channel.send("hello room"); // fan-out one cipherMessage per peer
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The wire protocol is JSON frames: `{ keyExchange: ... }`, `{ cipherMessage: ... }`,
|
|
205
|
+
plus arbitrary frames you ship with `channel.sendRaw(obj)` and receive via the
|
|
206
|
+
`RAW_FRAME` event.
|
|
207
|
+
|
|
208
|
+
### Bring-your-own-transport encrypted session
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { EncryptedSession } from "@muhkoo/connect";
|
|
212
|
+
|
|
213
|
+
const session = new EncryptedSession({ myId: "alice" });
|
|
214
|
+
await session.initialize();
|
|
215
|
+
|
|
216
|
+
// outbound handshake
|
|
217
|
+
const kx = await session.getOwnKeyExchange();
|
|
218
|
+
yourTransport.send(JSON.stringify(kx));
|
|
219
|
+
|
|
220
|
+
// inbound frame
|
|
221
|
+
const result = await session.receive(JSON.parse(rawFrame));
|
|
222
|
+
if (result.kind === "plaintext") {
|
|
223
|
+
console.log("from", result.from, ":", result.text);
|
|
224
|
+
} else if (result.kind === "handshake" && result.outbound) {
|
|
225
|
+
yourTransport.send(JSON.stringify(result.outbound)); // reciprocate
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// outbound message
|
|
229
|
+
const frames = await session.encrypt("hi");
|
|
230
|
+
for (const f of frames) yourTransport.send(JSON.stringify(f));
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`EncryptedSession` assigns roles deterministically with
|
|
234
|
+
`isClient = (myId < peerId)` lexicographically and dedups handshake
|
|
235
|
+
reciprocation with an internal `sentHandshakeTo` set.
|
|
236
|
+
|
|
237
|
+
### ZK-gated personal storage
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import {
|
|
241
|
+
PersonalSpaceClient,
|
|
242
|
+
wrapWithPassphrase,
|
|
243
|
+
unwrapWithPassphrase,
|
|
244
|
+
} from "@muhkoo/connect";
|
|
245
|
+
|
|
246
|
+
const client = new PersonalSpaceClient({
|
|
247
|
+
baseUrl: "https://accelerator.example.dev",
|
|
248
|
+
commitment, secret, salt, ecdsaPub, ecdsaPubHash, // decimal BigInt strings
|
|
249
|
+
circuits: {
|
|
250
|
+
wasmUrl: "/circuits/build/preimagePoK_js/preimagePoK.wasm",
|
|
251
|
+
zkeyUrl: "/circuits/build/preimagePoK_0001.zkey",
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Each call: POST /challenge -> reduce nonce -> snarkjs.groth16.fullProve -> POST gated endpoint
|
|
256
|
+
const wrapped = await wrapWithPassphrase("hunter2", new TextEncoder().encode("secret"));
|
|
257
|
+
await client.put("notes", wrapped);
|
|
258
|
+
|
|
259
|
+
const got = await client.get<typeof wrapped>("notes");
|
|
260
|
+
const plaintext = await unwrapWithPassphrase("hunter2", got!);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Identity derivation (deriving `commitment / secret / salt / ecdsaPub / ecdsaPubHash`
|
|
264
|
+
from a username + password) lives on the consumer side. The accelerator's chat
|
|
265
|
+
app uses PBKDF2(password, "muhkoo-zk-v1:" + username) -> 32-byte seed ->
|
|
266
|
+
HKDF-Expand for each material -> P-256 via `@noble/curves` -> Poseidon
|
|
267
|
+
commitment.
|
|
268
|
+
|
|
269
|
+
### Universal Groth16 verification (Workers / Node / browser)
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import {
|
|
273
|
+
initBn128Wasm,
|
|
274
|
+
verifyGroth16,
|
|
275
|
+
PREIMAGE_POK_VERIFICATION_KEY,
|
|
276
|
+
} from "@muhkoo/connect";
|
|
277
|
+
|
|
278
|
+
const { instance, memory, initialPFree } = await initBn128Wasm();
|
|
279
|
+
const ok = await verifyGroth16(
|
|
280
|
+
instance, memory, initialPFree,
|
|
281
|
+
PREIMAGE_POK_VERIFICATION_KEY,
|
|
282
|
+
proof, publicSignals,
|
|
283
|
+
);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Initialize once at boot. For CF Workers, pass a pre-compiled
|
|
287
|
+
`WebAssembly.Module` to skip runtime compilation:
|
|
288
|
+
`await initBn128Wasm(myWasmModule)`.
|
|
289
|
+
|
|
290
|
+
## KeyStore
|
|
291
|
+
|
|
292
|
+
Singleton store for ECDH + ECDSA P-384 keypairs keyed by identity ID.
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { KeyStore } from "@muhkoo/connect";
|
|
296
|
+
|
|
297
|
+
const ks = KeyStore.getInstance();
|
|
298
|
+
await ks.generateOwnKeyPair("alice"); // ECDH + ECDSA pair
|
|
299
|
+
const dehydrated = await ks.dehydrateKeyPair("alice"); // JWK -> string fields
|
|
300
|
+
await ks.hydrateKeyPair("bob", dehydrated);
|
|
301
|
+
|
|
302
|
+
await ks.storeRemotePublicKeys("carol", carolEcdhPub, carolEcdsaPub);
|
|
303
|
+
const packed = await ks.packDehydratedKeys("alice"); // base64 blob
|
|
304
|
+
await ks.hydrateFromPacked("alice", packed);
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Dehydrated form is JWK-based; the personal-space wrap/unwrap helpers above are
|
|
308
|
+
how you'd persist the packed blob (passphrase-wrapped) into the accelerator's
|
|
309
|
+
ZK-gated KV layer.
|
|
310
|
+
|
|
311
|
+
## Repo layout
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
src/
|
|
315
|
+
browser/ rollup entrypoint for the browser build
|
|
316
|
+
server/ rollup entrypoint for the server / default build
|
|
317
|
+
workers/ rollup entrypoint for the workers build (+ groth16-verifier + bundled bn128.wasm)
|
|
318
|
+
crypto/ KeyStore, DoubleRatchet, DoubleRatchetManager, Authenticator, ZeroKnowledge
|
|
319
|
+
sessions/ EncryptedSession, BroadcastChannel
|
|
320
|
+
transport/ WSTransport
|
|
321
|
+
personal/ PersonalSpaceClient + wrap.ts (excluded from workers build)
|
|
322
|
+
events/ EventCore + EventCoreEvents
|
|
323
|
+
messaging/ Message, Packet, decorators
|
|
324
|
+
types/ shared type defs (incl. zk.ts with PREIMAGE_POK_VERIFICATION_KEY)
|
|
325
|
+
network/ legacy Network class (not exported from any build)
|
|
326
|
+
storage/ Reed-Solomon Storage (not exported from any build)
|
|
327
|
+
utilities/ Logger, base58, ID generation, decorators
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Scripts
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
yarn build # rm -rf dist && yarn rollup:browser && yarn rollup:server && yarn rollup:workers
|
|
334
|
+
yarn dev # all three targets in watch mode (concurrently)
|
|
335
|
+
yarn rollup:browser # one-off browser build
|
|
336
|
+
yarn rollup:server # one-off server build
|
|
337
|
+
yarn rollup:workers # one-off workers build
|
|
338
|
+
yarn build:dts # complete .d.ts bundle -> dist/connect.d.ts
|
|
339
|
+
yarn build:docs # typedoc -> docs/
|
|
340
|
+
|
|
341
|
+
yarn test # vitest
|
|
342
|
+
yarn test:unit # vitest --run (no integration tests)
|
|
343
|
+
yarn test:integration # TEST_TYPE=integration vitest --run tests/integration
|
|
344
|
+
yarn lint # eslint ./src
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Compatibility
|
|
348
|
+
|
|
349
|
+
- Node >= 20
|
|
350
|
+
- All three builds rely on globalThis-level WebCrypto (`crypto.subtle`,
|
|
351
|
+
`crypto.getRandomValues`), available natively in modern browsers, Node 16+,
|
|
352
|
+
Bun, Deno, and CF Workers.
|
|
353
|
+
- The bn128.wasm verifier needs runtime `WebAssembly.compile()` available
|
|
354
|
+
(true for all of the above; on CF Workers, pre-compile via wrangler's
|
|
355
|
+
`.wasm` import if you want to skip startup cost).
|
|
356
|
+
|
|
357
|
+
## Related
|
|
358
|
+
|
|
359
|
+
- [`muhkoo/accelerator`](https://github.com/muhkoo/accelerator) — the CF
|
|
360
|
+
Workers + DOs backend this SDK targets, including the personal-space DO,
|
|
361
|
+
message-bus DO, and the bn128.wasm-driven `verifyZkAuthProof`.
|
|
362
|
+
|
|
363
|
+
## License
|
|
364
|
+
|
|
365
|
+
GPL-3.0 — see `LICENSE`.
|