@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.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  AuthApiClient: () => AuthApiClient,
24
24
  AuthRevokedError: () => AuthRevokedError,
25
25
  CAPABILITIES: () => CAPABILITIES,
26
+ CAPABILITY_PRESETS: () => CAPABILITY_PRESETS,
26
27
  CloudClient: () => CloudClient,
27
28
  DEFAULT_LOCAL_NODE_PORTS: () => DEFAULT_LOCAL_NODE_PORTS,
28
29
  DEFAULT_RELEASE_MIRROR: () => DEFAULT_RELEASE_MIRROR,
@@ -51,6 +52,8 @@ __export(index_exports, {
51
52
  admitterAddrsFromNetworkStatus: () => admitterAddrsFromNetworkStatus,
52
53
  buildAuthLoginUrl: () => buildAuthLoginUrl,
53
54
  callerProof: () => callerProof,
55
+ capMask: () => capMask,
56
+ capNames: () => capNames,
54
57
  classifyError: () => classifyError,
55
58
  cloudNodeReleaseUrl: () => cloudNodeReleaseUrl,
56
59
  combineSignals: () => combineSignals,
@@ -80,12 +83,14 @@ __export(index_exports, {
80
83
  createTimeoutSignal: () => createTimeoutSignal,
81
84
  createUniversalHttpClient: () => createUniversalHttpClient,
82
85
  creationInitHash: () => creationInitHash,
86
+ defaultCapabilitiesSetOp: () => defaultCapabilitiesSetOp,
83
87
  deviceCertPayload: () => deviceCertPayload,
84
88
  discoverLocalNodes: () => discoverLocalNodes,
85
89
  encodeSignedInvitation: () => encodeSignedInvitation,
86
90
  fetchAttestedTransportKey: () => fetchAttestedTransportKey,
87
91
  fetchNodeRelease: () => fetchNodeRelease,
88
92
  fetchNodeReleaseVersion: () => fetchNodeReleaseVersion,
93
+ foundedNamespaceId: () => foundedNamespaceId,
89
94
  generateAccountRoot: () => generateAccountRoot,
90
95
  generateSessionKey: () => generateSessionKey,
91
96
  governanceOpHash: () => governanceOpHash,
@@ -104,6 +109,7 @@ __export(index_exports, {
104
109
  memberRemovedOp: () => memberRemovedOp,
105
110
  memberRoleSetOp: () => memberRoleSetOp,
106
111
  mintDeviceId: () => mintDeviceId,
112
+ namespaceCreatedOp: () => namespaceCreatedOp,
107
113
  nodeEndpoint: () => nodeEndpoint,
108
114
  nodeReleaseVersionFromImage: () => nodeReleaseVersionFromImage,
109
115
  parseAuthCallback: () => parseAuthCallback,
@@ -124,6 +130,8 @@ __export(index_exports, {
124
130
  signRequest: () => signRequest,
125
131
  signRoutingChallenge: () => signRoutingChallenge,
126
132
  signWarrant: () => signWarrant,
133
+ signerFromCryptoKey: () => signerFromCryptoKey,
134
+ signerFromSecret: () => signerFromSecret,
127
135
  transportKeyBinding: () => transportKeyBinding,
128
136
  trustSignedRelease: () => trustSignedRelease,
129
137
  trustedMeasurementsFromReleases: () => trustedMeasurementsFromReleases,
@@ -881,6 +889,41 @@ var CAPABILITIES = {
881
889
  */
882
890
  CAN_AUTHOR_ON_BEHALF: 1 << 9
883
891
  };
892
+ var CAPABILITY_PRESETS = {
893
+ /** No capabilities. */
894
+ NONE: 0,
895
+ /** Join Open subgroups only: what a namespace starts with. */
896
+ JOIN_ONLY: CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
897
+ /**
898
+ * Create contexts, invite members, join Open subgroups (= 7). A member who
899
+ * can work in the namespace but not reshape it.
900
+ */
901
+ CONTRIBUTOR: CAPABILITIES.CAN_CREATE_CONTEXT | CAPABILITIES.CAN_INVITE_MEMBERS | CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
902
+ /**
903
+ * `CONTRIBUTOR` plus create and delete subgroups and manage their visibility
904
+ * (= 231). What mero-chat gives members, so they can start and close their
905
+ * own channels.
906
+ */
907
+ 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
908
+ };
909
+ function capMask(...caps) {
910
+ let mask = 0;
911
+ for (const cap of caps) {
912
+ if (typeof cap === "number") {
913
+ mask |= cap;
914
+ } else if (Object.prototype.hasOwnProperty.call(CAPABILITIES, cap)) {
915
+ mask |= CAPABILITIES[cap];
916
+ } else {
917
+ throw new Error(`unknown capability: ${String(cap)}`);
918
+ }
919
+ }
920
+ return mask >>> 0;
921
+ }
922
+ function capNames(mask) {
923
+ return Object.keys(CAPABILITIES).filter(
924
+ (name) => hasCap(mask, CAPABILITIES[name])
925
+ );
926
+ }
884
927
  function hasCap(mask, cap) {
885
928
  const capU32 = cap >>> 0;
886
929
  return (mask & capU32) >>> 0 === capU32;
@@ -6585,6 +6628,117 @@ var LocalStorageTokenStore = class {
6585
6628
  }
6586
6629
  };
6587
6630
 
6631
+ // src/signer/signer.ts
6632
+ var PKCS8_ED25519_PREFIX2 = new Uint8Array([
6633
+ 48,
6634
+ 46,
6635
+ 2,
6636
+ 1,
6637
+ 0,
6638
+ 48,
6639
+ 5,
6640
+ 6,
6641
+ 3,
6642
+ 43,
6643
+ 101,
6644
+ 112,
6645
+ 4,
6646
+ 34,
6647
+ 4,
6648
+ 32
6649
+ ]);
6650
+ function unsupported(cause) {
6651
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
6652
+ return new Error(
6653
+ "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
6654
+ );
6655
+ }
6656
+ async function signerFromSecret(secret, label2 = "secret") {
6657
+ const seed = fromHex(secret, label2, 32);
6658
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX2, seed);
6659
+ let privateKey;
6660
+ let publicKey;
6661
+ try {
6662
+ const exportable = await crypto.subtle.importKey(
6663
+ "pkcs8",
6664
+ pkcs8,
6665
+ { name: "Ed25519" },
6666
+ true,
6667
+ ["sign"]
6668
+ );
6669
+ const jwk = await crypto.subtle.exportKey("jwk", exportable);
6670
+ publicKey = hex(
6671
+ Uint8Array.from(
6672
+ atob(jwk.x.replace(/-/g, "+").replace(/_/g, "/")),
6673
+ (c) => c.charCodeAt(0)
6674
+ )
6675
+ );
6676
+ privateKey = await crypto.subtle.importKey(
6677
+ "pkcs8",
6678
+ pkcs8,
6679
+ { name: "Ed25519" },
6680
+ false,
6681
+ ["sign"]
6682
+ );
6683
+ } catch (cause) {
6684
+ throw unsupported(cause);
6685
+ }
6686
+ return fromKeyAndPublic(privateKey, publicKey);
6687
+ }
6688
+ async function signerFromCryptoKey(privateKey, publicKey) {
6689
+ if (privateKey.type !== "private") {
6690
+ throw new Error(
6691
+ `signerFromCryptoKey needs the private half of the pair, got a ${privateKey.type} key`
6692
+ );
6693
+ }
6694
+ if (!privateKey.usages.includes("sign")) {
6695
+ throw new Error(
6696
+ "this CryptoKey cannot sign: generate it with usages ['sign', 'verify']"
6697
+ );
6698
+ }
6699
+ let publicHex;
6700
+ if (typeof publicKey === "string") {
6701
+ fromHex(publicKey, "publicKey", 32);
6702
+ publicHex = publicKey.trim().toLowerCase();
6703
+ } else {
6704
+ try {
6705
+ publicHex = hex(
6706
+ new Uint8Array(await crypto.subtle.exportKey("raw", publicKey))
6707
+ );
6708
+ } catch (cause) {
6709
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
6710
+ throw new Error(
6711
+ "could not read the public half of this key pair; pass the public key as 64 hex instead" + detail
6712
+ );
6713
+ }
6714
+ }
6715
+ return fromKeyAndPublic(privateKey, publicHex);
6716
+ }
6717
+ function fromKeyAndPublic(privateKey, publicKey) {
6718
+ return {
6719
+ publicKey,
6720
+ async sign(payload) {
6721
+ try {
6722
+ return new Uint8Array(
6723
+ await crypto.subtle.sign({ name: "Ed25519" }, privateKey, payload)
6724
+ );
6725
+ } catch (cause) {
6726
+ throw unsupported(cause);
6727
+ }
6728
+ }
6729
+ };
6730
+ }
6731
+ async function resolveSigner(secret, signer, label2) {
6732
+ if (signer && secret !== void 0) {
6733
+ throw new Error(
6734
+ `pass either ${label2} or signer, not both \u2014 they may name different keys`
6735
+ );
6736
+ }
6737
+ if (signer) return signer;
6738
+ if (secret !== void 0) return signerFromSecret(secret, label2);
6739
+ throw new Error(`${label2} or signer is required`);
6740
+ }
6741
+
6588
6742
  // src/warrant/warrant.ts
6589
6743
  var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.warrant.v2");
6590
6744
  var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
@@ -6605,8 +6759,8 @@ async function signWarrant(input) {
6605
6759
  );
6606
6760
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6607
6761
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6608
- const key = await importSigningKey(input.deviceSecret);
6609
- const publicKey = await derivePublicKey(input.deviceSecret);
6762
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
6763
+ const publicKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6610
6764
  const method = new TextEncoder().encode(input.method);
6611
6765
  const commitment = await intentHash(input.method, input.argsJson);
6612
6766
  const nonce2 = u64le(input.nonce);
@@ -6626,9 +6780,7 @@ async function signWarrant(input) {
6626
6780
  nonce2,
6627
6781
  notAfter
6628
6782
  ]);
6629
- const signature = new Uint8Array(
6630
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6631
- );
6783
+ const signature = checkedSignature(await signer.sign(preimage));
6632
6784
  return hex(
6633
6785
  concat(
6634
6786
  context,
@@ -6649,6 +6801,13 @@ async function signWarrant(input) {
6649
6801
  )
6650
6802
  );
6651
6803
  }
6804
+ function checkedSignature(signature) {
6805
+ if (!(signature instanceof Uint8Array) || signature.length !== 64) {
6806
+ const got = signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature;
6807
+ throw new Error(`signer returned ${got}, expected a 64-byte Ed25519 signature`);
6808
+ }
6809
+ return signature;
6810
+ }
6652
6811
  function citedHeads(heads, label2) {
6653
6812
  const list = heads ?? [];
6654
6813
  if (list.length > MAX_CITED_HEADS) {
@@ -6698,8 +6857,8 @@ async function signCreationWarrant(input) {
6698
6857
  const name = label(input.name, "name");
6699
6858
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6700
6859
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6701
- const key = await importSigningKey(input.deviceSecret);
6702
- const deviceKey = await derivePublicKey(input.deviceSecret);
6860
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
6861
+ const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6703
6862
  const initHash = await creationInitHash(input.initArgs);
6704
6863
  const preimage = await creationWarrantPreimage({
6705
6864
  group,
@@ -6716,9 +6875,7 @@ async function signCreationWarrant(input) {
6716
6875
  nonce: input.nonce,
6717
6876
  notAfter: input.notAfter
6718
6877
  });
6719
- const signature = new Uint8Array(
6720
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6721
- );
6878
+ const signature = checkedSignature(await signer.sign(preimage));
6722
6879
  const warrant = hex(
6723
6880
  concat(
6724
6881
  group,
@@ -6847,8 +7004,8 @@ async function signGovernanceWarrant(input) {
6847
7004
  const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6848
7005
  const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6849
7006
  const kind = kindByte(input.op.kind);
6850
- const key = await importSigningKey(input.deviceSecret);
6851
- const deviceKey = await derivePublicKey(input.deviceSecret);
7007
+ const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
7008
+ const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
6852
7009
  const opHash = await governanceOpHash(input.op);
6853
7010
  const preimage = await governanceWarrantPreimage({
6854
7011
  scope,
@@ -6862,9 +7019,7 @@ async function signGovernanceWarrant(input) {
6862
7019
  nonce: input.nonce,
6863
7020
  notAfter: input.notAfter
6864
7021
  });
6865
- const signature = new Uint8Array(
6866
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6867
- );
7022
+ const signature = checkedSignature(await signer.sign(preimage));
6868
7023
  return hex(
6869
7024
  concat(
6870
7025
  scope,
@@ -6945,6 +7100,138 @@ function kindByte(kind) {
6945
7100
  return byte;
6946
7101
  }
6947
7102
 
7103
+ // src/warrant/governance-op.ts
7104
+ var ROLE = {
7105
+ Admin: 0,
7106
+ Member: 1,
7107
+ ReadOnly: 2
7108
+ };
7109
+ var GROUP_OP = {
7110
+ MemberAdded: 1,
7111
+ MemberRemoved: 2,
7112
+ MemberLeft: 3,
7113
+ MemberRoleSet: 4,
7114
+ DefaultCapabilitiesSet: 6
7115
+ };
7116
+ var ROOT_OP = {
7117
+ GroupCreated: 0,
7118
+ GroupReparented: 1,
7119
+ GroupDeleted: 2,
7120
+ NamespaceCreatedV2: 9
7121
+ };
7122
+ var NAMESPACE_ID_DOMAIN = new TextEncoder().encode("calimero.namespace.id.v1");
7123
+ var CLEARED_HASH = new Uint8Array(32);
7124
+ var EMPTY_VEC = u32le(0);
7125
+ function role(value) {
7126
+ const byte = ROLE[value];
7127
+ if (byte === void 0) {
7128
+ throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
7129
+ }
7130
+ return new Uint8Array([byte]);
7131
+ }
7132
+ function tag(byte) {
7133
+ return new Uint8Array([byte]);
7134
+ }
7135
+ function memberAddedOp(member, memberRole) {
7136
+ return {
7137
+ kind: "group",
7138
+ bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
7139
+ };
7140
+ }
7141
+ function memberRemovedOp(member) {
7142
+ return {
7143
+ kind: "group",
7144
+ bytes: concat(
7145
+ tag(GROUP_OP.MemberRemoved),
7146
+ fromHex(member, "member", 32),
7147
+ CLEARED_HASH,
7148
+ EMPTY_VEC
7149
+ )
7150
+ };
7151
+ }
7152
+ function memberLeftOp(member) {
7153
+ return {
7154
+ kind: "group",
7155
+ bytes: concat(
7156
+ tag(GROUP_OP.MemberLeft),
7157
+ fromHex(member, "member", 32),
7158
+ CLEARED_HASH,
7159
+ EMPTY_VEC
7160
+ )
7161
+ };
7162
+ }
7163
+ function memberRoleSetOp(member, memberRole) {
7164
+ return {
7165
+ kind: "group",
7166
+ bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
7167
+ };
7168
+ }
7169
+ function defaultCapabilitiesSetOp(capabilities) {
7170
+ if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
7171
+ throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
7172
+ }
7173
+ if (hasCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
7174
+ throw new Error(
7175
+ "capabilities may not include CAN_AUTHOR_ON_BEHALF (512): a relay never carries a change to it"
7176
+ );
7177
+ }
7178
+ return {
7179
+ kind: "group",
7180
+ bytes: concat(tag(GROUP_OP.DefaultCapabilitiesSet), u32le(capabilities))
7181
+ };
7182
+ }
7183
+ function groupCreatedOp(input) {
7184
+ return {
7185
+ kind: "root",
7186
+ bytes: concat(
7187
+ tag(ROOT_OP.GroupCreated),
7188
+ fromHex(input.groupId, "groupId", 32),
7189
+ fromHex(input.parentId, "parentId", 32),
7190
+ tag(input.restricted ? 1 : 0),
7191
+ fromHex(input.admin, "admin", 32)
7192
+ )
7193
+ };
7194
+ }
7195
+ function groupReparentedOp(childGroupId, newParentId) {
7196
+ return {
7197
+ kind: "root",
7198
+ bytes: concat(
7199
+ tag(ROOT_OP.GroupReparented),
7200
+ fromHex(childGroupId, "childGroupId", 32),
7201
+ fromHex(newParentId, "newParentId", 32)
7202
+ )
7203
+ };
7204
+ }
7205
+ function groupDeletedOp(rootGroupId) {
7206
+ return {
7207
+ kind: "root",
7208
+ bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
7209
+ };
7210
+ }
7211
+ async function foundedNamespaceId(founder, salt) {
7212
+ return hex(
7213
+ await domainHash(NAMESPACE_ID_DOMAIN, [
7214
+ fromHex(founder, "founder", 32),
7215
+ fromHex(salt, "salt", 32)
7216
+ ])
7217
+ );
7218
+ }
7219
+ function namespaceCreatedOp(input) {
7220
+ const credential = fromHexUnsized(input.credential, "credential");
7221
+ if (credential.length === 0) {
7222
+ throw new Error("credential must be the founder's AccountProof<DeviceCert>, got nothing");
7223
+ }
7224
+ return {
7225
+ kind: "root",
7226
+ bytes: concat(
7227
+ tag(ROOT_OP.NamespaceCreatedV2),
7228
+ fromHex(input.founder, "founder", 32),
7229
+ credential,
7230
+ fromHex(input.salt, "salt", 32)
7231
+ )
7232
+ };
7233
+ }
7234
+
6948
7235
  // src/relay/relay-client.ts
6949
7236
  var DEFAULT_TTL_SECONDS = 300;
6950
7237
  var IntentRefusedError = class extends Error {
@@ -6965,6 +7252,14 @@ var RelayClient = class {
6965
7252
  this.fetchImpl = injected ? (input, init) => injected(input, init) : (input, init) => globalThis.fetch(input, init);
6966
7253
  this.timeoutMs = config.timeoutMs ?? 1e4;
6967
7254
  }
7255
+ /**
7256
+ * The author device's signer, built from `deviceSecret` when that is what was
7257
+ * configured. A {@link Signer} and never the secret, so no caller of a
7258
+ * `RelayClient` gains the ability to read key material.
7259
+ */
7260
+ async authorSigner() {
7261
+ return resolveSigner(this.config.deviceSecret, this.config.signer, "deviceSecret");
7262
+ }
6968
7263
  /**
6969
7264
  * Ask the relay what it can do in `contextId`.
6970
7265
  *
@@ -6986,6 +7281,7 @@ var RelayClient = class {
6986
7281
  */
6987
7282
  async execute(contextId, method, argsJson = {}) {
6988
7283
  const executor = this.executorAccount ?? (await this.describe(contextId)).executorAccount;
7284
+ const signer = await this.authorSigner();
6989
7285
  const nonce2 = await this.config.nonces.next();
6990
7286
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6991
7287
  const warrant = await signWarrant({
@@ -6996,7 +7292,7 @@ var RelayClient = class {
6996
7292
  argsJson,
6997
7293
  nonce: nonce2,
6998
7294
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6999
- deviceSecret: this.config.deviceSecret
7295
+ signer
7000
7296
  });
7001
7297
  const body = await this.json(
7002
7298
  "POST",
@@ -7060,6 +7356,7 @@ var RelayClient = class {
7060
7356
  }
7061
7357
  const executor = this.checkedExecutor(described.executorAccount);
7062
7358
  const initArgs = input.initArgs ?? {};
7359
+ const signer = await this.authorSigner();
7063
7360
  const nonce2 = await this.config.nonces.next();
7064
7361
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
7065
7362
  const { warrant } = await signCreationWarrant({
@@ -7073,7 +7370,7 @@ var RelayClient = class {
7073
7370
  initArgs,
7074
7371
  nonce: nonce2,
7075
7372
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
7076
- deviceSecret: this.config.deviceSecret
7373
+ signer
7077
7374
  });
7078
7375
  const body = await this.json(
7079
7376
  "POST",
@@ -7123,6 +7420,7 @@ var RelayClient = class {
7123
7420
  );
7124
7421
  }
7125
7422
  const executor = this.checkedExecutor(described.executorAccount);
7423
+ const signer = await this.authorSigner();
7126
7424
  const nonce2 = await this.config.nonces.next();
7127
7425
  const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
7128
7426
  const warrant = await signGovernanceWarrant({
@@ -7132,14 +7430,95 @@ var RelayClient = class {
7132
7430
  executor,
7133
7431
  nonce: nonce2,
7134
7432
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
7135
- deviceSecret: this.config.deviceSecret
7433
+ signer
7136
7434
  });
7137
- const body = await this.json(
7138
- "POST",
7139
- `/admin-api/groups/${encodeURIComponent(input.groupId)}/governance-intents`,
7140
- { warrant, authorProof: this.config.authorProof, op: hex(input.op.bytes) }
7141
- );
7142
- return { groupId: body.data.groupId };
7435
+ const data = await this.postGovernance(input.groupId, input.op, warrant);
7436
+ return { groupId: data.groupId };
7437
+ }
7438
+ /**
7439
+ * Found a namespace through the relay, with the author as its founder, owner
7440
+ * and admin. For an account with no node, this is how it gets a namespace at
7441
+ * all.
7442
+ *
7443
+ * The author signs the exact genesis (`NamespaceCreatedV2`, carrying the
7444
+ * author's own credential and the salt) under a root-plane governance
7445
+ * warrant scoped to the new namespace's id, which is derived from the
7446
+ * author's account and the salt, so the relay can neither choose another id
7447
+ * nor found it for anyone else. The relay takes an identity in the new
7448
+ * namespace, mints its key, publishes the genesis, and is seated as the
7449
+ * founding relay (a `Member` holding `CAN_AUTHOR_ON_BEHALF`), so later
7450
+ * `govern`, `createContext` and `execute` calls in the namespace work
7451
+ * through it straight away. A TEE relay then admits itself as the
7452
+ * namespace's first TEE; `teeEnabled` reports whether it did.
7453
+ *
7454
+ * The executor cannot be learned from the relay first: the namespace does not
7455
+ * exist, so `describeGovernance` has nothing to answer about. It comes from
7456
+ * `input.executorAccount`, the configured one, or one an earlier call learned
7457
+ * (`describe`, `createContext`, `govern`), and without any of them this
7458
+ * throws before taking a nonce.
7459
+ * The nonce is spent in the new namespace's ledger.
7460
+ *
7461
+ * With `defaultCapabilities`, the founder then sets the namespace's default
7462
+ * capability mask through the same relay (a second warrant, a second nonce)
7463
+ * and `defaultCapabilitiesSet` reports whether it landed. A failure there
7464
+ * does not throw, since the namespace is already founded.
7465
+ *
7466
+ * Refusals (`400`/`403`) come back as {@link IntentRefusedError}; a salt
7467
+ * that names an existing namespace is a `409`, an `HTTPError`.
7468
+ */
7469
+ async foundNamespace(input = {}) {
7470
+ const executor = input.executorAccount ? this.checkedExecutor(input.executorAccount) : this.executorAccount;
7471
+ if (!executor) {
7472
+ throw new Error(
7473
+ "foundNamespace needs the relay's account: pass executorAccount or configure it (checked before signing, no nonce was spent)"
7474
+ );
7475
+ }
7476
+ const salt = input.salt ? hex(fromHex(input.salt, "salt", 32)) : hex(crypto.getRandomValues(new Uint8Array(32)));
7477
+ const namespaceId = await foundedNamespaceId(this.config.authorAccount, salt);
7478
+ const op = namespaceCreatedOp({
7479
+ founder: this.config.authorAccount,
7480
+ credential: this.config.authorProof,
7481
+ salt
7482
+ });
7483
+ const capabilitiesOp = input.defaultCapabilities === void 0 ? void 0 : defaultCapabilitiesSetOp(input.defaultCapabilities);
7484
+ const signer = await this.authorSigner();
7485
+ const nonce2 = await this.config.nonces.next();
7486
+ const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
7487
+ const warrant = await signGovernanceWarrant({
7488
+ scope: namespaceId,
7489
+ op,
7490
+ authorAccount: this.config.authorAccount,
7491
+ executor,
7492
+ nonce: nonce2,
7493
+ notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
7494
+ signer
7495
+ });
7496
+ const data = await this.postGovernance(namespaceId, op, warrant);
7497
+ const founded = {
7498
+ namespaceId: data.groupId,
7499
+ salt,
7500
+ teeEnabled: data.teeEnabled ?? false,
7501
+ ...data.teeError ? { teeError: data.teeError } : {}
7502
+ };
7503
+ if (!capabilitiesOp) return founded;
7504
+ try {
7505
+ await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
7506
+ return { ...founded, defaultCapabilitiesSet: true };
7507
+ } catch (err) {
7508
+ return {
7509
+ ...founded,
7510
+ defaultCapabilitiesSet: false,
7511
+ defaultCapabilitiesError: err instanceof Error ? err.message : String(err)
7512
+ };
7513
+ }
7514
+ }
7515
+ async postGovernance(groupId, op, warrant) {
7516
+ const body = await this.json("POST", `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`, {
7517
+ warrant,
7518
+ authorProof: this.config.authorProof,
7519
+ op: hex(op.bytes)
7520
+ });
7521
+ return body.data;
7143
7522
  }
7144
7523
  /**
7145
7524
  * The executor a warrant must name: the one the relay answered with, which a
@@ -8533,98 +8912,6 @@ function splitVersion2(version) {
8533
8912
  return [[Number(match[1]), Number(match[2]), Number(match[3])], match[4]];
8534
8913
  }
8535
8914
 
8536
- // src/warrant/governance-op.ts
8537
- var ROLE = {
8538
- Admin: 0,
8539
- Member: 1,
8540
- ReadOnly: 2
8541
- };
8542
- var GROUP_OP = {
8543
- MemberAdded: 1,
8544
- MemberRemoved: 2,
8545
- MemberLeft: 3,
8546
- MemberRoleSet: 4
8547
- };
8548
- var ROOT_OP = {
8549
- GroupCreated: 0,
8550
- GroupReparented: 1,
8551
- GroupDeleted: 2
8552
- };
8553
- var CLEARED_HASH = new Uint8Array(32);
8554
- var EMPTY_VEC = u32le(0);
8555
- function role(value) {
8556
- const byte = ROLE[value];
8557
- if (byte === void 0) {
8558
- throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
8559
- }
8560
- return new Uint8Array([byte]);
8561
- }
8562
- function tag(byte) {
8563
- return new Uint8Array([byte]);
8564
- }
8565
- function memberAddedOp(member, memberRole) {
8566
- return {
8567
- kind: "group",
8568
- bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
8569
- };
8570
- }
8571
- function memberRemovedOp(member) {
8572
- return {
8573
- kind: "group",
8574
- bytes: concat(
8575
- tag(GROUP_OP.MemberRemoved),
8576
- fromHex(member, "member", 32),
8577
- CLEARED_HASH,
8578
- EMPTY_VEC
8579
- )
8580
- };
8581
- }
8582
- function memberLeftOp(member) {
8583
- return {
8584
- kind: "group",
8585
- bytes: concat(
8586
- tag(GROUP_OP.MemberLeft),
8587
- fromHex(member, "member", 32),
8588
- CLEARED_HASH,
8589
- EMPTY_VEC
8590
- )
8591
- };
8592
- }
8593
- function memberRoleSetOp(member, memberRole) {
8594
- return {
8595
- kind: "group",
8596
- bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
8597
- };
8598
- }
8599
- function groupCreatedOp(input) {
8600
- return {
8601
- kind: "root",
8602
- bytes: concat(
8603
- tag(ROOT_OP.GroupCreated),
8604
- fromHex(input.groupId, "groupId", 32),
8605
- fromHex(input.parentId, "parentId", 32),
8606
- tag(input.restricted ? 1 : 0),
8607
- fromHex(input.admin, "admin", 32)
8608
- )
8609
- };
8610
- }
8611
- function groupReparentedOp(childGroupId, newParentId) {
8612
- return {
8613
- kind: "root",
8614
- bytes: concat(
8615
- tag(ROOT_OP.GroupReparented),
8616
- fromHex(childGroupId, "childGroupId", 32),
8617
- fromHex(newParentId, "newParentId", 32)
8618
- )
8619
- };
8620
- }
8621
- function groupDeletedOp(rootGroupId) {
8622
- return {
8623
- kind: "root",
8624
- bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
8625
- };
8626
- }
8627
-
8628
8915
  // src/namespace-op/namespace-op.ts
8629
8916
  var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 16;
8630
8917
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");