@calimero-network/mero-js 22.6.0 → 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.d.ts CHANGED
@@ -18,7 +18,7 @@ export type { Codec, EphemeralEntry } from "./ephemeral/index.js";
18
18
  export * from "./cloud/index.js";
19
19
  export * from "./sealed/index.js";
20
20
  export * from "./relay/index.js";
21
- export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, groupReparentedOp, groupDeletedOp, } from "./warrant/index.js";
21
+ export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, groupReparentedOp, groupDeletedOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from "./warrant/index.js";
22
22
  export { signerFromSecret, signerFromCryptoKey } from "./signer/index.js";
23
23
  export type { Signer } from "./signer/index.js";
24
24
  export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, signAccountLink, signAccountLogin, } from "./account/index.js";
@@ -27,7 +27,7 @@ export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from
27
27
  export type { DeviceCertInput } from "./device-cert/index.js";
28
28
  export { signMemberJoinOp, encodeSignedInvitation, SIGNED_NAMESPACE_OP_SCHEMA_VERSION, } from "./namespace-op/index.js";
29
29
  export type { SignMemberJoinInput } from "./namespace-op/index.js";
30
- export type { WarrantInput, CreationWarrantInput, CreationWarrantFields, SignedCreationWarrant, GovernanceWarrantInput, GovernanceWarrantFields, GovernanceOp, GovernanceOpKind, GovernanceMemberRole, GroupCreatedInput, } from "./warrant/index.js";
30
+ export type { WarrantInput, CreationWarrantInput, CreationWarrantFields, SignedCreationWarrant, GovernanceWarrantInput, GovernanceWarrantFields, GovernanceOp, GovernanceOpKind, GovernanceMemberRole, GroupCreatedInput, NamespaceCreatedInput, } from "./warrant/index.js";
31
31
  export { requestBodyHash, signRequest, callerProof, createProofSigner, } from "./request/index.js";
32
32
  export type { CallerProofInput, ProofRequest, ProofSignerOptions, } from "./request/index.js";
33
33
  export type { RequestSigInput } from "./request/index.js";
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ export * from "./sealed/index.js";
27
27
  // Relay client — write through delegated execution, holding only a signing key
28
28
  export * from "./relay/index.js";
29
29
  // Warrant signing — mint the author's consent for a relay to run one intent
30
- export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, groupReparentedOp, groupDeletedOp, } from "./warrant/index.js";
30
+ export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, signGovernanceWarrant, parseGovernanceWarrant, governanceOpHash, memberAddedOp, memberRemovedOp, memberLeftOp, memberRoleSetOp, groupCreatedOp, groupReparentedOp, groupDeletedOp, namespaceCreatedOp, defaultCapabilitiesSetOp, foundedNamespaceId, } from "./warrant/index.js";
31
31
  // Who signs — a key's capability, separated from its material, so a
32
32
  // non-extractable key can be used wherever a hex secret could.
33
33
  export { signerFromSecret, signerFromCryptoKey } from "./signer/index.js";
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;
@@ -6921,6 +6956,138 @@ function kindByte(kind) {
6921
6956
  return byte;
6922
6957
  }
6923
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
+
6924
7091
  // src/relay/relay-client.ts
6925
7092
  var DEFAULT_TTL_SECONDS = 300;
6926
7093
  var IntentRefusedError = class extends Error {
@@ -7121,12 +7288,93 @@ var RelayClient = class {
7121
7288
  notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
7122
7289
  signer
7123
7290
  });
7124
- const body = await this.json(
7125
- "POST",
7126
- `/admin-api/groups/${encodeURIComponent(input.groupId)}/governance-intents`,
7127
- { warrant, authorProof: this.config.authorProof, op: hex(input.op.bytes) }
7128
- );
7129
- 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;
7130
7378
  }
7131
7379
  /**
7132
7380
  * The executor a warrant must name: the one the relay answered with, which a
@@ -8520,98 +8768,6 @@ function splitVersion2(version) {
8520
8768
  return [[Number(match[1]), Number(match[2]), Number(match[3])], match[4]];
8521
8769
  }
8522
8770
 
8523
- // src/warrant/governance-op.ts
8524
- var ROLE = {
8525
- Admin: 0,
8526
- Member: 1,
8527
- ReadOnly: 2
8528
- };
8529
- var GROUP_OP = {
8530
- MemberAdded: 1,
8531
- MemberRemoved: 2,
8532
- MemberLeft: 3,
8533
- MemberRoleSet: 4
8534
- };
8535
- var ROOT_OP = {
8536
- GroupCreated: 0,
8537
- GroupReparented: 1,
8538
- GroupDeleted: 2
8539
- };
8540
- var CLEARED_HASH = new Uint8Array(32);
8541
- var EMPTY_VEC = u32le(0);
8542
- function role(value) {
8543
- const byte = ROLE[value];
8544
- if (byte === void 0) {
8545
- throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
8546
- }
8547
- return new Uint8Array([byte]);
8548
- }
8549
- function tag(byte) {
8550
- return new Uint8Array([byte]);
8551
- }
8552
- function memberAddedOp(member, memberRole) {
8553
- return {
8554
- kind: "group",
8555
- bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
8556
- };
8557
- }
8558
- function memberRemovedOp(member) {
8559
- return {
8560
- kind: "group",
8561
- bytes: concat(
8562
- tag(GROUP_OP.MemberRemoved),
8563
- fromHex(member, "member", 32),
8564
- CLEARED_HASH,
8565
- EMPTY_VEC
8566
- )
8567
- };
8568
- }
8569
- function memberLeftOp(member) {
8570
- return {
8571
- kind: "group",
8572
- bytes: concat(
8573
- tag(GROUP_OP.MemberLeft),
8574
- fromHex(member, "member", 32),
8575
- CLEARED_HASH,
8576
- EMPTY_VEC
8577
- )
8578
- };
8579
- }
8580
- function memberRoleSetOp(member, memberRole) {
8581
- return {
8582
- kind: "group",
8583
- bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
8584
- };
8585
- }
8586
- function groupCreatedOp(input) {
8587
- return {
8588
- kind: "root",
8589
- bytes: concat(
8590
- tag(ROOT_OP.GroupCreated),
8591
- fromHex(input.groupId, "groupId", 32),
8592
- fromHex(input.parentId, "parentId", 32),
8593
- tag(input.restricted ? 1 : 0),
8594
- fromHex(input.admin, "admin", 32)
8595
- )
8596
- };
8597
- }
8598
- function groupReparentedOp(childGroupId, newParentId) {
8599
- return {
8600
- kind: "root",
8601
- bytes: concat(
8602
- tag(ROOT_OP.GroupReparented),
8603
- fromHex(childGroupId, "childGroupId", 32),
8604
- fromHex(newParentId, "newParentId", 32)
8605
- )
8606
- };
8607
- }
8608
- function groupDeletedOp(rootGroupId) {
8609
- return {
8610
- kind: "root",
8611
- bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
8612
- };
8613
- }
8614
-
8615
8771
  // src/namespace-op/namespace-op.ts
8616
8772
  var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 16;
8617
8773
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
@@ -8940,6 +9096,7 @@ export {
8940
9096
  AuthApiClient,
8941
9097
  AuthRevokedError,
8942
9098
  CAPABILITIES,
9099
+ CAPABILITY_PRESETS,
8943
9100
  CloudClient,
8944
9101
  DEFAULT_LOCAL_NODE_PORTS,
8945
9102
  DEFAULT_RELEASE_MIRROR,
@@ -8968,6 +9125,8 @@ export {
8968
9125
  admitterAddrsFromNetworkStatus,
8969
9126
  buildAuthLoginUrl,
8970
9127
  callerProof,
9128
+ capMask,
9129
+ capNames,
8971
9130
  classifyError,
8972
9131
  cloudNodeReleaseUrl,
8973
9132
  combineSignals,
@@ -8997,12 +9156,14 @@ export {
8997
9156
  createTimeoutSignal,
8998
9157
  createUniversalHttpClient,
8999
9158
  creationInitHash,
9159
+ defaultCapabilitiesSetOp,
9000
9160
  deviceCertPayload,
9001
9161
  discoverLocalNodes,
9002
9162
  encodeSignedInvitation,
9003
9163
  fetchAttestedTransportKey,
9004
9164
  fetchNodeRelease,
9005
9165
  fetchNodeReleaseVersion,
9166
+ foundedNamespaceId,
9006
9167
  generateAccountRoot,
9007
9168
  generateSessionKey,
9008
9169
  governanceOpHash,
@@ -9021,6 +9182,7 @@ export {
9021
9182
  memberRemovedOp,
9022
9183
  memberRoleSetOp,
9023
9184
  mintDeviceId,
9185
+ namespaceCreatedOp,
9024
9186
  nodeEndpoint,
9025
9187
  nodeReleaseVersionFromImage,
9026
9188
  parseAuthCallback,