@majikah/majik-message 0.2.13 → 0.2.15

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.
@@ -8,7 +8,7 @@ import { MajikMessageChat } from "./core/database/chat/majik-message-chat";
8
8
  import { MajikMessageIdentity } from "./core/database/system/identity";
9
9
  import { MajikKey } from "@majikah/majik-key";
10
10
  import { MajikFile, MajikFileJSON } from "@majikah/majik-file";
11
- import { MajikSignature, type MajikSignatureJSON, type MajikSignerPublicKeys, type VerificationResult } from "@majikah/majik-signature";
11
+ import { EnvelopeInfo, ExpectedSigner, MajikSignature, SealInfo, SealVerificationResult, type MajikSignatureJSON, type MajikSignerPublicKeys, type VerificationResult } from "@majikah/majik-signature";
12
12
  type MajikMessageEvents = "message" | "envelope" | "untrusted" | "error" | "new-account" | "new-contact" | "removed-account" | "removed-contact" | "active-account-change";
13
13
  interface MajikMessageStatic<T extends MajikMessage> {
14
14
  new (config: MajikMessageConfig, id?: string): T;
@@ -595,6 +595,7 @@ export declare class MajikMessage {
595
595
  timestamp?: string;
596
596
  mimeType?: string;
597
597
  accountId?: string;
598
+ expectedSigners?: ExpectedSigner[];
598
599
  }): Promise<{
599
600
  blob: Blob;
600
601
  signature: MajikSignature;
@@ -818,6 +819,72 @@ export declare class MajikMessage {
818
819
  getFileSignatureInfo(file: Blob, options?: {
819
820
  mimeType?: string;
820
821
  }): Promise<MajikSignature[]>;
822
+ /**
823
+ * Return a complete summary of the envelope state in one file read.
824
+ * Covers: isMultiSig, isSealed, issuer, all signatories, allowlist, seal info.
825
+ * Useful for rendering a signing status UI without multiple separate calls.
826
+ *
827
+ * Returns null if the file has no envelope.
828
+ *
829
+ * @example
830
+ * const info = await majik.getEnvelopeInfo(file);
831
+ * if (info?.isSealed) console.log("Sealed by", info.sealInfo?.sealedBy);
832
+ * console.log(`${info?.signatories?.signed.length} of ${info?.signatories?.all.length} signed`);
833
+ */
834
+ getEnvelopeInfo(file: Blob, options?: {
835
+ mimeType?: string;
836
+ }): Promise<EnvelopeInfo | null>;
837
+ /**
838
+ * Seal a restricted multi-sig file, preventing any further signatures.
839
+ *
840
+ * Only the issuer (the signer who established the allowlist) may seal.
841
+ * Resolves the signing key from the keystore — the account must be loaded
842
+ * but does NOT need to be unlocked (sealing does not use private keys).
843
+ *
844
+ * @example
845
+ * const { blob, sealInfo } = await majik.seal(signedFile);
846
+ * console.log("Sealed at", sealInfo.sealTimestamp);
847
+ */
848
+ seal(file: Blob, options?: {
849
+ mimeType?: string;
850
+ timestamp?: string;
851
+ accountId?: string;
852
+ }): Promise<{
853
+ blob: Blob;
854
+ sealInfo: SealInfo;
855
+ handler: string;
856
+ mimeType: string;
857
+ }>;
858
+ /**
859
+ * Verify the seal hash against the current signatories and seal timestamp.
860
+ * Returns invalid if the envelope is not sealed.
861
+ * Does NOT verify individual cryptographic signatures — call verifyFile() for that.
862
+ *
863
+ * @example
864
+ * const result = await majik.verifySeal(file);
865
+ * if (result.valid) console.log("Sealed by", result.sealedBy, "at", result.sealTimestamp);
866
+ */
867
+ verifySeal(file: Blob, options?: {
868
+ mimeType?: string;
869
+ }): Promise<SealVerificationResult>;
870
+ /**
871
+ * Get seal metadata without verifying.
872
+ * Returns null if the file is not sealed or has no envelope.
873
+ *
874
+ * @example
875
+ * const info = await majik.getSealInfo(file);
876
+ * if (info) console.log("Sealed by", majik.resolveSignerLabel(info.sealedBy));
877
+ */
878
+ getSealInfo(file: Blob, options?: {
879
+ mimeType?: string;
880
+ }): Promise<SealInfo | null>;
881
+ /**
882
+ * Returns true if the file has a sealed envelope (structural check, no crypto).
883
+ * Use verifySeal() to confirm the seal hash is intact.
884
+ */
885
+ isSealed(file: Blob, options?: {
886
+ mimeType?: string;
887
+ }): Promise<boolean>;
821
888
  /**
822
889
  * Resolve MajikSignerPublicKeys from whichever signer hint was provided.
823
890
  * Returns null if no hint was given (caller should fall back to self-reported keys).
@@ -1416,6 +1416,7 @@ export class MajikMessage {
1416
1416
  contentType: options?.contentType,
1417
1417
  timestamp: options?.timestamp,
1418
1418
  mimeType: options?.mimeType,
1419
+ expectedSigners: options?.expectedSigners,
1419
1420
  });
1420
1421
  }
1421
1422
  catch (err) {
@@ -1785,6 +1786,105 @@ export class MajikMessage {
1785
1786
  throw err;
1786
1787
  }
1787
1788
  }
1789
+ /**
1790
+ * Return a complete summary of the envelope state in one file read.
1791
+ * Covers: isMultiSig, isSealed, issuer, all signatories, allowlist, seal info.
1792
+ * Useful for rendering a signing status UI without multiple separate calls.
1793
+ *
1794
+ * Returns null if the file has no envelope.
1795
+ *
1796
+ * @example
1797
+ * const info = await majik.getEnvelopeInfo(file);
1798
+ * if (info?.isSealed) console.log("Sealed by", info.sealInfo?.sealedBy);
1799
+ * console.log(`${info?.signatories?.signed.length} of ${info?.signatories?.all.length} signed`);
1800
+ */
1801
+ async getEnvelopeInfo(file, options) {
1802
+ try {
1803
+ return MajikSignature.getEnvelopeInfo(file, options);
1804
+ }
1805
+ catch (err) {
1806
+ this.emit("error", err, { context: "getEnvelopeInfo" });
1807
+ throw err;
1808
+ }
1809
+ }
1810
+ // ── Seal ──────────────────────────────────────────────────────────────────
1811
+ /**
1812
+ * Seal a restricted multi-sig file, preventing any further signatures.
1813
+ *
1814
+ * Only the issuer (the signer who established the allowlist) may seal.
1815
+ * Resolves the signing key from the keystore — the account must be loaded
1816
+ * but does NOT need to be unlocked (sealing does not use private keys).
1817
+ *
1818
+ * @example
1819
+ * const { blob, sealInfo } = await majik.seal(signedFile);
1820
+ * console.log("Sealed at", sealInfo.sealTimestamp);
1821
+ */
1822
+ async seal(file, options) {
1823
+ const id = options?.accountId ?? this.getActiveAccount()?.id;
1824
+ if (!id)
1825
+ throw new Error("No active account — call setActiveAccount() first");
1826
+ try {
1827
+ const key = MajikKeyStore.get(id);
1828
+ if (!key)
1829
+ throw new Error(`Account not found in keystore: "${id}"`);
1830
+ return MajikSignature.seal(file, key, {
1831
+ mimeType: options?.mimeType,
1832
+ timestamp: options?.timestamp,
1833
+ });
1834
+ }
1835
+ catch (err) {
1836
+ this.emit("error", err, { context: "seal" });
1837
+ throw err;
1838
+ }
1839
+ }
1840
+ /**
1841
+ * Verify the seal hash against the current signatories and seal timestamp.
1842
+ * Returns invalid if the envelope is not sealed.
1843
+ * Does NOT verify individual cryptographic signatures — call verifyFile() for that.
1844
+ *
1845
+ * @example
1846
+ * const result = await majik.verifySeal(file);
1847
+ * if (result.valid) console.log("Sealed by", result.sealedBy, "at", result.sealTimestamp);
1848
+ */
1849
+ async verifySeal(file, options) {
1850
+ try {
1851
+ return MajikSignature.verifySeal(file, options);
1852
+ }
1853
+ catch (err) {
1854
+ this.emit("error", err, { context: "verifySeal" });
1855
+ throw err;
1856
+ }
1857
+ }
1858
+ /**
1859
+ * Get seal metadata without verifying.
1860
+ * Returns null if the file is not sealed or has no envelope.
1861
+ *
1862
+ * @example
1863
+ * const info = await majik.getSealInfo(file);
1864
+ * if (info) console.log("Sealed by", majik.resolveSignerLabel(info.sealedBy));
1865
+ */
1866
+ async getSealInfo(file, options) {
1867
+ try {
1868
+ return MajikSignature.getSealInfo(file, options);
1869
+ }
1870
+ catch (err) {
1871
+ this.emit("error", err, { context: "getSealInfo" });
1872
+ throw err;
1873
+ }
1874
+ }
1875
+ /**
1876
+ * Returns true if the file has a sealed envelope (structural check, no crypto).
1877
+ * Use verifySeal() to confirm the seal hash is intact.
1878
+ */
1879
+ async isSealed(file, options) {
1880
+ try {
1881
+ return MajikSignature.isSealed(file, options);
1882
+ }
1883
+ catch (err) {
1884
+ this.emit("error", err, { context: "isSealed" });
1885
+ throw err;
1886
+ }
1887
+ }
1788
1888
  // ── Private: Signer resolution ────────────────────────────────────────────
1789
1889
  /**
1790
1890
  * Resolve MajikSignerPublicKeys from whichever signer hint was provided.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@majikah/majik-message",
3
3
  "type": "module",
4
4
  "description": "Post-quantum end-to-end encryption with ML-KEM-768. Seed phrase–based accounts. Auto-expiring messages. Offline-ready. Exportable encrypted messages. Tamper-proof threads with blockchain-like integrity. Quantum-resistant messaging.",
5
- "version": "0.2.13",
5
+ "version": "0.2.15",
6
6
  "license": "Apache-2.0",
7
7
  "author": "Zelijah",
8
8
  "main": "./dist/index.js",