@calimero-network/mero-js 23.2.0 → 23.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ephemeral/index.d.ts +6 -0
- package/dist/ephemeral/index.js +39 -29
- package/dist/ephemeral/types.d.ts +5 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +214 -54
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/index.mjs +214 -54
- package/dist/index.mjs.map +4 -4
- package/dist/presence/relay-presence.d.ts +56 -0
- package/dist/presence/relay-presence.js +107 -0
- package/dist/presence/statement.d.ts +12 -0
- package/dist/presence/statement.js +17 -0
- package/dist/relay/relay-client.d.ts +32 -0
- package/dist/relay/relay-client.js +38 -16
- package/dist/transport/mero-client.d.ts +11 -12
- package/dist/transport/mero-client.js +14 -15
- package/dist/warrant/governance-op.d.ts +14 -5
- package/dist/warrant/governance-op.js +26 -0
- package/dist/warrant/index.d.ts +1 -1
- package/dist/warrant/index.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -15,13 +15,15 @@ export { MeroClient, createMeroClient, RelayTransport, RelayObserver, defaultAud
|
|
|
15
15
|
export type { MeroClientConfig, NodeTransportConfig, RelayTransportConfig, RelayObserveConfig, ExecuteTransport, ExecuteResult, TransportKind, } from './transport/index.js';
|
|
16
16
|
export { SseClient, WsClient } from "./events/index.js";
|
|
17
17
|
export type { SseEventData, WsEventData, AppVersionChangedEvent, GroupMembershipEventData, GroupMigrationEventData, MigrationStartedData, MigrationProgressData, CascadeProgressData, MigrationCompletedData, } from "./events/index.js";
|
|
18
|
-
export { EphemeralClient, jsonCodec } from "./ephemeral/index.js";
|
|
18
|
+
export { EphemeralClient, jsonCodec, subscribePresence } from "./ephemeral/index.js";
|
|
19
|
+
export { RelayPresenceClient } from "./presence/relay-presence.js";
|
|
20
|
+
export { presenceStatementBytes, stateHash, PRESENCE_DOMAIN } from "./presence/statement.js";
|
|
19
21
|
export type { Codec, EphemeralEntry } from "./ephemeral/index.js";
|
|
20
22
|
export * from "./cloud/index.js";
|
|
21
23
|
export * from "./sealed/index.js";
|
|
22
24
|
export * from "./relay/index.js";
|
|
23
25
|
export * from "./request-proof/index.js";
|
|
24
|
-
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from "./warrant/index.js";
|
|
26
|
+
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, targetApplicationSetOp, foundedNamespaceId, } from "./warrant/index.js";
|
|
25
27
|
export { signerFromSecret, signerFromCryptoKey } from "./signer/index.js";
|
|
26
28
|
export type { Signer } from "./signer/index.js";
|
|
27
29
|
export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, createAccountRootSigner, accountRootSignerFromPhrase, signAccountLink, signAccountLogin, resolveRoot, resolveRootPair, } from "./account/index.js";
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,9 @@ RelayObserver, defaultAudience, } from './transport/index.js';
|
|
|
24
24
|
// Events (SSE / WebSocket)
|
|
25
25
|
export { SseClient, WsClient } from "./events/index.js";
|
|
26
26
|
// Ephemeral presence (cursors / typing / online)
|
|
27
|
-
export { EphemeralClient, jsonCodec } from "./ephemeral/index.js";
|
|
27
|
+
export { EphemeralClient, jsonCodec, subscribePresence } from "./ephemeral/index.js";
|
|
28
|
+
export { RelayPresenceClient } from "./presence/relay-presence.js";
|
|
29
|
+
export { presenceStatementBytes, stateHash, PRESENCE_DOMAIN } from "./presence/statement.js";
|
|
28
30
|
// Cloud client — namespaces, relays, HA, and the cloud sign-in path
|
|
29
31
|
export * from "./cloud/index.js";
|
|
30
32
|
// Sealed transport — requests encrypted to a TEE node's attested key
|
|
@@ -34,7 +36,7 @@ export * from "./relay/index.js";
|
|
|
34
36
|
// Request proofs — a caller's identity on the request itself, no session needed
|
|
35
37
|
export * from "./request-proof/index.js";
|
|
36
38
|
// Warrant signing — mint the author's consent for a relay to run one intent
|
|
37
|
-
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from "./warrant/index.js";
|
|
39
|
+
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, createdSubgroupId, subgroupCreation, groupReparentedOp, groupDeletedOp, memberCapabilitySetOp, contextDetachedOp, subgroupVisibilitySetOp, groupMetadataSetOp, memberMetadataSetOp, contextMetadataSetOp, contextCapabilityGrantedOp, contextCapabilityRevokedOp, memberJoinedOpenOp, namespaceCreatedOp, defaultCapabilitiesSetOp, targetApplicationSetOp, foundedNamespaceId, } from "./warrant/index.js";
|
|
38
40
|
// Who signs — a key's capability, separated from its material, so a
|
|
39
41
|
// non-extractable key can be used wherever a hex secret could.
|
|
40
42
|
export { signerFromSecret, signerFromCryptoKey } from "./signer/index.js";
|
package/dist/index.mjs
CHANGED
|
@@ -3292,28 +3292,32 @@ var EphemeralClient = class {
|
|
|
3292
3292
|
* and zero mean different things). Returns an unsubscribe function.
|
|
3293
3293
|
*/
|
|
3294
3294
|
subscribe(contextId, handler, codec = jsonCodec()) {
|
|
3295
|
-
|
|
3296
|
-
const e = event;
|
|
3297
|
-
if (e.type !== "Ephemeral" || e.contextId !== contextId) return;
|
|
3298
|
-
const data = e.data;
|
|
3299
|
-
if (!data?.author) return;
|
|
3300
|
-
const removed = Boolean(data.removed);
|
|
3301
|
-
const entry = {
|
|
3302
|
-
author: data.author,
|
|
3303
|
-
state: removed || data.state === void 0 ? void 0 : codec.decode(data.state),
|
|
3304
|
-
removed
|
|
3305
|
-
};
|
|
3306
|
-
if (data.ageMs !== void 0) entry.ageMs = data.ageMs;
|
|
3307
|
-
handler(entry);
|
|
3308
|
-
};
|
|
3309
|
-
this.sse.on("event", listener);
|
|
3310
|
-
void this.sse.connect().catch(() => void 0);
|
|
3311
|
-
void this.sse.subscribe([contextId]).catch(() => void 0);
|
|
3312
|
-
return () => {
|
|
3313
|
-
this.sse.off("event", listener);
|
|
3314
|
-
};
|
|
3295
|
+
return subscribePresence(this.sse, contextId, handler, codec);
|
|
3315
3296
|
}
|
|
3316
3297
|
};
|
|
3298
|
+
function subscribePresence(sse, contextId, handler, codec = jsonCodec()) {
|
|
3299
|
+
const listener = (event) => {
|
|
3300
|
+
const e = event;
|
|
3301
|
+
if (e.type !== "Ephemeral" || e.contextId !== contextId) return;
|
|
3302
|
+
const data = e.data;
|
|
3303
|
+
if (!data?.author) return;
|
|
3304
|
+
const removed = Boolean(data.removed);
|
|
3305
|
+
const entry = {
|
|
3306
|
+
author: data.author,
|
|
3307
|
+
state: removed || data.state === void 0 ? void 0 : codec.decode(data.state),
|
|
3308
|
+
removed
|
|
3309
|
+
};
|
|
3310
|
+
if (data.ageMs !== void 0) entry.ageMs = data.ageMs;
|
|
3311
|
+
if (data.account !== void 0) entry.account = data.account;
|
|
3312
|
+
handler(entry);
|
|
3313
|
+
};
|
|
3314
|
+
sse.on("event", listener);
|
|
3315
|
+
void sse.connect().catch(() => void 0);
|
|
3316
|
+
void sse.subscribe([contextId]).catch(() => void 0);
|
|
3317
|
+
return () => {
|
|
3318
|
+
sse.off("event", listener);
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
3317
3321
|
|
|
3318
3322
|
// src/signer/signer.ts
|
|
3319
3323
|
var PKCS8_ED25519_PREFIX2 = new Uint8Array([
|
|
@@ -7405,6 +7409,7 @@ var GROUP_OP = {
|
|
|
7405
7409
|
MemberRoleSet: 4,
|
|
7406
7410
|
MemberCapabilitySet: 5,
|
|
7407
7411
|
DefaultCapabilitiesSet: 6,
|
|
7412
|
+
TargetApplicationSet: 7,
|
|
7408
7413
|
ContextDetached: 9,
|
|
7409
7414
|
SubgroupVisibilitySet: 10,
|
|
7410
7415
|
GroupMetadataSet: 11,
|
|
@@ -7478,6 +7483,23 @@ async function createdSubgroupId(admin, parentId, restricted, salt) {
|
|
|
7478
7483
|
])
|
|
7479
7484
|
);
|
|
7480
7485
|
}
|
|
7486
|
+
function borshString2(value, what) {
|
|
7487
|
+
if (value.length === 0) throw new Error(`${what} must not be empty`);
|
|
7488
|
+
const bytes = new TextEncoder().encode(value);
|
|
7489
|
+
return concat(u32le(bytes.length), bytes);
|
|
7490
|
+
}
|
|
7491
|
+
function targetApplicationSetOp(input) {
|
|
7492
|
+
return {
|
|
7493
|
+
kind: "group",
|
|
7494
|
+
bytes: concat(
|
|
7495
|
+
tag(GROUP_OP.TargetApplicationSet),
|
|
7496
|
+
CLEARED_HASH,
|
|
7497
|
+
fromHex(input.applicationId, "applicationId", 32),
|
|
7498
|
+
borshString2(input.package, "package"),
|
|
7499
|
+
borshString2(input.version, "version")
|
|
7500
|
+
)
|
|
7501
|
+
};
|
|
7502
|
+
}
|
|
7481
7503
|
function defaultCapabilitiesSetOp(capabilities) {
|
|
7482
7504
|
if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
|
|
7483
7505
|
throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
|
|
@@ -7739,6 +7761,19 @@ var RelayClient = class {
|
|
|
7739
7761
|
);
|
|
7740
7762
|
return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };
|
|
7741
7763
|
}
|
|
7764
|
+
/**
|
|
7765
|
+
* Publish one presence statement through the relay (`presence-intents`).
|
|
7766
|
+
*
|
|
7767
|
+
* Not retried on 429: presence resends every 2.5 s anyway, and a retry would
|
|
7768
|
+
* only queue behind the next resend. A refusal throws with its `status`.
|
|
7769
|
+
*/
|
|
7770
|
+
async presenceIntent(contextId, body) {
|
|
7771
|
+
await this.jsonOnce(
|
|
7772
|
+
"POST",
|
|
7773
|
+
`/admin-api/contexts/${encodeURIComponent(contextId)}/presence-intents`,
|
|
7774
|
+
body
|
|
7775
|
+
);
|
|
7776
|
+
}
|
|
7742
7777
|
/**
|
|
7743
7778
|
* Ask the relay what it can do about creating contexts in `groupId`.
|
|
7744
7779
|
*
|
|
@@ -7919,6 +7954,7 @@ var RelayClient = class {
|
|
|
7919
7954
|
salt
|
|
7920
7955
|
});
|
|
7921
7956
|
const capabilitiesOp = input.defaultCapabilities === void 0 ? void 0 : defaultCapabilitiesSetOp(input.defaultCapabilities);
|
|
7957
|
+
const applicationOp = input.application ? targetApplicationSetOp(input.application) : void 0;
|
|
7922
7958
|
const signer = await this.authorSigner();
|
|
7923
7959
|
const nonce2 = await this.config.nonces.next();
|
|
7924
7960
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
@@ -7938,17 +7974,25 @@ var RelayClient = class {
|
|
|
7938
7974
|
teeEnabled: data.teeEnabled ?? false,
|
|
7939
7975
|
...data.teeError ? { teeError: data.teeError } : {}
|
|
7940
7976
|
};
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7977
|
+
let result = founded;
|
|
7978
|
+
const message = (err) => err instanceof Error ? err.message : String(err);
|
|
7979
|
+
if (applicationOp) {
|
|
7980
|
+
try {
|
|
7981
|
+
await this.govern({ groupId: founded.namespaceId, op: applicationOp });
|
|
7982
|
+
result = { ...result, applicationSet: true };
|
|
7983
|
+
} catch (err) {
|
|
7984
|
+
result = { ...result, applicationSet: false, applicationError: message(err) };
|
|
7985
|
+
}
|
|
7986
|
+
}
|
|
7987
|
+
if (capabilitiesOp) {
|
|
7988
|
+
try {
|
|
7989
|
+
await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
|
|
7990
|
+
result = { ...result, defaultCapabilitiesSet: true };
|
|
7991
|
+
} catch (err) {
|
|
7992
|
+
result = { ...result, defaultCapabilitiesSet: false, defaultCapabilitiesError: message(err) };
|
|
7993
|
+
}
|
|
7951
7994
|
}
|
|
7995
|
+
return result;
|
|
7952
7996
|
}
|
|
7953
7997
|
async postGovernance(groupId, op, warrant) {
|
|
7954
7998
|
const body = await this.json("POST", `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`, {
|
|
@@ -8040,6 +8084,7 @@ var RelayClient = class {
|
|
|
8040
8084
|
text
|
|
8041
8085
|
);
|
|
8042
8086
|
}
|
|
8087
|
+
if (response.status === 204) return void 0;
|
|
8043
8088
|
return await response.json();
|
|
8044
8089
|
}
|
|
8045
8090
|
};
|
|
@@ -8467,6 +8512,121 @@ function signedPath(url) {
|
|
|
8467
8512
|
return new URL(url).pathname;
|
|
8468
8513
|
}
|
|
8469
8514
|
|
|
8515
|
+
// src/presence/statement.ts
|
|
8516
|
+
var PRESENCE_DOMAIN = new TextEncoder().encode("calimero/presence/1");
|
|
8517
|
+
async function stateHash(state) {
|
|
8518
|
+
const borsh = state === null ? new Uint8Array([0]) : concat(new Uint8Array([1]), u32le(state.length), state);
|
|
8519
|
+
return new Uint8Array(await crypto.subtle.digest("SHA-256", borsh));
|
|
8520
|
+
}
|
|
8521
|
+
async function presenceStatementBytes(input) {
|
|
8522
|
+
return concat(
|
|
8523
|
+
PRESENCE_DOMAIN,
|
|
8524
|
+
fromHex(input.contextId, "contextId", 32),
|
|
8525
|
+
fromHex(input.author, "author", 32),
|
|
8526
|
+
u64le(input.seq),
|
|
8527
|
+
u64le(input.sentAtMs),
|
|
8528
|
+
await stateHash(input.state)
|
|
8529
|
+
);
|
|
8530
|
+
}
|
|
8531
|
+
|
|
8532
|
+
// src/presence/relay-presence.ts
|
|
8533
|
+
var HEARTBEAT_MS = 2500;
|
|
8534
|
+
var RelayPresenceClient = class {
|
|
8535
|
+
/**
|
|
8536
|
+
* @param opts.events the relay's event stream, asked for only on `subscribe`:
|
|
8537
|
+
* publishing needs none, so a client with no node key can still publish.
|
|
8538
|
+
*/
|
|
8539
|
+
constructor(opts) {
|
|
8540
|
+
this.timers = /* @__PURE__ */ new Map();
|
|
8541
|
+
this.lastSeq = /* @__PURE__ */ new Map();
|
|
8542
|
+
this.refused = /* @__PURE__ */ new Set();
|
|
8543
|
+
/**
|
|
8544
|
+
* Bumped by every `set` and `close`, per context. A `set` installs its
|
|
8545
|
+
* resends only if nothing newer happened while its first send was in flight,
|
|
8546
|
+
* so a retract (or a newer state) can never be overtaken by an older one.
|
|
8547
|
+
*/
|
|
8548
|
+
this.generation = /* @__PURE__ */ new Map();
|
|
8549
|
+
this.relay = opts.relay;
|
|
8550
|
+
this.events = opts.events;
|
|
8551
|
+
this.heartbeatMs = opts.heartbeatMs ?? HEARTBEAT_MS;
|
|
8552
|
+
this.now = opts.now ?? Date.now;
|
|
8553
|
+
}
|
|
8554
|
+
/**
|
|
8555
|
+
* Set this account's presence in `contextId`, or retract it with `null`.
|
|
8556
|
+
* Throws when the relay refuses this first send for good (a 4xx other than
|
|
8557
|
+
* 429), which also stops the resends. A rate limit, a network failure or a
|
|
8558
|
+
* 5xx is not thrown: the next resend covers it.
|
|
8559
|
+
*/
|
|
8560
|
+
async set(contextId, state, codec = jsonCodec()) {
|
|
8561
|
+
const generation = this.bump(contextId);
|
|
8562
|
+
this.refused.delete(contextId);
|
|
8563
|
+
const bytes = state === null ? null : new Uint8Array(codec.encode(state));
|
|
8564
|
+
await this.send(contextId, bytes);
|
|
8565
|
+
if (bytes === null || this.refused.has(contextId)) return;
|
|
8566
|
+
if (this.generation.get(contextId) !== generation) return;
|
|
8567
|
+
this.timers.set(
|
|
8568
|
+
contextId,
|
|
8569
|
+
setInterval(() => void this.send(contextId, bytes).catch(() => void 0), this.heartbeatMs)
|
|
8570
|
+
);
|
|
8571
|
+
}
|
|
8572
|
+
subscribe(contextId, handler, codec = jsonCodec()) {
|
|
8573
|
+
return subscribePresence(this.events(), contextId, handler, codec);
|
|
8574
|
+
}
|
|
8575
|
+
/** Stop every resend. Entries expire on the relay and its peers within 7 s. */
|
|
8576
|
+
close() {
|
|
8577
|
+
for (const contextId of /* @__PURE__ */ new Set([...this.timers.keys(), ...this.generation.keys()])) {
|
|
8578
|
+
this.bump(contextId);
|
|
8579
|
+
}
|
|
8580
|
+
}
|
|
8581
|
+
/** Stop the context's resends and invalidate any `set` still in flight. */
|
|
8582
|
+
bump(contextId) {
|
|
8583
|
+
this.stop(contextId);
|
|
8584
|
+
const next = (this.generation.get(contextId) ?? 0) + 1;
|
|
8585
|
+
this.generation.set(contextId, next);
|
|
8586
|
+
return next;
|
|
8587
|
+
}
|
|
8588
|
+
stop(contextId) {
|
|
8589
|
+
const timer = this.timers.get(contextId);
|
|
8590
|
+
if (timer !== void 0) clearInterval(timer);
|
|
8591
|
+
this.timers.delete(contextId);
|
|
8592
|
+
}
|
|
8593
|
+
/** Wall-clock seeded and strictly rising, so a relay restart never sees an old seq. */
|
|
8594
|
+
nextSeq(contextId) {
|
|
8595
|
+
const seq = Math.max(this.now(), (this.lastSeq.get(contextId) ?? 0) + 1);
|
|
8596
|
+
this.lastSeq.set(contextId, seq);
|
|
8597
|
+
return seq;
|
|
8598
|
+
}
|
|
8599
|
+
async send(contextId, state) {
|
|
8600
|
+
if (this.refused.has(contextId)) return;
|
|
8601
|
+
const signer = await this.relay.authorSigner();
|
|
8602
|
+
const seq = this.nextSeq(contextId);
|
|
8603
|
+
const sentAtMs = this.now();
|
|
8604
|
+
const statement = await presenceStatementBytes({
|
|
8605
|
+
contextId,
|
|
8606
|
+
author: signer.publicKey,
|
|
8607
|
+
seq: BigInt(seq),
|
|
8608
|
+
sentAtMs: BigInt(sentAtMs),
|
|
8609
|
+
state
|
|
8610
|
+
});
|
|
8611
|
+
const signature = hex(await signer.sign(statement));
|
|
8612
|
+
try {
|
|
8613
|
+
await this.relay.presenceIntent(contextId, {
|
|
8614
|
+
state: state === null ? null : hex(state),
|
|
8615
|
+
seq,
|
|
8616
|
+
sentAtMs,
|
|
8617
|
+
signature,
|
|
8618
|
+
authorProof: this.relay.authorProof
|
|
8619
|
+
});
|
|
8620
|
+
} catch (err) {
|
|
8621
|
+
const status = err.status;
|
|
8622
|
+
if (status === void 0 || status === 0 || status === 429 || status >= 500) return;
|
|
8623
|
+
this.refused.add(contextId);
|
|
8624
|
+
this.stop(contextId);
|
|
8625
|
+
throw err;
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
};
|
|
8629
|
+
|
|
8470
8630
|
// src/transport/mero-client.ts
|
|
8471
8631
|
function relayHasNo(surface, why) {
|
|
8472
8632
|
return new Error(
|
|
@@ -8510,6 +8670,7 @@ var MeroClient = class {
|
|
|
8510
8670
|
this.proofAuthorizer = null;
|
|
8511
8671
|
this.relayUrl = null;
|
|
8512
8672
|
this.proofEvents = null;
|
|
8673
|
+
this.relayPresence = null;
|
|
8513
8674
|
if (config.transport === "relay") {
|
|
8514
8675
|
this.transport = "relay";
|
|
8515
8676
|
this.nodeClient = null;
|
|
@@ -8664,26 +8825,19 @@ var MeroClient = class {
|
|
|
8664
8825
|
/**
|
|
8665
8826
|
* Ephemeral presence. Node transport only.
|
|
8666
8827
|
*
|
|
8667
|
-
*
|
|
8668
|
-
*
|
|
8669
|
-
*
|
|
8670
|
-
*
|
|
8671
|
-
*
|
|
8672
|
-
*
|
|
8673
|
-
*
|
|
8674
|
-
*
|
|
8675
|
-
* The rejected alternative was to expose it over the relay session and let
|
|
8676
|
-
* `set` fail at the node. That trades a clear construction-time answer for a
|
|
8677
|
-
* runtime failure inside a UI that has already rendered.
|
|
8828
|
+
* On a relay client this is an account's presence client
|
|
8829
|
+
* ({@link RelayPresenceClient}): `set` signs each update with the device key
|
|
8830
|
+
* and posts it to the relay's `presence-intents`, resending every 2.5 s, and
|
|
8831
|
+
* `subscribe` reads the relay's event stream. The relay checks and forwards
|
|
8832
|
+
* the update; other members verify the device's signature and certificate
|
|
8833
|
+
* themselves, so it can drop or delay an account's presence but not invent or
|
|
8834
|
+
* alter it. Only `subscribe` needs the relay's node key (for the event
|
|
8835
|
+
* stream), so publishing works on any relay client.
|
|
8678
8836
|
*/
|
|
8679
8837
|
get ephemeral() {
|
|
8680
|
-
if (
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
"publishing resolves the author from an owned context identity on the node, which a delegated session is not known to have \u2014 read presence off `client.events` instead"
|
|
8684
|
-
);
|
|
8685
|
-
}
|
|
8686
|
-
return this.nodeClient.ephemeral;
|
|
8838
|
+
if (this.nodeClient) return this.nodeClient.ephemeral;
|
|
8839
|
+
this.relayPresence ?? (this.relayPresence = new RelayPresenceClient({ relay: this.relay, events: () => this.events }));
|
|
8840
|
+
return this.relayPresence;
|
|
8687
8841
|
}
|
|
8688
8842
|
/**
|
|
8689
8843
|
* Calimero Cloud.
|
|
@@ -10488,7 +10642,7 @@ function optionalBytes32(value, label2) {
|
|
|
10488
10642
|
}
|
|
10489
10643
|
return concat(new Uint8Array([1]), new Uint8Array(value));
|
|
10490
10644
|
}
|
|
10491
|
-
function
|
|
10645
|
+
function borshString3(value) {
|
|
10492
10646
|
const bytes = new TextEncoder().encode(value);
|
|
10493
10647
|
return concat(u32le(bytes.length), bytes);
|
|
10494
10648
|
}
|
|
@@ -10502,7 +10656,7 @@ function encodeSignedInvitation(signed) {
|
|
|
10502
10656
|
// ...then the enclosing SignedGroupOpenInvitation, in declaration order.
|
|
10503
10657
|
// `inviter_account` sits between the signature and the addresses; putting it
|
|
10504
10658
|
// anywhere else still encodes 32 bytes and still verifies as nothing.
|
|
10505
|
-
|
|
10659
|
+
borshString3(signed.inviter_signature),
|
|
10506
10660
|
signed.inviter_account ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, "inviter_account", 32)) : new Uint8Array([0]),
|
|
10507
10661
|
// A `Vec<String>`, so each entry is a bare borsh string. This carried an
|
|
10508
10662
|
// enum until core dropped the URL variant, and an enum writes a
|
|
@@ -10510,7 +10664,7 @@ function encodeSignedInvitation(signed) {
|
|
|
10510
10664
|
// every following byte and fail as `invalid invitation signature`, pointing
|
|
10511
10665
|
// nowhere near this line.
|
|
10512
10666
|
u32le(admitterAddrs.length),
|
|
10513
|
-
...admitterAddrs.map(
|
|
10667
|
+
...admitterAddrs.map(borshString3),
|
|
10514
10668
|
optionalBytes32(signed.application_id, "application_id"),
|
|
10515
10669
|
// Borsh order follows core's field order, where this is `bytecode_id`; the
|
|
10516
10670
|
// JSON key is `app_key`, a rename covering both directions that core pins in
|
|
@@ -10583,12 +10737,12 @@ var te = new TextEncoder();
|
|
|
10583
10737
|
function tag2(byte) {
|
|
10584
10738
|
return new Uint8Array([byte]);
|
|
10585
10739
|
}
|
|
10586
|
-
function
|
|
10740
|
+
function borshString4(value) {
|
|
10587
10741
|
const bytes = te.encode(value);
|
|
10588
10742
|
return concat(u32le(bytes.length), bytes);
|
|
10589
10743
|
}
|
|
10590
10744
|
function borshStrings(values) {
|
|
10591
|
-
return concat(u32le(values.length), ...values.map(
|
|
10745
|
+
return concat(u32le(values.length), ...values.map(borshString4));
|
|
10592
10746
|
}
|
|
10593
10747
|
function borshBool(value) {
|
|
10594
10748
|
return tag2(value ? 1 : 0);
|
|
@@ -10642,7 +10796,7 @@ function teeAdmissionPolicyOp(input) {
|
|
|
10642
10796
|
};
|
|
10643
10797
|
}
|
|
10644
10798
|
function teeReleaseAdmissionPolicyOp(input) {
|
|
10645
|
-
const minRelease = input.minReleaseVersion === void 0 ? tag2(0) : concat(tag2(1),
|
|
10799
|
+
const minRelease = input.minReleaseVersion === void 0 ? tag2(0) : concat(tag2(1), borshString4(input.minReleaseVersion));
|
|
10646
10800
|
return {
|
|
10647
10801
|
kind: "teeReleaseAdmissionPolicy",
|
|
10648
10802
|
plane: "group",
|
|
@@ -10899,9 +11053,11 @@ export {
|
|
|
10899
11053
|
MeroJs,
|
|
10900
11054
|
NODE_RELEASE_SIGNER,
|
|
10901
11055
|
OWNER_OP_KIND,
|
|
11056
|
+
PRESENCE_DOMAIN,
|
|
10902
11057
|
REQUEST_PROOF_HEADER,
|
|
10903
11058
|
RelayClient,
|
|
10904
11059
|
RelayObserver,
|
|
11060
|
+
RelayPresenceClient,
|
|
10905
11061
|
RelayTransport,
|
|
10906
11062
|
RpcClient,
|
|
10907
11063
|
RpcError,
|
|
@@ -11021,6 +11177,7 @@ export {
|
|
|
11021
11177
|
parseDeviceCredential,
|
|
11022
11178
|
parseGovernanceWarrant,
|
|
11023
11179
|
parseWarrantNonce,
|
|
11180
|
+
presenceStatementBytes,
|
|
11024
11181
|
probeNodeHealth,
|
|
11025
11182
|
readCloudLinkCallback,
|
|
11026
11183
|
readEnrolmentCallback,
|
|
@@ -11050,8 +11207,11 @@ export {
|
|
|
11050
11207
|
signedPath,
|
|
11051
11208
|
signerFromCryptoKey,
|
|
11052
11209
|
signerFromSecret,
|
|
11210
|
+
stateHash,
|
|
11053
11211
|
subgroupCreation,
|
|
11054
11212
|
subgroupVisibilitySetOp,
|
|
11213
|
+
subscribePresence,
|
|
11214
|
+
targetApplicationSetOp,
|
|
11055
11215
|
teeAdmissionPolicyOp,
|
|
11056
11216
|
teeAuthoringPolicyOp,
|
|
11057
11217
|
teeReleaseAdmissionPolicyOp,
|