@muhkoo/connect 0.3.0-alpha.0 → 0.6.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/README.md +107 -10
- package/dist/browser/index.js +530 -8
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +587 -3
- package/dist/server/index.js +530 -8
- package/dist/server/index.js.map +1 -1
- package/dist/workers/index.js +20 -1
- package/dist/workers/index.js.map +1 -1
- package/package.json +2 -2
package/dist/server/index.js
CHANGED
|
@@ -2790,6 +2790,9 @@ class HttpClient {
|
|
|
2790
2790
|
post(path, body) {
|
|
2791
2791
|
return this.request("POST", path, body);
|
|
2792
2792
|
}
|
|
2793
|
+
patch(path, body) {
|
|
2794
|
+
return this.request("PATCH", path, body);
|
|
2795
|
+
}
|
|
2793
2796
|
del(path, body) {
|
|
2794
2797
|
return this.request("DELETE", path, body);
|
|
2795
2798
|
}
|
|
@@ -3272,6 +3275,7 @@ class WSTransport extends EventCore {
|
|
|
3272
3275
|
return `${this.id}:${event}`;
|
|
3273
3276
|
}
|
|
3274
3277
|
url;
|
|
3278
|
+
urlProvider;
|
|
3275
3279
|
socket = null;
|
|
3276
3280
|
_isConnected = false;
|
|
3277
3281
|
_isConnecting = false;
|
|
@@ -3297,6 +3301,7 @@ class WSTransport extends EventCore {
|
|
|
3297
3301
|
throw new Error("WSTransport: `url` is required");
|
|
3298
3302
|
}
|
|
3299
3303
|
this.url = opts.url;
|
|
3304
|
+
this.urlProvider = opts.urlProvider;
|
|
3300
3305
|
this.id = opts.id ?? `ws${++__wsInstanceSeq}`;
|
|
3301
3306
|
this.autoReconnect = opts.autoReconnect ?? true;
|
|
3302
3307
|
this.reconnectDelay = opts.reconnectDelay ?? 3000;
|
|
@@ -3313,6 +3318,18 @@ class WSTransport extends EventCore {
|
|
|
3313
3318
|
throw new Error("WSTransport: already connected or connecting");
|
|
3314
3319
|
}
|
|
3315
3320
|
this._isConnecting = true;
|
|
3321
|
+
// On a RECONNECT, refresh the URL (the baked-in single-use ticket is spent).
|
|
3322
|
+
// The first connect uses `url` as-is. If the provider throws (e.g. can't
|
|
3323
|
+
// mint a ticket), surface it and let scheduleReconnect retry.
|
|
3324
|
+
if (this.urlProvider && this.reconnectAttempts > 0) {
|
|
3325
|
+
try {
|
|
3326
|
+
this.url = await this.urlProvider();
|
|
3327
|
+
}
|
|
3328
|
+
catch (err) {
|
|
3329
|
+
this._isConnecting = false;
|
|
3330
|
+
throw err;
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3316
3333
|
return new Promise((resolve, reject) => {
|
|
3317
3334
|
try {
|
|
3318
3335
|
const socket = new WebSocket(this.url);
|
|
@@ -3485,7 +3502,12 @@ class WSTransport extends EventCore {
|
|
|
3485
3502
|
await this.connect();
|
|
3486
3503
|
}
|
|
3487
3504
|
catch {
|
|
3488
|
-
//
|
|
3505
|
+
// A failed reconnect never opened the socket, so its `onclose` won't
|
|
3506
|
+
// re-schedule (that path is guarded by `wasConnected`). Re-schedule here
|
|
3507
|
+
// so we keep retrying (with a fresh ticket each time) until we succeed
|
|
3508
|
+
// or hit the attempt cap.
|
|
3509
|
+
if (this.autoReconnect)
|
|
3510
|
+
this.scheduleReconnect();
|
|
3489
3511
|
}
|
|
3490
3512
|
}, this.reconnectDelay);
|
|
3491
3513
|
}
|
|
@@ -3652,6 +3674,92 @@ class KvNamespace {
|
|
|
3652
3674
|
}
|
|
3653
3675
|
}
|
|
3654
3676
|
|
|
3677
|
+
/**
|
|
3678
|
+
* `client.db` — the app's scalable database. A developer defines tables in the
|
|
3679
|
+
* Muhkoo portal (columns + indexes); each table is backed by its own Durable
|
|
3680
|
+
* Object SQLite instance and reachable through a sanitized REST gateway. This
|
|
3681
|
+
* namespace wraps that gateway:
|
|
3682
|
+
*
|
|
3683
|
+
* const todos = client.db.table('todos');
|
|
3684
|
+
* const { id } = await todos.insert({ title: 'Buy milk', done: false });
|
|
3685
|
+
* const one = await todos.get(id);
|
|
3686
|
+
* const { rows, nextCursor } = await todos.query({
|
|
3687
|
+
* where: [{ column: 'done', op: 'eq', value: false }],
|
|
3688
|
+
* orderBy: { column: 'rank', dir: 'asc' },
|
|
3689
|
+
* limit: 50,
|
|
3690
|
+
* });
|
|
3691
|
+
* await todos.update(id, { done: true });
|
|
3692
|
+
* await todos.delete(id);
|
|
3693
|
+
*
|
|
3694
|
+
* Authorization is the **app key** ({@link HttpClient} stamps it on every
|
|
3695
|
+
* request); the appId + environment are resolved server-side from the key, so a
|
|
3696
|
+
* key can only ever reach its own app's tables. The front end never touches the
|
|
3697
|
+
* database directly — this REST surface is the only gateway, and all input is
|
|
3698
|
+
* validated against the table's schema (parameterized statements, column +
|
|
3699
|
+
* operator allowlists). There is no raw-SQL passthrough.
|
|
3700
|
+
*
|
|
3701
|
+
* Schema is authored in the portal, not here (the SDK reads + writes rows, it
|
|
3702
|
+
* doesn't create tables). Pagination is keyset-based: pass the `nextCursor` from
|
|
3703
|
+
* a previous `query()` back as `cursor` to fetch the next page.
|
|
3704
|
+
*/
|
|
3705
|
+
/** A handle to one table — the ergonomic surface for row operations. */
|
|
3706
|
+
class DbTable {
|
|
3707
|
+
http;
|
|
3708
|
+
name;
|
|
3709
|
+
constructor(http, name) {
|
|
3710
|
+
this.http = http;
|
|
3711
|
+
this.name = name;
|
|
3712
|
+
}
|
|
3713
|
+
base() {
|
|
3714
|
+
return `/api/db/${encodeURIComponent(this.name)}`;
|
|
3715
|
+
}
|
|
3716
|
+
/** Insert a row. Returns the created row and its primary-key value. */
|
|
3717
|
+
async insert(values) {
|
|
3718
|
+
return this.http.post(this.base(), { values });
|
|
3719
|
+
}
|
|
3720
|
+
/** Fetch a row by primary key, or `null` if it doesn't exist. */
|
|
3721
|
+
async get(id) {
|
|
3722
|
+
try {
|
|
3723
|
+
const res = await this.http.get(`${this.base()}/${encodeURIComponent(String(id))}`);
|
|
3724
|
+
return res.row;
|
|
3725
|
+
}
|
|
3726
|
+
catch (e) {
|
|
3727
|
+
if (e?.status === 404)
|
|
3728
|
+
return null;
|
|
3729
|
+
throw e;
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
/** Query rows with filters, ordering, and keyset pagination. */
|
|
3733
|
+
async query(query = {}) {
|
|
3734
|
+
return this.http.post(`${this.base()}/query`, query);
|
|
3735
|
+
}
|
|
3736
|
+
/** Update a row by primary key. Returns the updated row. */
|
|
3737
|
+
async update(id, values) {
|
|
3738
|
+
return this.http.patch(`${this.base()}/${encodeURIComponent(String(id))}`, { values });
|
|
3739
|
+
}
|
|
3740
|
+
/** Delete a row by primary key. Returns the number of rows removed (0 or 1). */
|
|
3741
|
+
async delete(id) {
|
|
3742
|
+
const res = await this.http.del(`${this.base()}/${encodeURIComponent(String(id))}`);
|
|
3743
|
+
return res.deleted ?? 0;
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
class DbNamespace {
|
|
3747
|
+
deps;
|
|
3748
|
+
constructor(deps) {
|
|
3749
|
+
this.deps = deps;
|
|
3750
|
+
}
|
|
3751
|
+
/**
|
|
3752
|
+
* A handle to a table defined in the portal. The optional type parameter
|
|
3753
|
+
* gives row operations a typed shape:
|
|
3754
|
+
*
|
|
3755
|
+
* interface Todo { _id: number; title: string; done: boolean }
|
|
3756
|
+
* const todos = client.db.table<Todo>('todos');
|
|
3757
|
+
*/
|
|
3758
|
+
table(name) {
|
|
3759
|
+
return new DbTable(this.deps.http, name);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3655
3763
|
/**
|
|
3656
3764
|
* Wire types for the storage layer.
|
|
3657
3765
|
*
|
|
@@ -4266,6 +4374,8 @@ class FileStorage {
|
|
|
4266
4374
|
const fileId = input.fileId ?? generateId();
|
|
4267
4375
|
const createdAt = Date.now();
|
|
4268
4376
|
const chunks = [];
|
|
4377
|
+
const totalChunks = Math.max(1, Math.ceil(data.length / this.chunkSize));
|
|
4378
|
+
input.onProgress?.(0, totalChunks);
|
|
4269
4379
|
// Slicing + encrypting + encoding + uploading is done per-chunk so
|
|
4270
4380
|
// the peak memory footprint stays at ~chunkSize even for huge files.
|
|
4271
4381
|
// Within a chunk, the shard uploads are parallelized up to
|
|
@@ -4275,6 +4385,7 @@ class FileStorage {
|
|
|
4275
4385
|
const end = Math.min(start + this.chunkSize, data.length);
|
|
4276
4386
|
const plaintext = data.subarray(start, end);
|
|
4277
4387
|
chunks.push(await this.writeChunk(plaintext, chunkIndex));
|
|
4388
|
+
input.onProgress?.(chunks.length, totalChunks);
|
|
4278
4389
|
// Stop after one iteration if the file is empty — we still emit a
|
|
4279
4390
|
// single zero-length chunk so the manifest has a stable shape.
|
|
4280
4391
|
if (data.length === 0)
|
|
@@ -5390,12 +5501,27 @@ class Space {
|
|
|
5390
5501
|
/** Open the space websocket (resolves the ticket + identity lazily). */
|
|
5391
5502
|
async connect() {
|
|
5392
5503
|
if (!this.channel) {
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5504
|
+
// The WS upgrade ticket is single-use + short-TTL, so a reconnect
|
|
5505
|
+
// must mint a FRESH one — otherwise the socket drops (idle timeout,
|
|
5506
|
+
// network blip) and never comes back. `buildUrl` is handed to the
|
|
5507
|
+
// transport as a `urlProvider` it calls before each reconnect.
|
|
5508
|
+
const buildUrl = async () => {
|
|
5509
|
+
const ticket = await this.deps.fetchTicket();
|
|
5510
|
+
return (`${this.deps.wsBaseUrl}/api/spaces/${encodeURIComponent(this.name)}/websocket` +
|
|
5511
|
+
(ticket ? `?ticket=${encodeURIComponent(ticket)}` : ""));
|
|
5512
|
+
};
|
|
5513
|
+
const url = await buildUrl();
|
|
5396
5514
|
this.channel = this.deps.createChannel
|
|
5397
5515
|
? this.deps.createChannel(url, this.deps.myId())
|
|
5398
|
-
: new BroadcastChannel({
|
|
5516
|
+
: new BroadcastChannel({
|
|
5517
|
+
url,
|
|
5518
|
+
myId: this.deps.myId(),
|
|
5519
|
+
autoAnnounce: false,
|
|
5520
|
+
urlProvider: buildUrl,
|
|
5521
|
+
// Keep recovering across network flaps (each attempt mints a
|
|
5522
|
+
// fresh ticket); teardown calls disconnect() which stops it.
|
|
5523
|
+
maxReconnectAttempts: 0,
|
|
5524
|
+
});
|
|
5399
5525
|
for (const [event, handler] of this.pending)
|
|
5400
5526
|
this.channel.on(event, handler);
|
|
5401
5527
|
this.pending.length = 0;
|
|
@@ -5599,8 +5725,8 @@ class Space {
|
|
|
5599
5725
|
return this.requireKeyring().rotate(roster);
|
|
5600
5726
|
}
|
|
5601
5727
|
// -- room-scoped files (no websocket needed) -------------------------------
|
|
5602
|
-
async putFile(file, metadata) {
|
|
5603
|
-
return this.fileStorage().writeFileToShards({ data: file, metadata });
|
|
5728
|
+
async putFile(file, metadata, opts = {}) {
|
|
5729
|
+
return this.fileStorage().writeFileToShards({ data: file, metadata, onProgress: opts.onProgress });
|
|
5604
5730
|
}
|
|
5605
5731
|
async getFile(manifest) {
|
|
5606
5732
|
return this.fileStorage().readFileFromShards(manifest);
|
|
@@ -5757,6 +5883,12 @@ class Space {
|
|
|
5757
5883
|
* nothing to verify against → reject.
|
|
5758
5884
|
*/
|
|
5759
5885
|
async verifySender(packet) {
|
|
5886
|
+
// Trust our OWN messages — we sent them, so there's nothing to prove
|
|
5887
|
+
// against the roster. This also keeps a returning member (who loaded a
|
|
5888
|
+
// cached key and never re-published a join-request) from dropping the
|
|
5889
|
+
// echo of their own messages when their `ecdsaPub` isn't in the roster.
|
|
5890
|
+
if (packet.source === this.deps.myId())
|
|
5891
|
+
return true;
|
|
5760
5892
|
const keyring = this.deps.keyring;
|
|
5761
5893
|
const sig = packet.headers?.sig;
|
|
5762
5894
|
if (!keyring || typeof sig !== "string")
|
|
@@ -6253,6 +6385,34 @@ class KeyringClient {
|
|
|
6253
6385
|
async invite(username) {
|
|
6254
6386
|
await this.post("/keyring/invite", { username });
|
|
6255
6387
|
}
|
|
6388
|
+
// -- Shareable invite links ----------------------------------------------
|
|
6389
|
+
// A capability token tied to this space. Redeeming it allowlists the holder
|
|
6390
|
+
// so the keeper admits them — the link IS the invitation. Mint/list/revoke
|
|
6391
|
+
// require the caller to be the creator or an existing member.
|
|
6392
|
+
async createInviteLink(opts = {}) {
|
|
6393
|
+
return this.post("/keyring/link", opts);
|
|
6394
|
+
}
|
|
6395
|
+
async listInviteLinks() {
|
|
6396
|
+
const body = await this.get("/keyring/links");
|
|
6397
|
+
return body.links ?? [];
|
|
6398
|
+
}
|
|
6399
|
+
/** Set a member's role ("viewer" | "editor"). Owner-only on the server. */
|
|
6400
|
+
async setMemberRole(username, role) {
|
|
6401
|
+
await this.post("/keyring/role", { username, role });
|
|
6402
|
+
}
|
|
6403
|
+
/** Roster with roles (owner/members only). */
|
|
6404
|
+
async members() {
|
|
6405
|
+
const body = await this.get("/keyring/members");
|
|
6406
|
+
return body.members ?? [];
|
|
6407
|
+
}
|
|
6408
|
+
async revokeInviteLink(token) {
|
|
6409
|
+
await this.post("/keyring/link-revoke", { token });
|
|
6410
|
+
}
|
|
6411
|
+
/** Redeem a link: the server allowlists this member and asks the keeper to
|
|
6412
|
+
* wrap the group key for their identity. Caller must be authenticated. */
|
|
6413
|
+
async redeemInvite(req) {
|
|
6414
|
+
await this.post("/keyring/redeem", req);
|
|
6415
|
+
}
|
|
6256
6416
|
async fetchMetadata() {
|
|
6257
6417
|
try {
|
|
6258
6418
|
return await this.get("/metadata");
|
|
@@ -6390,6 +6550,56 @@ class SpaceNamespace {
|
|
|
6390
6550
|
return this.joinSpace(spaceId, opts);
|
|
6391
6551
|
}
|
|
6392
6552
|
// -------------------------------------------------------------------------
|
|
6553
|
+
// Invite links — shareable, keeper-gated invitations to a space. The token
|
|
6554
|
+
// is a capability: anyone signed in who redeems it is admitted by the
|
|
6555
|
+
// keeper. Mint/list/revoke require the caller to be the space's creator or
|
|
6556
|
+
// an existing member.
|
|
6557
|
+
// -------------------------------------------------------------------------
|
|
6558
|
+
/** Mint a shareable invite link for a space. `opts.expiresInSec` / `maxUses`
|
|
6559
|
+
* bound it (0/undefined = unlimited); `opts.role` ("viewer"|"editor") is the
|
|
6560
|
+
* access granted to redeemers (default viewer). Returns the link. */
|
|
6561
|
+
async createInviteLink(spaceId, opts = {}) {
|
|
6562
|
+
return this.keyringFor(spaceId).createInviteLink(opts);
|
|
6563
|
+
}
|
|
6564
|
+
/** Set a member's role on a space ("viewer" | "editor"). Owner-only. */
|
|
6565
|
+
async setMemberRole(spaceId, username, role) {
|
|
6566
|
+
await this.keyringFor(spaceId).setMemberRole(username, role);
|
|
6567
|
+
}
|
|
6568
|
+
/** Roster with roles (owner/members only). */
|
|
6569
|
+
async members(spaceId) {
|
|
6570
|
+
return this.keyringFor(spaceId).members();
|
|
6571
|
+
}
|
|
6572
|
+
/** List a space's active invite links (creator/members only). */
|
|
6573
|
+
async listInviteLinks(spaceId) {
|
|
6574
|
+
return this.keyringFor(spaceId).listInviteLinks();
|
|
6575
|
+
}
|
|
6576
|
+
/** Revoke an invite link by token. */
|
|
6577
|
+
async revokeInviteLink(spaceId, token) {
|
|
6578
|
+
await this.keyringFor(spaceId).revokeInviteLink(token);
|
|
6579
|
+
}
|
|
6580
|
+
/**
|
|
6581
|
+
* Join a space using an invite link: redeem the token (the keeper admits
|
|
6582
|
+
* this member), then connect and resolve once the group key arrives.
|
|
6583
|
+
* Returns the open {@link Space}.
|
|
6584
|
+
*/
|
|
6585
|
+
async joinByInvite(spaceId, token, opts = {}) {
|
|
6586
|
+
const memberId = this.myId();
|
|
6587
|
+
const { ecdhPub, ecdsaPub } = await this.ensureIdentity(memberId);
|
|
6588
|
+
await this.keyringFor(spaceId).redeemInvite({ token, identityEcdhPub: ecdhPub, identityEcdsaPub: ecdsaPub });
|
|
6589
|
+
return this.joinSpace(spaceId, opts);
|
|
6590
|
+
}
|
|
6591
|
+
/** The current member roster of a space (member id → identity public keys). */
|
|
6592
|
+
async roster(spaceId) {
|
|
6593
|
+
return this.keyringFor(spaceId).fetchRoster();
|
|
6594
|
+
}
|
|
6595
|
+
keyringFor(spaceId) {
|
|
6596
|
+
return new KeyringClient({
|
|
6597
|
+
spaceId,
|
|
6598
|
+
httpBaseUrl: this.deps.http.baseUrl,
|
|
6599
|
+
fetch: this.deps.http.fetch,
|
|
6600
|
+
});
|
|
6601
|
+
}
|
|
6602
|
+
// -------------------------------------------------------------------------
|
|
6393
6603
|
// Internals
|
|
6394
6604
|
// -------------------------------------------------------------------------
|
|
6395
6605
|
async build(spaceId, historyPolicy) {
|
|
@@ -6456,6 +6666,138 @@ class SpaceNamespace {
|
|
|
6456
6666
|
}
|
|
6457
6667
|
}
|
|
6458
6668
|
|
|
6669
|
+
/**
|
|
6670
|
+
* `client.agents` — manage an app's **Programmable Agents** (server-side
|
|
6671
|
+
* "virtual users" backed by Workers AI).
|
|
6672
|
+
*
|
|
6673
|
+
* const { config } = await client.agents.create(appId, {
|
|
6674
|
+
* handle: '@assistant', displayName: 'Assistant',
|
|
6675
|
+
* systemPrompt: 'You are a helpful teammate in this Space.',
|
|
6676
|
+
* triggers: [{ type: 'mention' }],
|
|
6677
|
+
* });
|
|
6678
|
+
* await client.agents.enable(appId, config.agentId, spaceId); // per-Space opt-in
|
|
6679
|
+
*
|
|
6680
|
+
* These are MANAGEMENT calls — the agent itself runs on the accelerator. Only an
|
|
6681
|
+
* app's owner or an editor of its shared Space may create/update/enable an agent
|
|
6682
|
+
* (viewers can read). Authorization rides the user session token; non-owner
|
|
6683
|
+
* editors pass their management Space via `opts.space`.
|
|
6684
|
+
*
|
|
6685
|
+
* An agent is "prompts + persona": a system prompt, a model, named prompt
|
|
6686
|
+
* `skills`, and `triggers` that decide when it speaks — plus optional `tools`
|
|
6687
|
+
* that let it act on the app (query/write its database, call its functions,
|
|
6688
|
+
* resolve its channels) via a server-side function-calling loop. See
|
|
6689
|
+
* {@link AgentToolsConfig}. Pair with the `@MuhkooAgent`/`@MuhkooSpace`/
|
|
6690
|
+
* `@MuhkooDB`/`@MuhkooFunction` decorators + `ejectAgentPrompt`/`ejectAgentTools`
|
|
6691
|
+
* to generate `systemPrompt` and `tools` straight from your app's surface.
|
|
6692
|
+
*/
|
|
6693
|
+
class AgentsNamespace {
|
|
6694
|
+
deps;
|
|
6695
|
+
constructor(deps) {
|
|
6696
|
+
this.deps = deps;
|
|
6697
|
+
}
|
|
6698
|
+
/** List the app's agents. */
|
|
6699
|
+
async list(appId, opts = {}) {
|
|
6700
|
+
const res = await this.deps.http.get(this.path(appId, "", opts));
|
|
6701
|
+
return res.agents ?? [];
|
|
6702
|
+
}
|
|
6703
|
+
/** Read one agent (config + identity keys). */
|
|
6704
|
+
async get(appId, agentId, opts = {}) {
|
|
6705
|
+
return this.deps.http.get(this.path(appId, `/${encodeURIComponent(agentId)}`, opts));
|
|
6706
|
+
}
|
|
6707
|
+
/** Create an agent (owner/editor only). */
|
|
6708
|
+
async create(appId, input, opts = {}) {
|
|
6709
|
+
return this.deps.http.post(this.path(appId, "", {}), { ...input, space: opts.space });
|
|
6710
|
+
}
|
|
6711
|
+
/** Update an agent's editor-settable fields (owner/editor only). */
|
|
6712
|
+
async update(appId, agentId, patch, opts = {}) {
|
|
6713
|
+
return this.deps.http.patch(this.path(appId, `/${encodeURIComponent(agentId)}`, {}), { ...patch, space: opts.space });
|
|
6714
|
+
}
|
|
6715
|
+
/** Delete an agent (owner/editor only). */
|
|
6716
|
+
async delete(appId, agentId, opts = {}) {
|
|
6717
|
+
return this.deps.http.del(this.path(appId, `/${encodeURIComponent(agentId)}`, {}), { space: opts.space });
|
|
6718
|
+
}
|
|
6719
|
+
/** Enable the agent on a Space (per-Space opt-in). */
|
|
6720
|
+
async enable(appId, agentId, spaceId, opts = {}) {
|
|
6721
|
+
return this.deps.http.post(this.path(appId, `/${encodeURIComponent(agentId)}/enable`, {}), { targetSpaceId: spaceId, space: opts.space });
|
|
6722
|
+
}
|
|
6723
|
+
/** Disable the agent on a Space. */
|
|
6724
|
+
async disable(appId, agentId, spaceId, opts = {}) {
|
|
6725
|
+
return this.deps.http.post(this.path(appId, `/${encodeURIComponent(agentId)}/disable`, {}), { targetSpaceId: spaceId, space: opts.space });
|
|
6726
|
+
}
|
|
6727
|
+
path(appId, suffix, opts) {
|
|
6728
|
+
const q = opts.space ? `?space=${encodeURIComponent(opts.space)}` : "";
|
|
6729
|
+
return `/api/apps/${encodeURIComponent(appId)}/agents${suffix}${q}`;
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
|
|
6733
|
+
/**
|
|
6734
|
+
* `client.functions` — manage an app's **serverless functions** (developer-
|
|
6735
|
+
* authored code that runs on the accelerator).
|
|
6736
|
+
*
|
|
6737
|
+
* const { config } = await client.functions.deploy(appId, {
|
|
6738
|
+
* name: 'hello', displayName: 'Hello',
|
|
6739
|
+
* code: `export default { fetch: () => new Response('hi') }`,
|
|
6740
|
+
* triggers: { http: { enabled: true } },
|
|
6741
|
+
* });
|
|
6742
|
+
* // HTTP-reachable at hello--<slug>.fns.muhkoo.dev
|
|
6743
|
+
* await client.functions.enable(appId, config.functionId, spaceId); // Space-bound
|
|
6744
|
+
*
|
|
6745
|
+
* These are MANAGEMENT calls — the function itself runs on the accelerator
|
|
6746
|
+
* (uploaded just-in-time, decrypted only at invocation). Only an app's owner or
|
|
6747
|
+
* an editor of its shared Space may deploy/update/enable (viewers read).
|
|
6748
|
+
* Authorization rides the user session token; non-owner editors pass their
|
|
6749
|
+
* management Space via `opts.space`.
|
|
6750
|
+
*
|
|
6751
|
+
* v1 is "compute-only": a function is an untrusted single-module ES worker
|
|
6752
|
+
* (`export default { fetch }`) with NO platform bindings — it reaches the
|
|
6753
|
+
* platform as an external client (the end-user session is passed through). Two
|
|
6754
|
+
* triggers: `http` (its own subdomain) and `space` (invoked on Space messages,
|
|
6755
|
+
* like a Programmable Agent).
|
|
6756
|
+
*/
|
|
6757
|
+
class FunctionsNamespace {
|
|
6758
|
+
deps;
|
|
6759
|
+
constructor(deps) {
|
|
6760
|
+
this.deps = deps;
|
|
6761
|
+
}
|
|
6762
|
+
/** List the app's functions. */
|
|
6763
|
+
async list(appId, opts = {}) {
|
|
6764
|
+
const res = await this.deps.http.get(this.path(appId, "", opts));
|
|
6765
|
+
return res.functions ?? [];
|
|
6766
|
+
}
|
|
6767
|
+
/** Read one function's config. */
|
|
6768
|
+
async get(appId, functionId, opts = {}) {
|
|
6769
|
+
return this.deps.http.get(this.path(appId, `/${encodeURIComponent(functionId)}`, opts));
|
|
6770
|
+
}
|
|
6771
|
+
/** Read a function's decrypted source (owner/editor; for the editor UI). */
|
|
6772
|
+
async code(appId, functionId, opts = {}) {
|
|
6773
|
+
return this.deps.http.get(this.path(appId, `/${encodeURIComponent(functionId)}/code`, opts));
|
|
6774
|
+
}
|
|
6775
|
+
/** Deploy (create) a function (owner/editor only). */
|
|
6776
|
+
async deploy(appId, input, opts = {}) {
|
|
6777
|
+
return this.deps.http.post(this.path(appId, "", {}), { ...input, space: opts.space });
|
|
6778
|
+
}
|
|
6779
|
+
/** Update a function's editor-settable fields and/or redeploy its `code`. */
|
|
6780
|
+
async update(appId, functionId, patch, opts = {}) {
|
|
6781
|
+
return this.deps.http.patch(this.path(appId, `/${encodeURIComponent(functionId)}`, {}), { ...patch, space: opts.space });
|
|
6782
|
+
}
|
|
6783
|
+
/** Delete a function (owner/editor only). */
|
|
6784
|
+
async delete(appId, functionId, opts = {}) {
|
|
6785
|
+
return this.deps.http.del(this.path(appId, `/${encodeURIComponent(functionId)}`, {}), { space: opts.space });
|
|
6786
|
+
}
|
|
6787
|
+
/** Enable the function on a Space (per-Space opt-in for the `space` trigger). */
|
|
6788
|
+
async enable(appId, functionId, spaceId, opts = {}) {
|
|
6789
|
+
return this.deps.http.post(this.path(appId, `/${encodeURIComponent(functionId)}/enable`, {}), { targetSpaceId: spaceId, space: opts.space });
|
|
6790
|
+
}
|
|
6791
|
+
/** Disable the function on a Space. */
|
|
6792
|
+
async disable(appId, functionId, spaceId, opts = {}) {
|
|
6793
|
+
return this.deps.http.post(this.path(appId, `/${encodeURIComponent(functionId)}/disable`, {}), { targetSpaceId: spaceId, space: opts.space });
|
|
6794
|
+
}
|
|
6795
|
+
path(appId, suffix, opts) {
|
|
6796
|
+
const q = opts.space ? `?space=${encodeURIComponent(opts.space)}` : "";
|
|
6797
|
+
return `/api/apps/${encodeURIComponent(appId)}/functions${suffix}${q}`;
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6800
|
+
|
|
6459
6801
|
/**
|
|
6460
6802
|
* `Client` — the single entry point to the Muhkoo SDK.
|
|
6461
6803
|
*
|
|
@@ -6494,12 +6836,18 @@ class Client {
|
|
|
6494
6836
|
auth;
|
|
6495
6837
|
/** Per-user key/value storage — `client.kv.set(...)`, etc. */
|
|
6496
6838
|
kv;
|
|
6839
|
+
/** App scalable database — `client.db.table('todos').query(...)`, etc. */
|
|
6840
|
+
db;
|
|
6497
6841
|
/** File storage — `client.storage.writeFile(...)`, etc. */
|
|
6498
6842
|
storage;
|
|
6499
6843
|
/** Realtime messaging — `client.message.subscribe(...)`, etc. */
|
|
6500
6844
|
message;
|
|
6501
6845
|
/** Fan-out group spaces — `client.space.createSpace(...)`, etc. */
|
|
6502
6846
|
space;
|
|
6847
|
+
/** Programmable Agents — `client.agents.create(appId, …)`, etc. */
|
|
6848
|
+
agents;
|
|
6849
|
+
/** Serverless functions — `client.functions.deploy(appId, …)`, etc. */
|
|
6850
|
+
functions;
|
|
6503
6851
|
session;
|
|
6504
6852
|
http;
|
|
6505
6853
|
/** Subscribers notified when a session expires and can't be recovered. */
|
|
@@ -6527,6 +6875,7 @@ class Client {
|
|
|
6527
6875
|
const wsBaseUrl = toWsBase(this.baseUrl);
|
|
6528
6876
|
this.auth = new AuthNamespace({ auth: authClient, circuits, session: this.session });
|
|
6529
6877
|
this.kv = new KvNamespace({ http: this.http, session: this.session, wsBaseUrl });
|
|
6878
|
+
this.db = new DbNamespace({ http: this.http });
|
|
6530
6879
|
this.storage = new StorageNamespace({ http: this.http, baseUrl: this.baseUrl, kv: this.kv });
|
|
6531
6880
|
this.message = new MessageNamespace({ http: this.http, session: this.session, wsBaseUrl });
|
|
6532
6881
|
// Group keys are cached in the user's PersonalSpace (encrypted at rest
|
|
@@ -6542,6 +6891,8 @@ class Client {
|
|
|
6542
6891
|
wsBaseUrl,
|
|
6543
6892
|
cache: spaceKeyCache,
|
|
6544
6893
|
});
|
|
6894
|
+
this.agents = new AgentsNamespace({ http: this.http });
|
|
6895
|
+
this.functions = new FunctionsNamespace({ http: this.http });
|
|
6545
6896
|
}
|
|
6546
6897
|
/** The currently signed-in user, or `null`. */
|
|
6547
6898
|
get user() {
|
|
@@ -6595,6 +6946,177 @@ class Client {
|
|
|
6595
6946
|
}
|
|
6596
6947
|
}
|
|
6597
6948
|
|
|
6949
|
+
/**
|
|
6950
|
+
* Muhkoo app decorators — declare your app's agent-facing surface in code, then
|
|
6951
|
+
* "eject" a system prompt you hand to a Programmable Agent.
|
|
6952
|
+
*
|
|
6953
|
+
* You annotate a plain class with `@MuhkooAgent` (the app's identity + how the
|
|
6954
|
+
* agent should behave) plus per-surface decorators — `@MuhkooSpace`,
|
|
6955
|
+
* `@MuhkooDB`, `@MuhkooFunction` — that describe what each channel, table, and
|
|
6956
|
+
* function is *for*. {@link ejectAgentPrompt} reads those annotations and
|
|
6957
|
+
* produces a `systemPrompt` string:
|
|
6958
|
+
*
|
|
6959
|
+
* ```ts
|
|
6960
|
+
* @MuhkooAgent({
|
|
6961
|
+
* name: "Chat Assistant",
|
|
6962
|
+
* purpose: "A helpful assistant inside a real-time team chat.",
|
|
6963
|
+
* guidance: ["Keep replies short.", "Only chime in when relevant."],
|
|
6964
|
+
* })
|
|
6965
|
+
* class ChatAssistant {
|
|
6966
|
+
* @MuhkooSpace({ description: "Main team discussion." }) general!: string;
|
|
6967
|
+
* @MuhkooDB({ access: "read", description: "Chat message history." }) messages!: unknown;
|
|
6968
|
+
* @MuhkooFunction({ description: "Open a support ticket." }) openTicket!: () => void;
|
|
6969
|
+
* }
|
|
6970
|
+
*
|
|
6971
|
+
* const systemPrompt = ejectAgentPrompt(ChatAssistant);
|
|
6972
|
+
* await client.agents.create({ handle: "assistant", displayName: "Assistant", systemPrompt });
|
|
6973
|
+
* ```
|
|
6974
|
+
*
|
|
6975
|
+
* The ejected prompt owns the **semantic** layer — what the app is, how to act,
|
|
6976
|
+
* and what each surface means. The Muhkoo runtime separately appends the
|
|
6977
|
+
* **authoritative** roster (exact columns, function parameters, and the closed
|
|
6978
|
+
* list of callable tools), so the prompt here never needs to restate schema and
|
|
6979
|
+
* can't drift from it. Decorators only describe; they never change runtime
|
|
6980
|
+
* behavior, so they're safe to apply to a throwaway descriptor class.
|
|
6981
|
+
*
|
|
6982
|
+
* Requires `experimentalDecorators` (already enabled in this package). Metadata
|
|
6983
|
+
* is captured in a per-class registry — no `reflect-metadata` dependency.
|
|
6984
|
+
*/
|
|
6985
|
+
// Per-class metadata store, keyed by the class constructor. Member decorators
|
|
6986
|
+
// run during class-body evaluation (before the class decorator), so each
|
|
6987
|
+
// decorator get-or-creates the descriptor and they all converge on one entry.
|
|
6988
|
+
const REGISTRY = new WeakMap();
|
|
6989
|
+
function descriptorFor(ctor) {
|
|
6990
|
+
let d = REGISTRY.get(ctor);
|
|
6991
|
+
if (!d) {
|
|
6992
|
+
d = { spaces: [], tables: [], functions: [] };
|
|
6993
|
+
REGISTRY.set(ctor, d);
|
|
6994
|
+
}
|
|
6995
|
+
return d;
|
|
6996
|
+
}
|
|
6997
|
+
/** Resolve the owning class constructor from a decorator `target` — the
|
|
6998
|
+
* prototype for instance members, the constructor itself for static ones. */
|
|
6999
|
+
function ctorOf(target) {
|
|
7000
|
+
return typeof target === "function" ? target : target.constructor;
|
|
7001
|
+
}
|
|
7002
|
+
/**
|
|
7003
|
+
* Class decorator. Declares the app's agent identity, purpose, and behavioral
|
|
7004
|
+
* guidance. Apply it to the class whose members carry the surface decorators.
|
|
7005
|
+
*/
|
|
7006
|
+
function MuhkooAgent(meta) {
|
|
7007
|
+
return (target) => {
|
|
7008
|
+
descriptorFor(target).agent = meta;
|
|
7009
|
+
};
|
|
7010
|
+
}
|
|
7011
|
+
/** Member decorator. Marks a channel/Space the agent can resolve and post to. */
|
|
7012
|
+
function MuhkooSpace(meta) {
|
|
7013
|
+
return ((target, propertyKey) => {
|
|
7014
|
+
descriptorFor(ctorOf(target)).spaces.push({
|
|
7015
|
+
name: meta.name ?? String(propertyKey),
|
|
7016
|
+
description: meta.description,
|
|
7017
|
+
});
|
|
7018
|
+
});
|
|
7019
|
+
}
|
|
7020
|
+
/** Member decorator. Marks an app database table the agent can query/mutate. */
|
|
7021
|
+
function MuhkooDB(meta) {
|
|
7022
|
+
return ((target, propertyKey) => {
|
|
7023
|
+
descriptorFor(ctorOf(target)).tables.push({
|
|
7024
|
+
table: meta.table ?? String(propertyKey),
|
|
7025
|
+
access: meta.access ?? "read",
|
|
7026
|
+
description: meta.description,
|
|
7027
|
+
});
|
|
7028
|
+
});
|
|
7029
|
+
}
|
|
7030
|
+
/** Member decorator. Marks a serverless function the agent can call. */
|
|
7031
|
+
function MuhkooFunction(meta) {
|
|
7032
|
+
return ((target, propertyKey) => {
|
|
7033
|
+
descriptorFor(ctorOf(target)).functions.push({
|
|
7034
|
+
name: meta.name ?? String(propertyKey),
|
|
7035
|
+
description: meta.description,
|
|
7036
|
+
});
|
|
7037
|
+
});
|
|
7038
|
+
}
|
|
7039
|
+
/** Read back the raw descriptor a class accumulated (for tooling/tests). */
|
|
7040
|
+
function getMuhkooAppDescriptor(appClass) {
|
|
7041
|
+
return REGISTRY.get(appClass);
|
|
7042
|
+
}
|
|
7043
|
+
/**
|
|
7044
|
+
* Compose the agent system prompt from a `@MuhkooAgent`-decorated class. Throws
|
|
7045
|
+
* if the class isn't decorated. The result is the semantic layer only — the
|
|
7046
|
+
* runtime appends exact schema + the closed tool list at invocation time.
|
|
7047
|
+
*/
|
|
7048
|
+
function ejectAgentPrompt(appClass) {
|
|
7049
|
+
const d = REGISTRY.get(appClass);
|
|
7050
|
+
if (!d || !d.agent) {
|
|
7051
|
+
throw new Error("ejectAgentPrompt: the class must be decorated with @MuhkooAgent");
|
|
7052
|
+
}
|
|
7053
|
+
const { agent } = d;
|
|
7054
|
+
const lines = [];
|
|
7055
|
+
lines.push(`You are ${agent.name}. ${agent.purpose}`.trim());
|
|
7056
|
+
if (agent.guidance?.length) {
|
|
7057
|
+
lines.push("", "Guidance:");
|
|
7058
|
+
for (const g of agent.guidance)
|
|
7059
|
+
lines.push(`- ${g}`);
|
|
7060
|
+
}
|
|
7061
|
+
if (d.spaces.length) {
|
|
7062
|
+
lines.push("", "Channels (Spaces) you can resolve with resolve_channel and post messages into:");
|
|
7063
|
+
for (const s of d.spaces)
|
|
7064
|
+
lines.push(`- ${s.name}: ${s.description}`);
|
|
7065
|
+
}
|
|
7066
|
+
if (d.tables.length) {
|
|
7067
|
+
lines.push("", "App database tables:");
|
|
7068
|
+
for (const t of d.tables) {
|
|
7069
|
+
const verbs = t.access === "write"
|
|
7070
|
+
? "read & write — db_query/db_get/db_insert/db_update/db_delete"
|
|
7071
|
+
: "read-only — db_query/db_get";
|
|
7072
|
+
lines.push(`- ${t.table} (${verbs}): ${t.description}`);
|
|
7073
|
+
}
|
|
7074
|
+
}
|
|
7075
|
+
if (d.functions.length) {
|
|
7076
|
+
lines.push("", "Functions you can invoke with call_function:");
|
|
7077
|
+
for (const f of d.functions)
|
|
7078
|
+
lines.push(`- ${f.name}: ${f.description}`);
|
|
7079
|
+
}
|
|
7080
|
+
if (agent.instructions?.trim()) {
|
|
7081
|
+
lines.push("", agent.instructions.trim());
|
|
7082
|
+
}
|
|
7083
|
+
// How to respond — the load-bearing behavioral contract. Without this, models
|
|
7084
|
+
// (especially gpt-oss) tend to run tool calls and then end their turn with no
|
|
7085
|
+
// user-facing message, so the user sees the work happen but gets no reply.
|
|
7086
|
+
const hasTools = d.tables.length > 0 || d.functions.length > 0;
|
|
7087
|
+
lines.push("", "How to respond:");
|
|
7088
|
+
if (hasTools) {
|
|
7089
|
+
lines.push("- When you need information or need to make a change, call your tools immediately — don't ask the user to do it, and don't describe or name the tools to them.", "- After your tool calls return, you MUST send one final reply to the channel, in plain language, that answers the request using the results.");
|
|
7090
|
+
}
|
|
7091
|
+
lines.push("- Always end your turn with a short written reply (one or two sentences). Never finish with only tool calls and no message, and never reply with an empty message.", "- Don't restate function names, parameters, JSON, or your list of tools to the user — just give them the answer.");
|
|
7092
|
+
lines.push("", "The exact columns, function parameters, and the full list of callable tools are supplied to you by the runtime. Follow that authoritative list — never invent tables, columns, functions, or tools.");
|
|
7093
|
+
return lines.join("\n");
|
|
7094
|
+
}
|
|
7095
|
+
/**
|
|
7096
|
+
* Derive a suggested tools allowlist from a decorated class — the db tables
|
|
7097
|
+
* (and whether any are writable), the callable functions, and whether channels
|
|
7098
|
+
* are in play. Pair with {@link ejectAgentPrompt} when configuring the agent.
|
|
7099
|
+
*
|
|
7100
|
+
* If any tables/functions are present the result has `enabled: true`; to
|
|
7101
|
+
* actually grant tools you must also pass a function-calling `model` in the same
|
|
7102
|
+
* `client.agents.create`/`update` call (the server enforces this).
|
|
7103
|
+
*/
|
|
7104
|
+
function ejectAgentTools(appClass, opts) {
|
|
7105
|
+
const d = REGISTRY.get(appClass);
|
|
7106
|
+
if (!d) {
|
|
7107
|
+
throw new Error("ejectAgentTools: the class must be decorated with @MuhkooAgent");
|
|
7108
|
+
}
|
|
7109
|
+
const anyWrite = d.tables.some((t) => t.access === "write");
|
|
7110
|
+
const mode = d.tables.length === 0 ? "off" : anyWrite ? "write" : "read";
|
|
7111
|
+
return {
|
|
7112
|
+
enabled: d.tables.length > 0 || d.functions.length > 0 || d.spaces.length > 0,
|
|
7113
|
+
db: { mode, tables: d.tables.map((t) => t.table) },
|
|
7114
|
+
functions: d.functions.map((f) => f.name),
|
|
7115
|
+
channels: d.spaces.length > 0,
|
|
7116
|
+
maxIterations: opts?.maxIterations ?? 6,
|
|
7117
|
+
};
|
|
7118
|
+
}
|
|
7119
|
+
|
|
6598
7120
|
const appLogger$1 = new Logger("connect", 'ERROR');
|
|
6599
7121
|
globalThis.appLogger = appLogger$1;
|
|
6600
7122
|
|
|
@@ -7131,5 +7653,5 @@ var bundledLoader = /*#__PURE__*/Object.freeze({
|
|
|
7131
7653
|
default: loadRsWasm
|
|
7132
7654
|
});
|
|
7133
7655
|
|
|
7134
|
-
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvNamespace, LocalStorageSessionStore, Logger, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, Ready, ReedSolomonCodec, Retry, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, WSTransport, ZkAuth, _accountId, _formatBytes, _messageId, _objectId, _packetId, _socketId, _userId, appLogger$1 as appLogger, assertType, base58Decode, base58Encode, buildCommitment, compilePrograms, concatBytes, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deserialize, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, fromBase64, fromBase64Url, fromHex, generateAuthProof, generateChecksum, generateId, getIPAddress, getId, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, isNumber, log, manifestToStat, poseidonHash, quickVerify, randomBytes, serialize, shardHash, signMessage, toBase64, toBase64Url, toField, toHex, unwrapWithPassphrase, utf8Decode, utf8Encode, verify, verifyChecksum, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
|
|
7656
|
+
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DbNamespace, DbTable, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvNamespace, LocalStorageSessionStore, Logger, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, Ready, ReedSolomonCodec, Retry, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, WSTransport, ZkAuth, _accountId, _formatBytes, _messageId, _objectId, _packetId, _socketId, _userId, appLogger$1 as appLogger, assertType, base58Decode, base58Encode, buildCommitment, compilePrograms, concatBytes, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deserialize, ejectAgentPrompt, ejectAgentTools, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, fromBase64, fromBase64Url, fromHex, generateAuthProof, generateChecksum, generateId, getIPAddress, getId, getMuhkooAppDescriptor, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, isNumber, log, manifestToStat, poseidonHash, quickVerify, randomBytes, serialize, shardHash, signMessage, toBase64, toBase64Url, toField, toHex, unwrapWithPassphrase, utf8Decode, utf8Encode, verify, verifyChecksum, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
|
|
7135
7657
|
//# sourceMappingURL=index.js.map
|