@calimero-network/mero-js 22.3.0 → 22.5.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
@@ -2183,11 +2183,11 @@ function u32le(value) {
2183
2183
  function hex(bytes) {
2184
2184
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2185
2185
  }
2186
- function fromHex(value, label, expectedBytes) {
2186
+ function fromHex(value, label2, expectedBytes) {
2187
2187
  const clean = value.trim();
2188
2188
  if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
2189
2189
  throw new Error(
2190
- `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
2190
+ `${label2} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
2191
2191
  );
2192
2192
  }
2193
2193
  const bytes = new Uint8Array(expectedBytes);
@@ -2196,10 +2196,10 @@ function fromHex(value, label, expectedBytes) {
2196
2196
  }
2197
2197
  return bytes;
2198
2198
  }
2199
- function fromHexUnsized(value, label) {
2199
+ function fromHexUnsized(value, label2) {
2200
2200
  const clean = value.trim();
2201
2201
  if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
2202
- throw new Error(`${label} must be an even number of hex characters`);
2202
+ throw new Error(`${label2} must be an even number of hex characters`);
2203
2203
  }
2204
2204
  const bytes = new Uint8Array(clean.length / 2);
2205
2205
  for (let i = 0; i < bytes.length; i += 1) {
@@ -6513,14 +6513,300 @@ async function signWarrant(input) {
6513
6513
  )
6514
6514
  );
6515
6515
  }
6516
- function citedHeads(heads, label) {
6516
+ function citedHeads(heads, label2) {
6517
6517
  const list = heads ?? [];
6518
6518
  if (list.length > MAX_CITED_HEADS) {
6519
6519
  throw new Error(
6520
- `${label} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`
6520
+ `${label2} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`
6521
6521
  );
6522
6522
  }
6523
- return list.map((head, i) => fromHex(head, `${label}[${i}]`, 32));
6523
+ return list.map((head, i) => fromHex(head, `${label2}[${i}]`, 32));
6524
+ }
6525
+
6526
+ // src/warrant/creation-warrant.ts
6527
+ var SIGN_DOMAIN3 = new TextEncoder().encode("calimero.context-creation-warrant.v1");
6528
+ var INIT_DOMAIN = new TextEncoder().encode("calimero.context-creation.init.v1");
6529
+ var MAX_LABEL_BYTES = 256;
6530
+ async function creationInitHash(initArgs) {
6531
+ const bytes = new TextEncoder().encode(JSON.stringify(initArgs));
6532
+ return domainHash(INIT_DOMAIN, [bytes]);
6533
+ }
6534
+ async function creationWarrantPreimage(p) {
6535
+ return domainHash(SIGN_DOMAIN3, [
6536
+ p.group,
6537
+ p.seed,
6538
+ p.authorAccount,
6539
+ p.deviceKey,
6540
+ p.executor,
6541
+ p.applicationId,
6542
+ new Uint8Array([p.serviceName === null ? 0 : 1]),
6543
+ p.serviceName ?? new Uint8Array(0),
6544
+ new Uint8Array([p.name === null ? 0 : 1]),
6545
+ p.name ?? new Uint8Array(0),
6546
+ p.initHash,
6547
+ u64le(p.accountHeads.length),
6548
+ ...p.accountHeads,
6549
+ u64le(p.governanceFloor.length),
6550
+ ...p.governanceFloor,
6551
+ u64le(p.nonce),
6552
+ u64le(p.notAfter)
6553
+ ]);
6554
+ }
6555
+ async function signCreationWarrant(input) {
6556
+ const group = fromHex(input.group, "group", 32);
6557
+ const seed = input.seed === void 0 ? crypto.getRandomValues(new Uint8Array(32)) : fromHex(input.seed, "seed", 32);
6558
+ const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
6559
+ const executor = fromHex(input.executor, "executor", 32);
6560
+ const applicationId = fromHex(input.applicationId, "applicationId", 32);
6561
+ const serviceName = label(input.serviceName, "serviceName");
6562
+ const name = label(input.name, "name");
6563
+ const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6564
+ const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6565
+ const key = await importSigningKey(input.deviceSecret);
6566
+ const deviceKey = await derivePublicKey(input.deviceSecret);
6567
+ const initHash = await creationInitHash(input.initArgs);
6568
+ const preimage = await creationWarrantPreimage({
6569
+ group,
6570
+ seed,
6571
+ authorAccount,
6572
+ deviceKey,
6573
+ executor,
6574
+ applicationId,
6575
+ serviceName,
6576
+ name,
6577
+ initHash,
6578
+ accountHeads,
6579
+ governanceFloor,
6580
+ nonce: input.nonce,
6581
+ notAfter: input.notAfter
6582
+ });
6583
+ const signature = new Uint8Array(
6584
+ await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6585
+ );
6586
+ const warrant = hex(
6587
+ concat(
6588
+ group,
6589
+ seed,
6590
+ authorAccount,
6591
+ deviceKey,
6592
+ executor,
6593
+ applicationId,
6594
+ borshOption(serviceName),
6595
+ borshOption(name),
6596
+ initHash,
6597
+ u32le(accountHeads.length),
6598
+ ...accountHeads,
6599
+ u32le(governanceFloor.length),
6600
+ ...governanceFloor,
6601
+ u64le(input.nonce),
6602
+ u64le(input.notAfter),
6603
+ signature
6604
+ )
6605
+ );
6606
+ return { warrant, seed: hex(seed) };
6607
+ }
6608
+ function parseCreationWarrant(warrant) {
6609
+ const clean = warrant.trim();
6610
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
6611
+ throw new Error("creation warrant must be an even number of hex characters");
6612
+ }
6613
+ const bytes = new Uint8Array(clean.length / 2);
6614
+ for (let i = 0; i < bytes.length; i += 1) {
6615
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
6616
+ }
6617
+ const view = new DataView(bytes.buffer);
6618
+ let o = 0;
6619
+ const take = (n, what) => {
6620
+ if (o + n > bytes.length) {
6621
+ throw new Error(`creation warrant ends inside ${what} (${bytes.length} bytes)`);
6622
+ }
6623
+ const out = bytes.subarray(o, o + n);
6624
+ o += n;
6625
+ return out;
6626
+ };
6627
+ const u32 = (what) => view.getUint32(take(4, what).byteOffset, true);
6628
+ const u64 = (what) => view.getBigUint64(take(8, what).byteOffset, true);
6629
+ const option = (what) => {
6630
+ const tag2 = take(1, what)[0];
6631
+ if (tag2 === 0) return null;
6632
+ if (tag2 !== 1) throw new Error(`${what} has option tag ${tag2}, expected 0 or 1`);
6633
+ const len = u32(what);
6634
+ if (len > MAX_LABEL_BYTES) {
6635
+ throw new Error(`${what} is ${len} bytes, over the ${MAX_LABEL_BYTES} a node accepts`);
6636
+ }
6637
+ return new TextDecoder("utf-8", { fatal: true }).decode(take(len, what));
6638
+ };
6639
+ const heads = (what) => {
6640
+ const count = u32(what);
6641
+ if (count > 64) {
6642
+ throw new Error(`${what} cites ${count} heads, over the 64 a node accepts`);
6643
+ }
6644
+ return Array.from({ length: count }, () => hex(take(32, what)));
6645
+ };
6646
+ const fields = {
6647
+ group: hex(take(32, "group")),
6648
+ seed: hex(take(32, "seed")),
6649
+ authorAccount: hex(take(32, "authorAccount")),
6650
+ deviceKey: hex(take(32, "deviceKey")),
6651
+ executor: hex(take(32, "executor")),
6652
+ applicationId: hex(take(32, "applicationId")),
6653
+ serviceName: option("serviceName"),
6654
+ name: option("name"),
6655
+ initHash: hex(take(32, "initHash")),
6656
+ accountHeads: heads("accountHeads"),
6657
+ governanceFloor: heads("governanceFloor"),
6658
+ nonce: u64("nonce"),
6659
+ notAfter: u64("notAfter"),
6660
+ signature: hex(take(64, "signature"))
6661
+ };
6662
+ if (o !== bytes.length) {
6663
+ throw new Error(
6664
+ `creation warrant is ${bytes.length} bytes but its fields account for ${o}`
6665
+ );
6666
+ }
6667
+ return fields;
6668
+ }
6669
+ function label(value, what) {
6670
+ if (value === void 0) return null;
6671
+ const bytes = new TextEncoder().encode(value);
6672
+ if (bytes.length > MAX_LABEL_BYTES) {
6673
+ throw new Error(
6674
+ `${what} is ${bytes.length} UTF-8 bytes, over the ${MAX_LABEL_BYTES} a node accepts`
6675
+ );
6676
+ }
6677
+ return bytes;
6678
+ }
6679
+ function borshOption(bytes) {
6680
+ if (bytes === null) return new Uint8Array([0]);
6681
+ return concat(new Uint8Array([1]), u32le(bytes.length), bytes);
6682
+ }
6683
+
6684
+ // src/warrant/governance-warrant.ts
6685
+ var SIGN_DOMAIN4 = new TextEncoder().encode("calimero.governance-warrant.v1");
6686
+ var OP_DOMAIN = new TextEncoder().encode("calimero.governance-warrant.op.v1");
6687
+ var KIND_BYTE = { group: 0, root: 1 };
6688
+ async function governanceOpHash(op) {
6689
+ return domainHash(OP_DOMAIN, [new Uint8Array([kindByte(op.kind)]), op.bytes]);
6690
+ }
6691
+ async function governanceWarrantPreimage(p) {
6692
+ return domainHash(SIGN_DOMAIN4, [
6693
+ p.scope,
6694
+ new Uint8Array([kindByte(p.kind)]),
6695
+ p.authorAccount,
6696
+ p.deviceKey,
6697
+ p.executor,
6698
+ p.opHash,
6699
+ u64le(p.accountHeads.length),
6700
+ ...p.accountHeads,
6701
+ u64le(p.governanceFloor.length),
6702
+ ...p.governanceFloor,
6703
+ u64le(p.nonce),
6704
+ u64le(p.notAfter)
6705
+ ]);
6706
+ }
6707
+ async function signGovernanceWarrant(input) {
6708
+ const scope = fromHex(input.scope, "scope", 32);
6709
+ const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
6710
+ const executor = fromHex(input.executor, "executor", 32);
6711
+ const accountHeads = citedHeads(input.accountHeads, "accountHeads");
6712
+ const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
6713
+ const kind = kindByte(input.op.kind);
6714
+ const key = await importSigningKey(input.deviceSecret);
6715
+ const deviceKey = await derivePublicKey(input.deviceSecret);
6716
+ const opHash = await governanceOpHash(input.op);
6717
+ const preimage = await governanceWarrantPreimage({
6718
+ scope,
6719
+ kind: input.op.kind,
6720
+ authorAccount,
6721
+ deviceKey,
6722
+ executor,
6723
+ opHash,
6724
+ accountHeads,
6725
+ governanceFloor,
6726
+ nonce: input.nonce,
6727
+ notAfter: input.notAfter
6728
+ });
6729
+ const signature = new Uint8Array(
6730
+ await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6731
+ );
6732
+ return hex(
6733
+ concat(
6734
+ scope,
6735
+ new Uint8Array([kind]),
6736
+ authorAccount,
6737
+ deviceKey,
6738
+ executor,
6739
+ opHash,
6740
+ u32le(accountHeads.length),
6741
+ ...accountHeads,
6742
+ u32le(governanceFloor.length),
6743
+ ...governanceFloor,
6744
+ u64le(input.nonce),
6745
+ u64le(input.notAfter),
6746
+ signature
6747
+ )
6748
+ );
6749
+ }
6750
+ function parseGovernanceWarrant(warrant) {
6751
+ const clean = warrant.trim();
6752
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
6753
+ throw new Error("governance warrant must be an even number of hex characters");
6754
+ }
6755
+ const bytes = new Uint8Array(clean.length / 2);
6756
+ for (let i = 0; i < bytes.length; i += 1) {
6757
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
6758
+ }
6759
+ const view = new DataView(bytes.buffer);
6760
+ let o = 0;
6761
+ const take = (n, what) => {
6762
+ if (o + n > bytes.length) {
6763
+ throw new Error(`governance warrant ends inside ${what} (${bytes.length} bytes)`);
6764
+ }
6765
+ const out = bytes.subarray(o, o + n);
6766
+ o += n;
6767
+ return out;
6768
+ };
6769
+ const u32 = (what) => view.getUint32(take(4, what).byteOffset, true);
6770
+ const u64 = (what) => view.getBigUint64(take(8, what).byteOffset, true);
6771
+ const heads = (what) => {
6772
+ const count = u32(what);
6773
+ if (count > 64) {
6774
+ throw new Error(`${what} cites ${count} heads, over the 64 a node accepts`);
6775
+ }
6776
+ return Array.from({ length: count }, () => hex(take(32, what)));
6777
+ };
6778
+ const kind = () => {
6779
+ const byte = take(1, "kind")[0];
6780
+ if (byte === 0) return "group";
6781
+ if (byte === 1) return "root";
6782
+ throw new Error(`governance warrant has kind ${byte}, expected 0 (group) or 1 (root)`);
6783
+ };
6784
+ const fields = {
6785
+ scope: hex(take(32, "scope")),
6786
+ kind: kind(),
6787
+ authorAccount: hex(take(32, "authorAccount")),
6788
+ deviceKey: hex(take(32, "deviceKey")),
6789
+ executor: hex(take(32, "executor")),
6790
+ opHash: hex(take(32, "opHash")),
6791
+ accountHeads: heads("accountHeads"),
6792
+ governanceFloor: heads("governanceFloor"),
6793
+ nonce: u64("nonce"),
6794
+ notAfter: u64("notAfter"),
6795
+ signature: hex(take(64, "signature"))
6796
+ };
6797
+ if (o !== bytes.length) {
6798
+ throw new Error(
6799
+ `governance warrant is ${bytes.length} bytes but its fields account for ${o}`
6800
+ );
6801
+ }
6802
+ return fields;
6803
+ }
6804
+ function kindByte(kind) {
6805
+ const byte = KIND_BYTE[kind];
6806
+ if (byte === void 0) {
6807
+ throw new Error(`op kind must be 'group' or 'root', got ${String(kind)}`);
6808
+ }
6809
+ return byte;
6524
6810
  }
6525
6811
 
6526
6812
  // src/relay/relay-client.ts
@@ -6583,6 +6869,156 @@ var RelayClient = class {
6583
6869
  );
6584
6870
  return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };
6585
6871
  }
6872
+ /**
6873
+ * Ask the relay what it can do about creating contexts in `groupId`.
6874
+ *
6875
+ * Pass `author` (an account, hex) to also learn whether that account may
6876
+ * create here — `authorMayCreate` is present only then.
6877
+ */
6878
+ async describeCreation(groupId, opts = {}) {
6879
+ const query = opts.author ? `?author=${encodeURIComponent(opts.author)}` : "";
6880
+ const body = await this.json(
6881
+ "GET",
6882
+ `/admin-api/groups/${encodeURIComponent(groupId)}/context-intents${query}`
6883
+ );
6884
+ return body.data;
6885
+ }
6886
+ /**
6887
+ * Create a context in a group through the relay, as the author.
6888
+ *
6889
+ * Always asks {@link describeCreation} first — with the author, so both
6890
+ * standing checks happen before anything is signed. A relay without standing
6891
+ * in the group, or an author without `CAN_CREATE_CONTEXT`, is refused here as
6892
+ * an {@link IntentRefusedError} *before* a nonce is taken: the nonce source
6893
+ * is monotonic, and a warrant nobody will spend burns one for nothing.
6894
+ *
6895
+ * The creation warrant's nonce is spent in the new context's per-device
6896
+ * ledger — the same one later `execute` calls in that context draw from — so
6897
+ * it comes from the configured {@link NonceSource} like any other warrant.
6898
+ *
6899
+ * Sealing: nothing here is plaintext-specific. The request goes through the
6900
+ * injected `fetch`, so a `createAttestedSealedFetch` seals it exactly as it
6901
+ * seals `execute`. Whether the relay *accepts* it sealed is the node's call:
6902
+ * a proxy-auth relay only admits sealed requests for routes `merod` serves
6903
+ * without a credential, so `/admin-api/groups/:id/context-intents` must be on
6904
+ * that list on the core side or the request comes back
6905
+ * `403 sealed_route_unguarded`.
6906
+ */
6907
+ async createContext(input) {
6908
+ const described = await this.describeCreation(input.groupId, {
6909
+ author: this.config.authorAccount
6910
+ });
6911
+ if (!described.canCreateOnBehalf) {
6912
+ throw new IntentRefusedError(
6913
+ `the relay (${described.executorAccount}) has no standing to act for members of group ${described.groupId}; an admin must admit it as a relay or grant it CAN_AUTHOR_ON_BEHALF (checked before signing \u2014 no nonce was spent)`,
6914
+ false,
6915
+ 403
6916
+ );
6917
+ }
6918
+ if (described.authorMayCreate === false) {
6919
+ throw new IntentRefusedError(
6920
+ `the author (${this.config.authorAccount}) may not create contexts in group ${described.groupId}; it needs CAN_CREATE_CONTEXT or admin (checked before signing \u2014 no nonce was spent)`,
6921
+ false,
6922
+ 403
6923
+ );
6924
+ }
6925
+ const executor = this.checkedExecutor(described.executorAccount);
6926
+ const initArgs = input.initArgs ?? {};
6927
+ const nonce2 = await this.config.nonces.next();
6928
+ const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6929
+ const { warrant } = await signCreationWarrant({
6930
+ group: input.groupId,
6931
+ seed: input.seed,
6932
+ authorAccount: this.config.authorAccount,
6933
+ executor,
6934
+ applicationId: input.applicationId,
6935
+ serviceName: input.serviceName,
6936
+ name: input.name,
6937
+ initArgs,
6938
+ nonce: nonce2,
6939
+ notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6940
+ deviceSecret: this.config.deviceSecret
6941
+ });
6942
+ const body = await this.json(
6943
+ "POST",
6944
+ `/admin-api/groups/${encodeURIComponent(input.groupId)}/context-intents`,
6945
+ { warrant, authorProof: this.config.authorProof, initArgs }
6946
+ );
6947
+ return {
6948
+ contextId: body.data.contextId,
6949
+ groupId: body.data.groupId,
6950
+ memberPublicKey: body.data.memberPublicKey
6951
+ };
6952
+ }
6953
+ /**
6954
+ * Ask the relay whether it may publish governance ops for members of
6955
+ * `groupId`, and which account a warrant must name.
6956
+ */
6957
+ async describeGovernance(groupId) {
6958
+ const body = await this.json(
6959
+ "GET",
6960
+ `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`
6961
+ );
6962
+ return body.data;
6963
+ }
6964
+ /**
6965
+ * Publish one governance op through the relay, as the author.
6966
+ *
6967
+ * The warrant commits to the op's exact bytes and is scoped to `groupId`, so
6968
+ * the relay can neither change what the op does nor spend it elsewhere. Every
6969
+ * peer applies the op as the author, so the author's own rights decide
6970
+ * (`MANAGE_MEMBERS` to add a member, `CAN_CREATE_SUBGROUP` to create a
6971
+ * subgroup, and so on); a lack of them comes back as an
6972
+ * {@link IntentRefusedError} from the relay.
6973
+ *
6974
+ * Always asks {@link describeGovernance} first and refuses *before* taking a
6975
+ * nonce when the relay has no standing, for the reason `createContext` does.
6976
+ * The nonce comes from the configured {@link NonceSource}; it is spent in a
6977
+ * per-group ledger, and a monotonic source is correct for it as for every
6978
+ * other warrant.
6979
+ */
6980
+ async govern(input) {
6981
+ const described = await this.describeGovernance(input.groupId);
6982
+ if (!described.canActOnBehalf) {
6983
+ throw new IntentRefusedError(
6984
+ `the relay (${described.executorAccount}) has no standing to act for members of group ${described.groupId}; an admin must admit it as a relay or grant it CAN_AUTHOR_ON_BEHALF (checked before signing, no nonce was spent)`,
6985
+ false,
6986
+ 403
6987
+ );
6988
+ }
6989
+ const executor = this.checkedExecutor(described.executorAccount);
6990
+ const nonce2 = await this.config.nonces.next();
6991
+ const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6992
+ const warrant = await signGovernanceWarrant({
6993
+ scope: input.groupId,
6994
+ op: input.op,
6995
+ authorAccount: this.config.authorAccount,
6996
+ executor,
6997
+ nonce: nonce2,
6998
+ notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
6999
+ deviceSecret: this.config.deviceSecret
7000
+ });
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 };
7007
+ }
7008
+ /**
7009
+ * The executor a warrant must name: the one the relay answered with, which a
7010
+ * configured account must agree with. Remembered for later calls.
7011
+ */
7012
+ checkedExecutor(answered) {
7013
+ const configured = this.config.executorAccount;
7014
+ if (configured && configured.toLowerCase() !== answered.toLowerCase()) {
7015
+ throw new Error(
7016
+ `configured executorAccount ${configured} is not the relay's account ${answered}; a warrant naming it would be unspendable`
7017
+ );
7018
+ }
7019
+ this.executorAccount = answered;
7020
+ return answered;
7021
+ }
6586
7022
  async json(method, path, body) {
6587
7023
  const headers = { Accept: "application/json" };
6588
7024
  if (body !== void 0) headers["Content-Type"] = "application/json";
@@ -7282,8 +7718,8 @@ var REGISTERS = ["mrtd", "rtmr0", "rtmr1", "rtmr2", "rtmr3"];
7282
7718
  function createQuoteVerifier(options) {
7283
7719
  const allowedMrtd = measurements(options.allowedMrtd ?? [], "allowedMrtd");
7284
7720
  const allowedImages = (options.allowedMeasurements ?? []).map((image, index) => {
7285
- const label = `allowedMeasurements[${index}]`;
7286
- return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${label}.${register}`)[0]).join();
7721
+ const label2 = `allowedMeasurements[${index}]`;
7722
+ return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${label2}.${register}`)[0]).join();
7287
7723
  });
7288
7724
  const allowedRtmr = [
7289
7725
  measurements(options.allowedRtmr0 ?? [], "allowedRtmr0"),
@@ -7352,11 +7788,11 @@ function createQuoteVerifier(options) {
7352
7788
  };
7353
7789
  return Object.assign(verifier, { includeCollateral: true });
7354
7790
  }
7355
- function measurements(values, label) {
7791
+ function measurements(values, label2) {
7356
7792
  return values.map((value) => {
7357
7793
  const normalized = value.trim().toLowerCase();
7358
7794
  if (!MEASUREMENT_HEX.test(normalized)) {
7359
- throw new Error(`${label} holds ${JSON.stringify(value)}, which is not a 48-byte hex measurement`);
7795
+ throw new Error(`${label2} holds ${JSON.stringify(value)}, which is not a 48-byte hex measurement`);
7360
7796
  }
7361
7797
  return normalized;
7362
7798
  });
@@ -7469,8 +7905,8 @@ var SIGNATURE_HASHES = {
7469
7905
  };
7470
7906
  function read(bytes, offset, limit) {
7471
7907
  if (offset + 2 > limit) throw new Error("it is truncated");
7472
- const tag = bytes[offset];
7473
- if ((tag & 31) === 31) throw new Error("it uses a tag this parser does not read");
7908
+ const tag2 = bytes[offset];
7909
+ if ((tag2 & 31) === 31) throw new Error("it uses a tag this parser does not read");
7474
7910
  let length = bytes[offset + 1];
7475
7911
  let start = offset + 2;
7476
7912
  if (length & 128) {
@@ -7482,7 +7918,7 @@ function read(bytes, offset, limit) {
7482
7918
  }
7483
7919
  const end = start + length;
7484
7920
  if (end > limit) throw new Error("it is truncated");
7485
- return { tag, bytes, offset, start, end };
7921
+ return { tag: tag2, bytes, offset, start, end };
7486
7922
  }
7487
7923
  function parseDer(bytes) {
7488
7924
  const element = read(bytes, 0, bytes.length);
@@ -7498,8 +7934,8 @@ function children(element) {
7498
7934
  }
7499
7935
  return out;
7500
7936
  }
7501
- function expectTag(element, tag, what) {
7502
- if (!element || element.tag !== tag) throw new Error(`${what} is not where it should be`);
7937
+ function expectTag(element, tag2, what) {
7938
+ if (!element || element.tag !== tag2) throw new Error(`${what} is not where it should be`);
7503
7939
  return element;
7504
7940
  }
7505
7941
  function contents(element) {
@@ -7961,11 +8397,103 @@ function splitVersion2(version) {
7961
8397
  return [[Number(match[1]), Number(match[2]), Number(match[3])], match[4]];
7962
8398
  }
7963
8399
 
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
+
7964
8492
  // src/namespace-op/namespace-op.ts
7965
- var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 12;
8493
+ var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 15;
7966
8494
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
7967
8495
  var NAMESPACE_OP_ROOT = 0;
7968
- var ROOT_OP = {
8496
+ var ROOT_OP2 = {
7969
8497
  GroupCreated: 0,
7970
8498
  GroupReparented: 1,
7971
8499
  GroupDeleted: 2,
@@ -7978,18 +8506,18 @@ var ROOT_OP = {
7978
8506
  NamespaceCreatedV2: 9,
7979
8507
  MemberJoinedViaTeeAttestation: 10
7980
8508
  };
7981
- function bytes32(value, label) {
8509
+ function bytes32(value, label2) {
7982
8510
  if (value.length !== 32) {
7983
- throw new Error(`${label} must be 32 bytes, got ${value.length}`);
8511
+ throw new Error(`${label2} must be 32 bytes, got ${value.length}`);
7984
8512
  }
7985
8513
  return new Uint8Array(value);
7986
8514
  }
7987
- function optionalBytes32(value, label) {
8515
+ function optionalBytes32(value, label2) {
7988
8516
  if (value === null || value === void 0) {
7989
8517
  return new Uint8Array([0]);
7990
8518
  }
7991
8519
  if (value.length !== 32) {
7992
- throw new Error(`${label} must be 32 bytes, got ${value.length}`);
8520
+ throw new Error(`${label2} must be 32 bytes, got ${value.length}`);
7993
8521
  }
7994
8522
  return concat(new Uint8Array([1]), new Uint8Array(value));
7995
8523
  }
@@ -8040,13 +8568,13 @@ async function signMemberJoinOp(input) {
8040
8568
  const expires = BigInt(input.invitation.invitation.expiration_timestamp ?? 0) !== 0n;
8041
8569
  const joinedAt = input.joinedAt ?? BigInt(Math.floor(Date.now() / 1e3));
8042
8570
  const rootOp = expires ? concat(
8043
- new Uint8Array([ROOT_OP.MemberJoinedAt]),
8571
+ new Uint8Array([ROOT_OP2.MemberJoinedAt]),
8044
8572
  fromHex(input.member, "member", 32),
8045
8573
  encodeSignedInvitation(input.invitation),
8046
8574
  u64le(joinedAt),
8047
8575
  credential
8048
8576
  ) : concat(
8049
- new Uint8Array([ROOT_OP.MemberJoined]),
8577
+ new Uint8Array([ROOT_OP2.MemberJoined]),
8050
8578
  fromHex(input.member, "member", 32),
8051
8579
  encodeSignedInvitation(input.invitation),
8052
8580
  credential
@@ -8071,7 +8599,7 @@ async function signMemberJoinOp(input) {
8071
8599
  }
8072
8600
 
8073
8601
  // src/login/login.ts
8074
- var SIGN_DOMAIN3 = new TextEncoder().encode("calimero.auth.login.v1");
8602
+ var SIGN_DOMAIN5 = new TextEncoder().encode("calimero.auth.login.v1");
8075
8603
  var AUDIENCE_TAG = {
8076
8604
  webOrigin: 0,
8077
8605
  codeSigningId: 1,
@@ -8095,12 +8623,12 @@ function audienceSigningBytes(audience) {
8095
8623
  );
8096
8624
  }
8097
8625
  function audienceWire(audience) {
8098
- const tag = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);
8626
+ const tag2 = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);
8099
8627
  if (audience.kind === "cli") {
8100
- return tag;
8628
+ return tag2;
8101
8629
  }
8102
8630
  const body = audienceBody(audience);
8103
- return concat(tag, u32le(body.length), body);
8631
+ return concat(tag2, u32le(body.length), body);
8104
8632
  }
8105
8633
  async function signLoginStatement(input) {
8106
8634
  const node = fromHex(input.node, "node", 32);
@@ -8110,7 +8638,7 @@ async function signLoginStatement(input) {
8110
8638
  const deviceKey = await derivePublicKey(input.deviceSecret);
8111
8639
  const issuedAt = u64le(input.issuedAt);
8112
8640
  const expiresAt = u64le(input.expiresAt);
8113
- const preimage = await domainHash(SIGN_DOMAIN3, [
8641
+ const preimage = await domainHash(SIGN_DOMAIN5, [
8114
8642
  node,
8115
8643
  audienceSigningBytes(input.audience),
8116
8644
  challenge,
@@ -8345,6 +8873,7 @@ export {
8345
8873
  createSignedReleaseVerifier,
8346
8874
  createTimeoutSignal,
8347
8875
  createUniversalHttpClient,
8876
+ creationInitHash,
8348
8877
  deviceCertPayload,
8349
8878
  discoverLocalNodes,
8350
8879
  encodeSignedInvitation,
@@ -8353,6 +8882,10 @@ export {
8353
8882
  fetchNodeReleaseVersion,
8354
8883
  generateAccountRoot,
8355
8884
  generateSessionKey,
8885
+ governanceOpHash,
8886
+ groupCreatedOp,
8887
+ groupDeletedOp,
8888
+ groupReparentedOp,
8356
8889
  hasCap,
8357
8890
  hexEncodeUtf8,
8358
8891
  intentHash,
@@ -8360,10 +8893,16 @@ export {
8360
8893
  jsonCodec,
8361
8894
  localNodeUrl,
8362
8895
  login,
8896
+ memberAddedOp,
8897
+ memberLeftOp,
8898
+ memberRemovedOp,
8899
+ memberRoleSetOp,
8363
8900
  mintDeviceId,
8364
8901
  nodeEndpoint,
8365
8902
  nodeReleaseVersionFromImage,
8366
8903
  parseAuthCallback,
8904
+ parseCreationWarrant,
8905
+ parseGovernanceWarrant,
8367
8906
  probeNodeHealth,
8368
8907
  redeemInvitation,
8369
8908
  requestBodyHash,
@@ -8371,7 +8910,9 @@ export {
8371
8910
  shouldRetain,
8372
8911
  signAccountLink,
8373
8912
  signAccountLogin,
8913
+ signCreationWarrant,
8374
8914
  signDeviceCert,
8915
+ signGovernanceWarrant,
8375
8916
  signLoginStatement,
8376
8917
  signMemberJoinOp,
8377
8918
  signRequest,