@calimero-network/mero-js 24.1.2 → 24.2.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/account/create-context.d.ts +2 -4
- package/dist/account/create-context.js +34 -14
- package/dist/account/session.d.ts +3 -2
- package/dist/admin-api/admin-client.d.ts +6 -6
- package/dist/admin-api/admin-client.js +6 -6
- package/dist/admin-api/admin-types.d.ts +10 -11
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +85 -43
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +85 -43
- package/dist/index.mjs.map +2 -2
- package/dist/namespace-op/namespace-op.d.ts +7 -1
- package/dist/namespace-op/namespace-op.js +7 -1
- package/dist/relay/index.d.ts +1 -1
- package/dist/relay/relay-client.d.ts +24 -27
- package/dist/relay/relay-client.js +39 -31
- package/dist/warrant/creation-warrant.d.ts +5 -1
- package/dist/warrant/creation-warrant.js +5 -1
- package/dist/warrant/governance-warrant.d.ts +5 -1
- package/dist/warrant/governance-warrant.js +5 -1
- package/dist/warrant/warrant.d.ts +7 -1
- package/dist/warrant/warrant.js +5 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1767,12 +1767,12 @@ var AdminApiClient = class {
|
|
|
1767
1767
|
* anything.
|
|
1768
1768
|
*
|
|
1769
1769
|
* The two facts {@link performIntent} needs and a client cannot derive: whose
|
|
1770
|
-
* account
|
|
1771
|
-
* `CAN_AUTHOR_ON_BEHALF` on the owning group.
|
|
1772
|
-
* back as an answer rather than an error
|
|
1773
|
-
* context
|
|
1774
|
-
* `executorAccount`" instead of presenting a
|
|
1775
|
-
* after the author has spent a nonce on it.
|
|
1770
|
+
* account and key go in the warrant's `executor` and `executor_key`, and
|
|
1771
|
+
* whether this node holds `CAN_AUTHOR_ON_BEHALF` on the owning group.
|
|
1772
|
+
* `canAuthorOnBehalf: false` comes back as an answer rather than an error, as
|
|
1773
|
+
* it is the default state of every context, so a caller can say "an admin of
|
|
1774
|
+
* `groupId` must grant it to `executorAccount`" instead of presenting a
|
|
1775
|
+
* warrant that will be refused after the author has spent a nonce on it.
|
|
1776
1776
|
*
|
|
1777
1777
|
* `404` means the context belongs to no group, or this node holds no account
|
|
1778
1778
|
* yet; either way it can be named as no warrant's executor.
|
|
@@ -7481,6 +7481,7 @@ async function signWarrant(input) {
|
|
|
7481
7481
|
const context = fromHex(input.context, "context", 32);
|
|
7482
7482
|
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
7483
7483
|
const executor = fromHex(input.executor, "executor", 32);
|
|
7484
|
+
const executorKey = fromHex(input.executorKey, "executorKey", 32);
|
|
7484
7485
|
const appVersion = fromHex(
|
|
7485
7486
|
input.appVersion ?? UNPINNED_APP,
|
|
7486
7487
|
"appVersion",
|
|
@@ -7499,6 +7500,7 @@ async function signWarrant(input) {
|
|
|
7499
7500
|
authorAccount,
|
|
7500
7501
|
publicKey,
|
|
7501
7502
|
executor,
|
|
7503
|
+
executorKey,
|
|
7502
7504
|
appVersion,
|
|
7503
7505
|
method,
|
|
7504
7506
|
commitment,
|
|
@@ -7516,6 +7518,7 @@ async function signWarrant(input) {
|
|
|
7516
7518
|
authorAccount,
|
|
7517
7519
|
publicKey,
|
|
7518
7520
|
executor,
|
|
7521
|
+
executorKey,
|
|
7519
7522
|
appVersion,
|
|
7520
7523
|
u32le(method.length),
|
|
7521
7524
|
method,
|
|
@@ -7562,6 +7565,7 @@ async function creationWarrantPreimage(p) {
|
|
|
7562
7565
|
p.authorAccount,
|
|
7563
7566
|
p.deviceKey,
|
|
7564
7567
|
p.executor,
|
|
7568
|
+
p.executorKey,
|
|
7565
7569
|
p.applicationId,
|
|
7566
7570
|
new Uint8Array([p.serviceName === null ? 0 : 1]),
|
|
7567
7571
|
p.serviceName ?? new Uint8Array(0),
|
|
@@ -7581,6 +7585,7 @@ async function signCreationWarrant(input) {
|
|
|
7581
7585
|
const seed = input.seed === void 0 ? crypto.getRandomValues(new Uint8Array(32)) : fromHex(input.seed, "seed", 32);
|
|
7582
7586
|
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
7583
7587
|
const executor = fromHex(input.executor, "executor", 32);
|
|
7588
|
+
const executorKey = fromHex(input.executorKey, "executorKey", 32);
|
|
7584
7589
|
const applicationId = fromHex(input.applicationId, "applicationId", 32);
|
|
7585
7590
|
const serviceName = label(input.serviceName, "serviceName");
|
|
7586
7591
|
const name = label(input.name, "name");
|
|
@@ -7595,6 +7600,7 @@ async function signCreationWarrant(input) {
|
|
|
7595
7600
|
authorAccount,
|
|
7596
7601
|
deviceKey,
|
|
7597
7602
|
executor,
|
|
7603
|
+
executorKey,
|
|
7598
7604
|
applicationId,
|
|
7599
7605
|
serviceName,
|
|
7600
7606
|
name,
|
|
@@ -7612,6 +7618,7 @@ async function signCreationWarrant(input) {
|
|
|
7612
7618
|
authorAccount,
|
|
7613
7619
|
deviceKey,
|
|
7614
7620
|
executor,
|
|
7621
|
+
executorKey,
|
|
7615
7622
|
applicationId,
|
|
7616
7623
|
borshOption(serviceName),
|
|
7617
7624
|
borshOption(name),
|
|
@@ -7671,6 +7678,7 @@ function parseCreationWarrant(warrant) {
|
|
|
7671
7678
|
authorAccount: hex(take(32, "authorAccount")),
|
|
7672
7679
|
deviceKey: hex(take(32, "deviceKey")),
|
|
7673
7680
|
executor: hex(take(32, "executor")),
|
|
7681
|
+
executorKey: hex(take(32, "executorKey")),
|
|
7674
7682
|
applicationId: hex(take(32, "applicationId")),
|
|
7675
7683
|
serviceName: option("serviceName"),
|
|
7676
7684
|
name: option("name"),
|
|
@@ -7717,6 +7725,7 @@ async function governanceWarrantPreimage(p) {
|
|
|
7717
7725
|
p.authorAccount,
|
|
7718
7726
|
p.deviceKey,
|
|
7719
7727
|
p.executor,
|
|
7728
|
+
p.executorKey,
|
|
7720
7729
|
p.opHash,
|
|
7721
7730
|
u64le(p.accountHeads.length),
|
|
7722
7731
|
...p.accountHeads,
|
|
@@ -7730,6 +7739,7 @@ async function signGovernanceWarrant(input) {
|
|
|
7730
7739
|
const scope = fromHex(input.scope, "scope", 32);
|
|
7731
7740
|
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
7732
7741
|
const executor = fromHex(input.executor, "executor", 32);
|
|
7742
|
+
const executorKey = fromHex(input.executorKey, "executorKey", 32);
|
|
7733
7743
|
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
7734
7744
|
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
7735
7745
|
const kind = kindByte(input.op.kind);
|
|
@@ -7742,6 +7752,7 @@ async function signGovernanceWarrant(input) {
|
|
|
7742
7752
|
authorAccount,
|
|
7743
7753
|
deviceKey,
|
|
7744
7754
|
executor,
|
|
7755
|
+
executorKey,
|
|
7745
7756
|
opHash,
|
|
7746
7757
|
accountHeads,
|
|
7747
7758
|
governanceFloor,
|
|
@@ -7756,6 +7767,7 @@ async function signGovernanceWarrant(input) {
|
|
|
7756
7767
|
authorAccount,
|
|
7757
7768
|
deviceKey,
|
|
7758
7769
|
executor,
|
|
7770
|
+
executorKey,
|
|
7759
7771
|
opHash,
|
|
7760
7772
|
u32le(accountHeads.length),
|
|
7761
7773
|
...accountHeads,
|
|
@@ -7807,6 +7819,7 @@ function parseGovernanceWarrant(warrant) {
|
|
|
7807
7819
|
authorAccount: hex(take(32, "authorAccount")),
|
|
7808
7820
|
deviceKey: hex(take(32, "deviceKey")),
|
|
7809
7821
|
executor: hex(take(32, "executor")),
|
|
7822
|
+
executorKey: hex(take(32, "executorKey")),
|
|
7810
7823
|
opHash: hex(take(32, "opHash")),
|
|
7811
7824
|
accountHeads: heads("accountHeads"),
|
|
7812
7825
|
governanceFloor: heads("governanceFloor"),
|
|
@@ -8111,7 +8124,6 @@ var RelayClient = class {
|
|
|
8111
8124
|
constructor(config) {
|
|
8112
8125
|
this.config = config;
|
|
8113
8126
|
this.baseUrl = config.relayUrl.replace(/\/+$/, "");
|
|
8114
|
-
this.executorAccount = config.executorAccount;
|
|
8115
8127
|
const injected = config.fetch;
|
|
8116
8128
|
this.fetchImpl = injected ? (input, init) => injected(input, init) : (input, init) => globalThis.fetch(input, init);
|
|
8117
8129
|
this.timeoutMs = config.timeoutMs ?? 1e4;
|
|
@@ -8161,8 +8173,11 @@ var RelayClient = class {
|
|
|
8161
8173
|
* as diagnostics after a failure.
|
|
8162
8174
|
*/
|
|
8163
8175
|
async describe(contextId) {
|
|
8164
|
-
const body = await this.json(
|
|
8165
|
-
|
|
8176
|
+
const body = await this.json(
|
|
8177
|
+
"GET",
|
|
8178
|
+
`/admin-api/contexts/${encodeURIComponent(contextId)}/intents`
|
|
8179
|
+
);
|
|
8180
|
+
this.checkedExecutor(body.data);
|
|
8166
8181
|
return body.data;
|
|
8167
8182
|
}
|
|
8168
8183
|
/**
|
|
@@ -8173,14 +8188,15 @@ var RelayClient = class {
|
|
|
8173
8188
|
* apply. Nothing accumulates and nothing is reusable.
|
|
8174
8189
|
*/
|
|
8175
8190
|
async execute(contextId, method, argsJson = {}) {
|
|
8176
|
-
const executor = this.
|
|
8191
|
+
const executor = this.executor ?? this.checkedExecutor(await this.describe(contextId));
|
|
8177
8192
|
const signer = await this.authorSigner();
|
|
8178
8193
|
const nonce2 = await this.config.nonces.next();
|
|
8179
8194
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
8180
8195
|
const warrant = await signWarrant({
|
|
8181
8196
|
context: contextId,
|
|
8182
8197
|
authorAccount: this.config.authorAccount,
|
|
8183
|
-
executor,
|
|
8198
|
+
executor: executor.executorAccount,
|
|
8199
|
+
executorKey: executor.executorKey,
|
|
8184
8200
|
method,
|
|
8185
8201
|
argsJson,
|
|
8186
8202
|
nonce: nonce2,
|
|
@@ -8191,7 +8207,10 @@ var RelayClient = class {
|
|
|
8191
8207
|
"POST",
|
|
8192
8208
|
`/admin-api/contexts/${encodeURIComponent(contextId)}/intents`,
|
|
8193
8209
|
{ method, argsJson, warrant, authorProof: this.config.authorProof }
|
|
8194
|
-
)
|
|
8210
|
+
).catch((err) => {
|
|
8211
|
+
if (err instanceof IntentRefusedError) this.executor = void 0;
|
|
8212
|
+
throw err;
|
|
8213
|
+
});
|
|
8195
8214
|
return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };
|
|
8196
8215
|
}
|
|
8197
8216
|
/**
|
|
@@ -8260,7 +8279,7 @@ var RelayClient = class {
|
|
|
8260
8279
|
403
|
|
8261
8280
|
);
|
|
8262
8281
|
}
|
|
8263
|
-
const executor = this.checkedExecutor(described
|
|
8282
|
+
const executor = this.checkedExecutor(described);
|
|
8264
8283
|
const initArgs = input.initArgs ?? {};
|
|
8265
8284
|
const signer = await this.authorSigner();
|
|
8266
8285
|
const nonce2 = await this.config.nonces.next();
|
|
@@ -8269,7 +8288,8 @@ var RelayClient = class {
|
|
|
8269
8288
|
group: input.groupId,
|
|
8270
8289
|
seed: input.seed,
|
|
8271
8290
|
authorAccount: this.config.authorAccount,
|
|
8272
|
-
executor,
|
|
8291
|
+
executor: executor.executorAccount,
|
|
8292
|
+
executorKey: executor.executorKey,
|
|
8273
8293
|
applicationId: input.applicationId,
|
|
8274
8294
|
serviceName: input.serviceName,
|
|
8275
8295
|
name: input.name,
|
|
@@ -8291,7 +8311,7 @@ var RelayClient = class {
|
|
|
8291
8311
|
}
|
|
8292
8312
|
/**
|
|
8293
8313
|
* Ask the relay whether it may publish governance ops for members of
|
|
8294
|
-
* `groupId`, and which account a warrant must name.
|
|
8314
|
+
* `groupId`, and which account and key a warrant must name.
|
|
8295
8315
|
*/
|
|
8296
8316
|
async describeGovernance(groupId) {
|
|
8297
8317
|
const body = await this.json(
|
|
@@ -8325,7 +8345,7 @@ var RelayClient = class {
|
|
|
8325
8345
|
403
|
|
8326
8346
|
);
|
|
8327
8347
|
}
|
|
8328
|
-
const executor = this.checkedExecutor(described
|
|
8348
|
+
const executor = this.checkedExecutor(described);
|
|
8329
8349
|
const signer = await this.authorSigner();
|
|
8330
8350
|
const nonce2 = await this.config.nonces.next();
|
|
8331
8351
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
@@ -8333,7 +8353,8 @@ var RelayClient = class {
|
|
|
8333
8353
|
scope: input.groupId,
|
|
8334
8354
|
op: input.op,
|
|
8335
8355
|
authorAccount: this.config.authorAccount,
|
|
8336
|
-
executor,
|
|
8356
|
+
executor: executor.executorAccount,
|
|
8357
|
+
executorKey: executor.executorKey,
|
|
8337
8358
|
nonce: nonce2,
|
|
8338
8359
|
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
8339
8360
|
signer
|
|
@@ -8359,9 +8380,7 @@ var RelayClient = class {
|
|
|
8359
8380
|
*
|
|
8360
8381
|
* The executor cannot be learned from the relay first: the namespace does not
|
|
8361
8382
|
* exist, so `describeGovernance` has nothing to answer about. It comes from
|
|
8362
|
-
* `input.
|
|
8363
|
-
* (`describe`, `createContext`, `govern`), and without any of them this
|
|
8364
|
-
* throws before taking a nonce.
|
|
8383
|
+
* `input.executor` only, and without it this throws before taking a nonce.
|
|
8365
8384
|
* The nonce is spent in the new namespace's ledger.
|
|
8366
8385
|
*
|
|
8367
8386
|
* With `defaultCapabilities`, the founder then sets the namespace's default
|
|
@@ -8372,13 +8391,13 @@ var RelayClient = class {
|
|
|
8372
8391
|
* Refusals (`400`/`403`) come back as {@link IntentRefusedError}; a salt
|
|
8373
8392
|
* that names an existing namespace is a `409`, an `HTTPError`.
|
|
8374
8393
|
*/
|
|
8375
|
-
async foundNamespace(input
|
|
8376
|
-
|
|
8377
|
-
if (!executor) {
|
|
8394
|
+
async foundNamespace(input) {
|
|
8395
|
+
if (!input?.executor) {
|
|
8378
8396
|
throw new Error(
|
|
8379
|
-
"foundNamespace needs the relay's account
|
|
8397
|
+
"foundNamespace needs the relay's account and signing key: pass executor (checked before signing, no nonce was spent)"
|
|
8380
8398
|
);
|
|
8381
8399
|
}
|
|
8400
|
+
const executor = this.checkedExecutor(input.executor);
|
|
8382
8401
|
const salt = input.salt ? hex(fromHex(input.salt, "salt", 32)) : hex(crypto.getRandomValues(new Uint8Array(32)));
|
|
8383
8402
|
const namespaceId = await foundedNamespaceId(this.config.authorAccount, salt);
|
|
8384
8403
|
const op = namespaceCreatedOp({
|
|
@@ -8395,7 +8414,8 @@ var RelayClient = class {
|
|
|
8395
8414
|
scope: namespaceId,
|
|
8396
8415
|
op,
|
|
8397
8416
|
authorAccount: this.config.authorAccount,
|
|
8398
|
-
executor,
|
|
8417
|
+
executor: executor.executorAccount,
|
|
8418
|
+
executorKey: executor.executorKey,
|
|
8399
8419
|
nonce: nonce2,
|
|
8400
8420
|
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
8401
8421
|
signer
|
|
@@ -8436,18 +8456,22 @@ var RelayClient = class {
|
|
|
8436
8456
|
return body.data;
|
|
8437
8457
|
}
|
|
8438
8458
|
/**
|
|
8439
|
-
* The
|
|
8440
|
-
*
|
|
8459
|
+
* The relay's answer, checked against a configured account and remembered.
|
|
8460
|
+
* Decoded here so a relay naming no key is refused before a nonce is taken.
|
|
8441
8461
|
*/
|
|
8442
8462
|
checkedExecutor(answered) {
|
|
8463
|
+
const executor = {
|
|
8464
|
+
executorAccount: hex(fromHex(answered.executorAccount ?? "", "the relay's executorAccount", 32)),
|
|
8465
|
+
executorKey: hex(fromHex(answered.executorKey ?? "", "the relay's executorKey", 32))
|
|
8466
|
+
};
|
|
8443
8467
|
const configured = this.config.executorAccount;
|
|
8444
|
-
if (configured && configured.toLowerCase() !==
|
|
8468
|
+
if (configured && configured.toLowerCase() !== executor.executorAccount) {
|
|
8445
8469
|
throw new Error(
|
|
8446
|
-
`configured executorAccount ${configured} is not the relay's account ${
|
|
8470
|
+
`configured executorAccount ${configured} is not the relay's account ${executor.executorAccount}; a warrant naming it would be unspendable`
|
|
8447
8471
|
);
|
|
8448
8472
|
}
|
|
8449
|
-
this.
|
|
8450
|
-
return
|
|
8473
|
+
this.executor = executor;
|
|
8474
|
+
return executor;
|
|
8451
8475
|
}
|
|
8452
8476
|
/**
|
|
8453
8477
|
* One request, waiting out a rate limit rather than failing the caller.
|
|
@@ -10434,7 +10458,7 @@ function bytes32(value, label2) {
|
|
|
10434
10458
|
}
|
|
10435
10459
|
|
|
10436
10460
|
// src/namespace-op/namespace-op.ts
|
|
10437
|
-
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION =
|
|
10461
|
+
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 23;
|
|
10438
10462
|
var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
|
|
10439
10463
|
var NAMESPACE_OP_ROOT = 0;
|
|
10440
10464
|
var ROOT_OP2 = {
|
|
@@ -10789,19 +10813,10 @@ async function foundDelegatedNamespace(s, req = {}, deps = {}) {
|
|
|
10789
10813
|
const relays = knownRelays(s).map((u) => u.replace(/\/+$/, ""));
|
|
10790
10814
|
const relay = relays[0];
|
|
10791
10815
|
if (!relay) throw new Error("no relay is known for this account, so there is nowhere to found a namespace");
|
|
10792
|
-
const
|
|
10793
|
-
([, url]) => url.replace(/\/+$/, "") === relay
|
|
10794
|
-
)?.[0];
|
|
10795
|
-
const named = s.executorAccount && s.relayUrl && s.relayUrl.replace(/\/+$/, "") === relay ? s.executorAccount : null;
|
|
10796
|
-
if (!named && !known) {
|
|
10797
|
-
throw new Error(
|
|
10798
|
-
"the executor account of this relay is not known: join a namespace on it first, or connect with the relay's executor account (the cloud shows it beside the relay)"
|
|
10799
|
-
);
|
|
10800
|
-
}
|
|
10801
|
-
const executorAccount = named ?? (await client(s, relay, governanceNonce(relay, known), deps.fetch).describeGovernance(known)).executorAccount;
|
|
10816
|
+
const executor = await foundingExecutor(s, relay, deps.fetch);
|
|
10802
10817
|
let next = BigInt(Date.now());
|
|
10803
10818
|
const founded = await client(s, relay, { next: async () => next++ }, deps.fetch).foundNamespace({
|
|
10804
|
-
|
|
10819
|
+
executor,
|
|
10805
10820
|
...req.defaultCapabilities !== void 0 ? { defaultCapabilities: req.defaultCapabilities } : {},
|
|
10806
10821
|
...req.application ? { application: req.application } : {}
|
|
10807
10822
|
});
|
|
@@ -10821,6 +10836,33 @@ async function foundDelegatedNamespace(s, req = {}, deps = {}) {
|
|
|
10821
10836
|
};
|
|
10822
10837
|
return { namespaceId: founded.namespaceId, teeEnabled: founded.teeEnabled, ...ha };
|
|
10823
10838
|
}
|
|
10839
|
+
async function foundingExecutor(s, relay, fetch2) {
|
|
10840
|
+
const named = s.executorAccount && s.relayUrl?.replace(/\/+$/, "") === relay ? s.executorAccount : null;
|
|
10841
|
+
if (named) return { executorAccount: named, executorKey: await attestedNodeKey(relay) };
|
|
10842
|
+
const known = Object.entries(readRelayMap(s.account).namespaces).find(
|
|
10843
|
+
([, url]) => url.replace(/\/+$/, "") === relay
|
|
10844
|
+
)?.[0];
|
|
10845
|
+
if (!known) {
|
|
10846
|
+
throw new Error(
|
|
10847
|
+
"the executor account of this relay is not known: join a namespace on it first, or connect with the relay's executor account (the cloud shows it beside the relay)"
|
|
10848
|
+
);
|
|
10849
|
+
}
|
|
10850
|
+
const executorKey = await attestedNodeKey(relay);
|
|
10851
|
+
const described = await client(s, relay, governanceNonce(relay, known), fetch2).describeGovernance(known);
|
|
10852
|
+
if (described.executorKey?.toLowerCase() !== executorKey) {
|
|
10853
|
+
throw new Error(
|
|
10854
|
+
`the relay's discovery names signing key ${described.executorKey}, not the relay's node key ${executorKey}: refusing to found through it`
|
|
10855
|
+
);
|
|
10856
|
+
}
|
|
10857
|
+
return { executorAccount: described.executorAccount, executorKey };
|
|
10858
|
+
}
|
|
10859
|
+
async function attestedNodeKey(relay) {
|
|
10860
|
+
const key = await attemptRelayNodeKey(relay);
|
|
10861
|
+
if (key.kind === "learned") return key.nodeKey;
|
|
10862
|
+
throw new Error(
|
|
10863
|
+
key.kind === "unavailable" ? "the relay's signing key could not be learned: its attestation did not answer, try again" : "the relay's attestation was refused, so founding through it is not possible (only a key from its operator, pinned with pinRelayNodeKey, can stand in)"
|
|
10864
|
+
);
|
|
10865
|
+
}
|
|
10824
10866
|
var HA_ACCOUNT_NOT_LINKED_MESSAGE = "link this account to your cloud user in the wallet so invitees can find this namespace";
|
|
10825
10867
|
var HA_REFUSAL_MESSAGES = {
|
|
10826
10868
|
account_not_linked: HA_ACCOUNT_NOT_LINKED_MESSAGE,
|