@calimero-network/mero-js 22.5.1 → 22.7.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/index.mjs CHANGED
@@ -745,6 +745,41 @@ var CAPABILITIES = {
745
745
  */
746
746
  CAN_AUTHOR_ON_BEHALF: 1 << 9
747
747
  };
748
+ var CAPABILITY_PRESETS = {
749
+ /** No capabilities. */
750
+ NONE: 0,
751
+ /** Join Open subgroups only: what a namespace starts with. */
752
+ JOIN_ONLY: CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
753
+ /**
754
+ * Create contexts, invite members, join Open subgroups (= 7). A member who
755
+ * can work in the namespace but not reshape it.
756
+ */
757
+ CONTRIBUTOR: CAPABILITIES.CAN_CREATE_CONTEXT | CAPABILITIES.CAN_INVITE_MEMBERS | CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
758
+ /**
759
+ * `CONTRIBUTOR` plus create and delete subgroups and manage their visibility
760
+ * (= 231). What mero-chat gives members, so they can start and close their
761
+ * own channels.
762
+ */
763
+ COLLABORATOR: CAPABILITIES.CAN_CREATE_CONTEXT | CAPABILITIES.CAN_INVITE_MEMBERS | CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS | CAPABILITIES.CAN_CREATE_SUBGROUP | CAPABILITIES.CAN_DELETE_SUBGROUP | CAPABILITIES.CAN_MANAGE_VISIBILITY
764
+ };
765
+ function capMask(...caps) {
766
+ let mask = 0;
767
+ for (const cap of caps) {
768
+ if (typeof cap === "number") {
769
+ mask |= cap;
770
+ } else if (Object.prototype.hasOwnProperty.call(CAPABILITIES, cap)) {
771
+ mask |= CAPABILITIES[cap];
772
+ } else {
773
+ throw new Error(`unknown capability: ${String(cap)}`);
774
+ }
775
+ }
776
+ return mask >>> 0;
777
+ }
778
+ function capNames(mask) {
779
+ return Object.keys(CAPABILITIES).filter(
780
+ (name) => hasCap(mask, CAPABILITIES[name])
781
+ );
782
+ }
748
783
  function hasCap(mask, cap) {
749
784
  const capU32 = cap >>> 0;
750
785
  return (mask & capU32) >>> 0 === capU32;
@@ -6449,6 +6484,117 @@ var LocalStorageTokenStore = class {
6449
6484
  }
6450
6485
  };
6451
6486
 
6487
+ // src/signer/signer.ts
6488
+ var PKCS8_ED25519_PREFIX2 = new Uint8Array([
6489
+ 48,
6490
+ 46,
6491
+ 2,
6492
+ 1,
6493
+ 0,
6494
+ 48,
6495
+ 5,
6496
+ 6,
6497
+ 3,
6498
+ 43,
6499
+ 101,
6500
+ 112,
6501
+ 4,
6502
+ 34,
6503
+ 4,
6504
+ 32
6505
+ ]);
6506
+ function unsupported(cause) {
6507
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
6508
+ return new Error(
6509
+ "this runtime has no WebCrypto Ed25519, so nothing can be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it" + detail
6510
+ );
6511
+ }
6512
+ async function signerFromSecret(secret, label2 = "secret") {
6513
+ const seed = fromHex(secret, label2, 32);
6514
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX2, seed);
6515
+ let privateKey;
6516
+ let publicKey;
6517
+ try {
6518
+ const exportable = await crypto.subtle.importKey(
6519
+ "pkcs8",
6520
+ pkcs8,
6521
+ { name: "Ed25519" },
6522
+ true,
6523
+ ["sign"]
6524
+ );
6525
+ const jwk = await crypto.subtle.exportKey("jwk", exportable);
6526
+ publicKey = hex(
6527
+ Uint8Array.from(
6528
+ atob(jwk.x.replace(/-/g, "+").replace(/_/g, "/")),
6529
+ (c) => c.charCodeAt(0)
6530
+ )
6531
+ );
6532
+ privateKey = await crypto.subtle.importKey(
6533
+ "pkcs8",
6534
+ pkcs8,
6535
+ { name: "Ed25519" },
6536
+ false,
6537
+ ["sign"]
6538
+ );
6539
+ } catch (cause) {
6540
+ throw unsupported(cause);
6541
+ }
6542
+ return fromKeyAndPublic(privateKey, publicKey);
6543
+ }
6544
+ async function signerFromCryptoKey(privateKey, publicKey) {
6545
+ if (privateKey.type !== "private") {
6546
+ throw new Error(
6547
+ `signerFromCryptoKey needs the private half of the pair, got a ${privateKey.type} key`
6548
+ );
6549
+ }
6550
+ if (!privateKey.usages.includes("sign")) {
6551
+ throw new Error(
6552
+ "this CryptoKey cannot sign: generate it with usages ['sign', 'verify']"
6553
+ );
6554
+ }
6555
+ let publicHex;
6556
+ if (typeof publicKey === "string") {
6557
+ fromHex(publicKey, "publicKey", 32);
6558
+ publicHex = publicKey.trim().toLowerCase();
6559
+ } else {
6560
+ try {
6561
+ publicHex = hex(
6562
+ new Uint8Array(await crypto.subtle.exportKey("raw", publicKey))
6563
+ );
6564
+ } catch (cause) {
6565
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
6566
+ throw new Error(
6567
+ "could not read the public half of this key pair; pass the public key as 64 hex instead" + detail
6568
+ );
6569
+ }
6570
+ }
6571
+ return fromKeyAndPublic(privateKey, publicHex);
6572
+ }
6573
+ function fromKeyAndPublic(privateKey, publicKey) {
6574
+ return {
6575
+ publicKey,
6576
+ async sign(payload) {
6577
+ try {
6578
+ return new Uint8Array(
6579
+ await crypto.subtle.sign({ name: "Ed25519" }, privateKey, payload)
6580
+ );
6581
+ } catch (cause) {
6582
+ throw unsupported(cause);
6583
+ }
6584
+ }
6585
+ };
6586
+ }
6587
+ async function resolveSigner(secret, signer, label2) {
6588
+ if (signer && secret !== void 0) {
6589
+ throw new Error(
6590
+ `pass either ${label2} or signer, not both \u2014 they may name different keys`
6591
+ );
6592
+ }
6593
+ if (signer) return signer;
6594
+ if (secret !== void 0) return signerFromSecret(secret, label2);
6595
+ throw new Error(`${label2} or signer is required`);
6596
+ }
6597
+
6452
6598
  // src/warrant/warrant.ts
6453
6599
  var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.warrant.v2");
6454
6600
  var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
@@ -6469,8 +6615,8 @@ async function signWarrant(input) {
6469
6615
  );
6470
6616
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6471
6617
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6472
- const key = await importSigningKey(input.deviceSecret);
6473
- const publicKey = await derivePublicKey(input.deviceSecret);
6618
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
6619
+ const publicKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6474
6620
  const method = new TextEncoder().encode(input.method);
6475
6621
  const commitment = await intentHash(input.method, input.argsJson);
6476
6622
  const nonce2 = u64le(input.nonce);
@@ -6490,9 +6636,7 @@ async function signWarrant(input) {
6490
6636
  nonce2,
6491
6637
  notAfter
6492
6638
  ]);
6493
- const signature = new Uint8Array(
6494
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6495
- );
6639
+ const signature = checkedSignature(await signer.sign(preimage));
6496
6640
  return hex(
6497
6641
  concat(
6498
6642
  context,
@@ -6513,6 +6657,13 @@ async function signWarrant(input) {
6513
6657
  )
6514
6658
  );
6515
6659
  }
6660
+ function checkedSignature(signature) {
6661
+ if (!(signature instanceof Uint8Array) || signature.length !== 64) {
6662
+ const got = signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature;
6663
+ throw new Error(`signer returned ${got}, expected a 64-byte Ed25519 signature`);
6664
+ }
6665
+ return signature;
6666
+ }
6516
6667
  function citedHeads(heads, label2) {
6517
6668
  const list = heads ?? [];
6518
6669
  if (list.length > MAX_CITED_HEADS) {
@@ -6562,8 +6713,8 @@ async function signCreationWarrant(input) {
6562
6713
  const name = label(input.name, "name");
6563
6714
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6564
6715
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6565
- const key = await importSigningKey(input.deviceSecret);
6566
- const deviceKey = await derivePublicKey(input.deviceSecret);
6716
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
6717
+ const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6567
6718
  const initHash = await creationInitHash(input.initArgs);
6568
6719
  const preimage = await creationWarrantPreimage({
6569
6720
  group,
@@ -6580,9 +6731,7 @@ async function signCreationWarrant(input) {
6580
6731
  nonce: input.nonce,
6581
6732
  notAfter: input.notAfter
6582
6733
  });
6583
- const signature = new Uint8Array(
6584
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6585
- );
6734
+ const signature = checkedSignature(await signer.sign(preimage));
6586
6735
  const warrant = hex(
6587
6736
  concat(
6588
6737
  group,
@@ -6711,8 +6860,8 @@ async function signGovernanceWarrant(input) {
6711
6860
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6712
6861
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6713
6862
  const kind = kindByte(input.op.kind);
6714
- const key = await importSigningKey(input.deviceSecret);
6715
- const deviceKey = await derivePublicKey(input.deviceSecret);
6863
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
6864
+ const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6716
6865
  const opHash = await governanceOpHash(input.op);
6717
6866
  const preimage = await governanceWarrantPreimage({
6718
6867
  scope,
@@ -6726,9 +6875,7 @@ async function signGovernanceWarrant(input) {
6726
6875
  nonce: input.nonce,
6727
6876
  notAfter: input.notAfter
6728
6877
  });
6729
- const signature = new Uint8Array(
6730
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6731
- );
6878
+ const signature = checkedSignature(await signer.sign(preimage));
6732
6879
  return hex(
6733
6880
  concat(
6734
6881
  scope,
@@ -6809,6 +6956,138 @@ function kindByte(kind) {
6809
6956
  return byte;
6810
6957
  }
6811
6958
 
6959
+ // src/warrant/governance-op.ts
6960
+ var ROLE = {
6961
+ Admin: 0,
6962
+ Member: 1,
6963
+ ReadOnly: 2
6964
+ };
6965
+ var GROUP_OP = {
6966
+ MemberAdded: 1,
6967
+ MemberRemoved: 2,
6968
+ MemberLeft: 3,
6969
+ MemberRoleSet: 4,
6970
+ DefaultCapabilitiesSet: 6
6971
+ };
6972
+ var ROOT_OP = {
6973
+ GroupCreated: 0,
6974
+ GroupReparented: 1,
6975
+ GroupDeleted: 2,
6976
+ NamespaceCreatedV2: 9
6977
+ };
6978
+ var NAMESPACE_ID_DOMAIN = new TextEncoder().encode("calimero.namespace.id.v1");
6979
+ var CLEARED_HASH = new Uint8Array(32);
6980
+ var EMPTY_VEC = u32le(0);
6981
+ function role(value) {
6982
+ const byte = ROLE[value];
6983
+ if (byte === void 0) {
6984
+ throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
6985
+ }
6986
+ return new Uint8Array([byte]);
6987
+ }
6988
+ function tag(byte) {
6989
+ return new Uint8Array([byte]);
6990
+ }
6991
+ function memberAddedOp(member, memberRole) {
6992
+ return {
6993
+ kind: "group",
6994
+ bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
6995
+ };
6996
+ }
6997
+ function memberRemovedOp(member) {
6998
+ return {
6999
+ kind: "group",
7000
+ bytes: concat(
7001
+ tag(GROUP_OP.MemberRemoved),
7002
+ fromHex(member, "member", 32),
7003
+ CLEARED_HASH,
7004
+ EMPTY_VEC
7005
+ )
7006
+ };
7007
+ }
7008
+ function memberLeftOp(member) {
7009
+ return {
7010
+ kind: "group",
7011
+ bytes: concat(
7012
+ tag(GROUP_OP.MemberLeft),
7013
+ fromHex(member, "member", 32),
7014
+ CLEARED_HASH,
7015
+ EMPTY_VEC
7016
+ )
7017
+ };
7018
+ }
7019
+ function memberRoleSetOp(member, memberRole) {
7020
+ return {
7021
+ kind: "group",
7022
+ bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
7023
+ };
7024
+ }
7025
+ function defaultCapabilitiesSetOp(capabilities) {
7026
+ if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
7027
+ throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
7028
+ }
7029
+ if (hasCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
7030
+ throw new Error(
7031
+ "capabilities may not include CAN_AUTHOR_ON_BEHALF (512): a relay never carries a change to it"
7032
+ );
7033
+ }
7034
+ return {
7035
+ kind: "group",
7036
+ bytes: concat(tag(GROUP_OP.DefaultCapabilitiesSet), u32le(capabilities))
7037
+ };
7038
+ }
7039
+ function groupCreatedOp(input) {
7040
+ return {
7041
+ kind: "root",
7042
+ bytes: concat(
7043
+ tag(ROOT_OP.GroupCreated),
7044
+ fromHex(input.groupId, "groupId", 32),
7045
+ fromHex(input.parentId, "parentId", 32),
7046
+ tag(input.restricted ? 1 : 0),
7047
+ fromHex(input.admin, "admin", 32)
7048
+ )
7049
+ };
7050
+ }
7051
+ function groupReparentedOp(childGroupId, newParentId) {
7052
+ return {
7053
+ kind: "root",
7054
+ bytes: concat(
7055
+ tag(ROOT_OP.GroupReparented),
7056
+ fromHex(childGroupId, "childGroupId", 32),
7057
+ fromHex(newParentId, "newParentId", 32)
7058
+ )
7059
+ };
7060
+ }
7061
+ function groupDeletedOp(rootGroupId) {
7062
+ return {
7063
+ kind: "root",
7064
+ bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
7065
+ };
7066
+ }
7067
+ async function foundedNamespaceId(founder, salt) {
7068
+ return hex(
7069
+ await domainHash(NAMESPACE_ID_DOMAIN, [
7070
+ fromHex(founder, "founder", 32),
7071
+ fromHex(salt, "salt", 32)
7072
+ ])
7073
+ );
7074
+ }
7075
+ function namespaceCreatedOp(input) {
7076
+ const credential = fromHexUnsized(input.credential, "credential");
7077
+ if (credential.length === 0) {
7078
+ throw new Error("credential must be the founder's AccountProof<DeviceCert>, got nothing");
7079
+ }
7080
+ return {
7081
+ kind: "root",
7082
+ bytes: concat(
7083
+ tag(ROOT_OP.NamespaceCreatedV2),
7084
+ fromHex(input.founder, "founder", 32),
7085
+ credential,
7086
+ fromHex(input.salt, "salt", 32)
7087
+ )
7088
+ };
7089
+ }
7090
+
6812
7091
  // src/relay/relay-client.ts
6813
7092
  var DEFAULT_TTL_SECONDS = 300;
6814
7093
  var IntentRefusedError = class extends Error {
@@ -6829,6 +7108,14 @@ var RelayClient = class {
6829
7108
  this.fetchImpl = injected ? (input, init) => injected(input, init) : (input, init) => globalThis.fetch(input, init);
6830
7109
  this.timeoutMs = config.timeoutMs ?? 1e4;
6831
7110
  }
7111
+ /**
7112
+ * The author device's signer, built from `deviceSecret` when that is what was
7113
+ * configured. A {@link Signer} and never the secret, so no caller of a
7114
+ * `RelayClient` gains the ability to read key material.
7115
+ */
7116
+ async authorSigner() {
7117
+ return resolveSigner(this.config.deviceSecret, this.config.signer, "deviceSecret");
7118
+ }
6832
7119
  /**
6833
7120
  * Ask the relay what it can do in `contextId`.
6834
7121
  *
@@ -6850,6 +7137,7 @@ var RelayClient = class {
6850
7137
  */
6851
7138
  async execute(contextId, method, argsJson = {}) {
6852
7139
  const executor = this.executorAccount ?? (await this.describe(contextId)).executorAccount;
7140
+ const signer = await this.authorSigner();
6853
7141
  const nonce2 = await this.config.nonces.next();
6854
7142
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6855
7143
  const warrant = await signWarrant({
@@ -6860,7 +7148,7 @@ var RelayClient = class {
6860
7148
  argsJson,
6861
7149
  nonce: nonce2,
6862
7150
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6863
- deviceSecret: this.config.deviceSecret
7151
+ signer
6864
7152
  });
6865
7153
  const body = await this.json(
6866
7154
  "POST",
@@ -6924,6 +7212,7 @@ var RelayClient = class {
6924
7212
  }
6925
7213
  const executor = this.checkedExecutor(described.executorAccount);
6926
7214
  const initArgs = input.initArgs ?? {};
7215
+ const signer = await this.authorSigner();
6927
7216
  const nonce2 = await this.config.nonces.next();
6928
7217
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6929
7218
  const { warrant } = await signCreationWarrant({
@@ -6937,7 +7226,7 @@ var RelayClient = class {
6937
7226
  initArgs,
6938
7227
  nonce: nonce2,
6939
7228
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6940
- deviceSecret: this.config.deviceSecret
7229
+ signer
6941
7230
  });
6942
7231
  const body = await this.json(
6943
7232
  "POST",
@@ -6987,6 +7276,7 @@ var RelayClient = class {
6987
7276
  );
6988
7277
  }
6989
7278
  const executor = this.checkedExecutor(described.executorAccount);
7279
+ const signer = await this.authorSigner();
6990
7280
  const nonce2 = await this.config.nonces.next();
6991
7281
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6992
7282
  const warrant = await signGovernanceWarrant({
@@ -6996,14 +7286,95 @@ var RelayClient = class {
6996
7286
  executor,
6997
7287
  nonce: nonce2,
6998
7288
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6999
- deviceSecret: this.config.deviceSecret
7289
+ signer
7000
7290
  });
7001
- const body = await this.json(
7002
- "POST",
7003
- `/admin-api/groups/${encodeURIComponent(input.groupId)}/governance-intents`,
7004
- { warrant, authorProof: this.config.authorProof, op: hex(input.op.bytes) }
7005
- );
7006
- return { groupId: body.data.groupId };
7291
+ const data = await this.postGovernance(input.groupId, input.op, warrant);
7292
+ return { groupId: data.groupId };
7293
+ }
7294
+ /**
7295
+ * Found a namespace through the relay, with the author as its founder, owner
7296
+ * and admin. For an account with no node, this is how it gets a namespace at
7297
+ * all.
7298
+ *
7299
+ * The author signs the exact genesis (`NamespaceCreatedV2`, carrying the
7300
+ * author's own credential and the salt) under a root-plane governance
7301
+ * warrant scoped to the new namespace's id, which is derived from the
7302
+ * author's account and the salt, so the relay can neither choose another id
7303
+ * nor found it for anyone else. The relay takes an identity in the new
7304
+ * namespace, mints its key, publishes the genesis, and is seated as the
7305
+ * founding relay (a `Member` holding `CAN_AUTHOR_ON_BEHALF`), so later
7306
+ * `govern`, `createContext` and `execute` calls in the namespace work
7307
+ * through it straight away. A TEE relay then admits itself as the
7308
+ * namespace's first TEE; `teeEnabled` reports whether it did.
7309
+ *
7310
+ * The executor cannot be learned from the relay first: the namespace does not
7311
+ * exist, so `describeGovernance` has nothing to answer about. It comes from
7312
+ * `input.executorAccount`, the configured one, or one an earlier call learned
7313
+ * (`describe`, `createContext`, `govern`), and without any of them this
7314
+ * throws before taking a nonce.
7315
+ * The nonce is spent in the new namespace's ledger.
7316
+ *
7317
+ * With `defaultCapabilities`, the founder then sets the namespace's default
7318
+ * capability mask through the same relay (a second warrant, a second nonce)
7319
+ * and `defaultCapabilitiesSet` reports whether it landed. A failure there
7320
+ * does not throw, since the namespace is already founded.
7321
+ *
7322
+ * Refusals (`400`/`403`) come back as {@link IntentRefusedError}; a salt
7323
+ * that names an existing namespace is a `409`, an `HTTPError`.
7324
+ */
7325
+ async foundNamespace(input = {}) {
7326
+ const executor = input.executorAccount ? this.checkedExecutor(input.executorAccount) : this.executorAccount;
7327
+ if (!executor) {
7328
+ throw new Error(
7329
+ "foundNamespace needs the relay's account: pass executorAccount or configure it (checked before signing, no nonce was spent)"
7330
+ );
7331
+ }
7332
+ const salt = input.salt ? hex(fromHex(input.salt, "salt", 32)) : hex(crypto.getRandomValues(new Uint8Array(32)));
7333
+ const namespaceId = await foundedNamespaceId(this.config.authorAccount, salt);
7334
+ const op = namespaceCreatedOp({
7335
+ founder: this.config.authorAccount,
7336
+ credential: this.config.authorProof,
7337
+ salt
7338
+ });
7339
+ const capabilitiesOp = input.defaultCapabilities === void 0 ? void 0 : defaultCapabilitiesSetOp(input.defaultCapabilities);
7340
+ const signer = await this.authorSigner();
7341
+ const nonce2 = await this.config.nonces.next();
7342
+ const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
7343
+ const warrant = await signGovernanceWarrant({
7344
+ scope: namespaceId,
7345
+ op,
7346
+ authorAccount: this.config.authorAccount,
7347
+ executor,
7348
+ nonce: nonce2,
7349
+ notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
7350
+ signer
7351
+ });
7352
+ const data = await this.postGovernance(namespaceId, op, warrant);
7353
+ const founded = {
7354
+ namespaceId: data.groupId,
7355
+ salt,
7356
+ teeEnabled: data.teeEnabled ?? false,
7357
+ ...data.teeError ? { teeError: data.teeError } : {}
7358
+ };
7359
+ if (!capabilitiesOp) return founded;
7360
+ try {
7361
+ await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
7362
+ return { ...founded, defaultCapabilitiesSet: true };
7363
+ } catch (err) {
7364
+ return {
7365
+ ...founded,
7366
+ defaultCapabilitiesSet: false,
7367
+ defaultCapabilitiesError: err instanceof Error ? err.message : String(err)
7368
+ };
7369
+ }
7370
+ }
7371
+ async postGovernance(groupId, op, warrant) {
7372
+ const body = await this.json("POST", `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`, {
7373
+ warrant,
7374
+ authorProof: this.config.authorProof,
7375
+ op: hex(op.bytes)
7376
+ });
7377
+ return body.data;
7007
7378
  }
7008
7379
  /**
7009
7380
  * The executor a warrant must name: the one the relay answered with, which a
@@ -8397,98 +8768,6 @@ function splitVersion2(version) {
8397
8768
  return [[Number(match[1]), Number(match[2]), Number(match[3])], match[4]];
8398
8769
  }
8399
8770
 
8400
- // src/warrant/governance-op.ts
8401
- var ROLE = {
8402
- Admin: 0,
8403
- Member: 1,
8404
- ReadOnly: 2
8405
- };
8406
- var GROUP_OP = {
8407
- MemberAdded: 1,
8408
- MemberRemoved: 2,
8409
- MemberLeft: 3,
8410
- MemberRoleSet: 4
8411
- };
8412
- var ROOT_OP = {
8413
- GroupCreated: 0,
8414
- GroupReparented: 1,
8415
- GroupDeleted: 2
8416
- };
8417
- var CLEARED_HASH = new Uint8Array(32);
8418
- var EMPTY_VEC = u32le(0);
8419
- function role(value) {
8420
- const byte = ROLE[value];
8421
- if (byte === void 0) {
8422
- throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
8423
- }
8424
- return new Uint8Array([byte]);
8425
- }
8426
- function tag(byte) {
8427
- return new Uint8Array([byte]);
8428
- }
8429
- function memberAddedOp(member, memberRole) {
8430
- return {
8431
- kind: "group",
8432
- bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
8433
- };
8434
- }
8435
- function memberRemovedOp(member) {
8436
- return {
8437
- kind: "group",
8438
- bytes: concat(
8439
- tag(GROUP_OP.MemberRemoved),
8440
- fromHex(member, "member", 32),
8441
- CLEARED_HASH,
8442
- EMPTY_VEC
8443
- )
8444
- };
8445
- }
8446
- function memberLeftOp(member) {
8447
- return {
8448
- kind: "group",
8449
- bytes: concat(
8450
- tag(GROUP_OP.MemberLeft),
8451
- fromHex(member, "member", 32),
8452
- CLEARED_HASH,
8453
- EMPTY_VEC
8454
- )
8455
- };
8456
- }
8457
- function memberRoleSetOp(member, memberRole) {
8458
- return {
8459
- kind: "group",
8460
- bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
8461
- };
8462
- }
8463
- function groupCreatedOp(input) {
8464
- return {
8465
- kind: "root",
8466
- bytes: concat(
8467
- tag(ROOT_OP.GroupCreated),
8468
- fromHex(input.groupId, "groupId", 32),
8469
- fromHex(input.parentId, "parentId", 32),
8470
- tag(input.restricted ? 1 : 0),
8471
- fromHex(input.admin, "admin", 32)
8472
- )
8473
- };
8474
- }
8475
- function groupReparentedOp(childGroupId, newParentId) {
8476
- return {
8477
- kind: "root",
8478
- bytes: concat(
8479
- tag(ROOT_OP.GroupReparented),
8480
- fromHex(childGroupId, "childGroupId", 32),
8481
- fromHex(newParentId, "newParentId", 32)
8482
- )
8483
- };
8484
- }
8485
- function groupDeletedOp(rootGroupId) {
8486
- return {
8487
- kind: "root",
8488
- bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
8489
- };
8490
- }
8491
-
8492
8771
  // src/namespace-op/namespace-op.ts
8493
8772
  var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 16;
8494
8773
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
@@ -8817,6 +9096,7 @@ export {
8817
9096
  AuthApiClient,
8818
9097
  AuthRevokedError,
8819
9098
  CAPABILITIES,
9099
+ CAPABILITY_PRESETS,
8820
9100
  CloudClient,
8821
9101
  DEFAULT_LOCAL_NODE_PORTS,
8822
9102
  DEFAULT_RELEASE_MIRROR,
@@ -8845,6 +9125,8 @@ export {
8845
9125
  admitterAddrsFromNetworkStatus,
8846
9126
  buildAuthLoginUrl,
8847
9127
  callerProof,
9128
+ capMask,
9129
+ capNames,
8848
9130
  classifyError,
8849
9131
  cloudNodeReleaseUrl,
8850
9132
  combineSignals,
@@ -8874,12 +9156,14 @@ export {
8874
9156
  createTimeoutSignal,
8875
9157
  createUniversalHttpClient,
8876
9158
  creationInitHash,
9159
+ defaultCapabilitiesSetOp,
8877
9160
  deviceCertPayload,
8878
9161
  discoverLocalNodes,
8879
9162
  encodeSignedInvitation,
8880
9163
  fetchAttestedTransportKey,
8881
9164
  fetchNodeRelease,
8882
9165
  fetchNodeReleaseVersion,
9166
+ foundedNamespaceId,
8883
9167
  generateAccountRoot,
8884
9168
  generateSessionKey,
8885
9169
  governanceOpHash,
@@ -8898,6 +9182,7 @@ export {
8898
9182
  memberRemovedOp,
8899
9183
  memberRoleSetOp,
8900
9184
  mintDeviceId,
9185
+ namespaceCreatedOp,
8901
9186
  nodeEndpoint,
8902
9187
  nodeReleaseVersionFromImage,
8903
9188
  parseAuthCallback,
@@ -8918,6 +9203,8 @@ export {
8918
9203
  signRequest,
8919
9204
  signRoutingChallenge,
8920
9205
  signWarrant,
9206
+ signerFromCryptoKey,
9207
+ signerFromSecret,
8921
9208
  transportKeyBinding,
8922
9209
  trustSignedRelease,
8923
9210
  trustedMeasurementsFromReleases,