@majikah/majik-message 0.2.15 → 0.2.17

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 { EnvelopeInfo, ExpectedSigner, MajikSignature, SealInfo, SealVerificationResult, type MajikSignatureJSON, type MajikSignerPublicKeys, type VerificationResult } from "@majikah/majik-signature";
11
+ import { EnvelopeInfo, ExpectedSigner, MajikSignature, SealInfo, SealVerificationResult, SignatoriesFilter, SignatoriesResult, SignatoryInfo, 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;
@@ -798,6 +798,106 @@ export declare class MajikMessage {
798
798
  handler: string;
799
799
  mimeType: string;
800
800
  }>;
801
+ /**
802
+ * Build an ExpectedSigner entry from a MajikKey.
803
+ * Use this to construct the expectedSigners array passed to signFile().
804
+ * The key does not need to be unlocked.
805
+ *
806
+ * @example
807
+ * const { blob } = await majik.signFile(file, {
808
+ * expectedSigners: [
809
+ * MajikSignatureClient.expectedSignerFromKey(aliceKey),
810
+ * MajikSignatureClient.expectedSignerFromKey(bobKey),
811
+ * ],
812
+ * });
813
+ */
814
+ static expectedSignerFromKey(key: MajikKey): ExpectedSigner;
815
+ /**
816
+ * Get the allowlist from a file without verifying any signatures.
817
+ * Returns null for open-signing files or unsigned files.
818
+ *
819
+ * @example
820
+ * const list = await majik.getAllowlist(file);
821
+ * if (list) console.log("Restricted to", list.map(e => e.signerId));
822
+ */
823
+ getAllowlist(file: Blob, options?: {
824
+ mimeType?: string;
825
+ }): Promise<ExpectedSigner[] | null>;
826
+ /**
827
+ * Check whether a MajikKey is permitted to add a signature to this file.
828
+ * Accounts for seal status and allowlist membership (full three-field check).
829
+ *
830
+ * @example
831
+ * const { permitted, reason } = await majik.canSign(file, key);
832
+ * if (!permitted) showError(reason);
833
+ */
834
+ canSign(file: Blob, key: MajikKey, options?: {
835
+ mimeType?: string;
836
+ }): Promise<{
837
+ permitted: boolean;
838
+ reason?: string;
839
+ }>;
840
+ /**
841
+ * Returns true when the file has a restricted multi-sig envelope
842
+ * (allowlist with more than one expected signer).
843
+ * Returns false for unsigned, open-signing, or single-signer files.
844
+ */
845
+ isMultiSig(file: Blob, options?: {
846
+ mimeType?: string;
847
+ }): Promise<boolean>;
848
+ /**
849
+ * Core signatories method — returns all, signed, and pending arrays.
850
+ *
851
+ * When an allowlist is present:
852
+ * - all = every expected signer with their signing status
853
+ * - signed = those who have already signed
854
+ * - pending = those who are expected but have not yet signed
855
+ *
856
+ * When no allowlist is present:
857
+ * - all / signed = actual signers (everyone has signed by definition)
858
+ * - pending = always empty
859
+ *
860
+ * Returns null if the file has no envelope.
861
+ *
862
+ * @example
863
+ * const result = await majik.getSignatories(file);
864
+ * console.log(`${result?.signed.length} of ${result?.all.length} signed`);
865
+ */
866
+ getSignatories(file: Blob, options?: {
867
+ mimeType?: string;
868
+ }, filter?: SignatoriesFilter): Promise<SignatoriesResult | null>;
869
+ /**
870
+ * Returns only signatories who have already signed.
871
+ * Alias for getSignatories(file, options, "signed").
872
+ */
873
+ getSignedSignatories(file: Blob, options?: {
874
+ mimeType?: string;
875
+ }): Promise<SignatoriesResult | null>;
876
+ /**
877
+ * Returns only signatories who are expected but have not yet signed.
878
+ * Alias for getSignatories(file, options, "pending").
879
+ */
880
+ getPendingSignatories(file: Blob, options?: {
881
+ mimeType?: string;
882
+ }): Promise<SignatoriesResult | null>;
883
+ /**
884
+ * Returns all signatories with full status information.
885
+ * Alias for getSignatories(file, options, "all").
886
+ */
887
+ getAllSignatories(file: Blob, options?: {
888
+ mimeType?: string;
889
+ }): Promise<SignatoriesResult | null>;
890
+ /**
891
+ * Returns the issuer — the signer who established the allowlist and
892
+ * controls sealing. Returns null for open-signing or unsigned files.
893
+ *
894
+ * @example
895
+ * const issuer = await majik.getIssuer(file);
896
+ * if (issuer) console.log("Issued by", majik.resolveSignerLabel(issuer.signerId));
897
+ */
898
+ getIssuer(file: Blob, options?: {
899
+ mimeType?: string;
900
+ }): Promise<SignatoryInfo | null>;
801
901
  /**
802
902
  * Extract metadata from a file's embedded signature without verifying it.
803
903
  *
@@ -1759,6 +1759,154 @@ export class MajikMessage {
1759
1759
  // that makes the caller's intent explicit at the call-site.
1760
1760
  return this.signFile(file, options);
1761
1761
  }
1762
+ // ── Multi-sig & Allowlist ─────────────────────────────────────────────────
1763
+ /**
1764
+ * Build an ExpectedSigner entry from a MajikKey.
1765
+ * Use this to construct the expectedSigners array passed to signFile().
1766
+ * The key does not need to be unlocked.
1767
+ *
1768
+ * @example
1769
+ * const { blob } = await majik.signFile(file, {
1770
+ * expectedSigners: [
1771
+ * MajikSignatureClient.expectedSignerFromKey(aliceKey),
1772
+ * MajikSignatureClient.expectedSignerFromKey(bobKey),
1773
+ * ],
1774
+ * });
1775
+ */
1776
+ static expectedSignerFromKey(key) {
1777
+ return MajikSignature.expectedSignerFromKey(key);
1778
+ }
1779
+ /**
1780
+ * Get the allowlist from a file without verifying any signatures.
1781
+ * Returns null for open-signing files or unsigned files.
1782
+ *
1783
+ * @example
1784
+ * const list = await majik.getAllowlist(file);
1785
+ * if (list) console.log("Restricted to", list.map(e => e.signerId));
1786
+ */
1787
+ async getAllowlist(file, options) {
1788
+ try {
1789
+ return MajikSignature.getAllowlist(file, options);
1790
+ }
1791
+ catch (err) {
1792
+ this.emit("error", err, { context: "getAllowlist" });
1793
+ throw err;
1794
+ }
1795
+ }
1796
+ /**
1797
+ * Check whether a MajikKey is permitted to add a signature to this file.
1798
+ * Accounts for seal status and allowlist membership (full three-field check).
1799
+ *
1800
+ * @example
1801
+ * const { permitted, reason } = await majik.canSign(file, key);
1802
+ * if (!permitted) showError(reason);
1803
+ */
1804
+ async canSign(file, key, options) {
1805
+ try {
1806
+ return MajikSignature.canSign(file, key, options);
1807
+ }
1808
+ catch (err) {
1809
+ this.emit("error", err, { context: "canSign" });
1810
+ throw err;
1811
+ }
1812
+ }
1813
+ /**
1814
+ * Returns true when the file has a restricted multi-sig envelope
1815
+ * (allowlist with more than one expected signer).
1816
+ * Returns false for unsigned, open-signing, or single-signer files.
1817
+ */
1818
+ async isMultiSig(file, options) {
1819
+ try {
1820
+ return MajikSignature.isMultiSig(file, options);
1821
+ }
1822
+ catch (err) {
1823
+ this.emit("error", err, { context: "isMultiSig" });
1824
+ throw err;
1825
+ }
1826
+ }
1827
+ /**
1828
+ * Core signatories method — returns all, signed, and pending arrays.
1829
+ *
1830
+ * When an allowlist is present:
1831
+ * - all = every expected signer with their signing status
1832
+ * - signed = those who have already signed
1833
+ * - pending = those who are expected but have not yet signed
1834
+ *
1835
+ * When no allowlist is present:
1836
+ * - all / signed = actual signers (everyone has signed by definition)
1837
+ * - pending = always empty
1838
+ *
1839
+ * Returns null if the file has no envelope.
1840
+ *
1841
+ * @example
1842
+ * const result = await majik.getSignatories(file);
1843
+ * console.log(`${result?.signed.length} of ${result?.all.length} signed`);
1844
+ */
1845
+ async getSignatories(file, options, filter) {
1846
+ try {
1847
+ return MajikSignature.getSignatories(file, options, filter);
1848
+ }
1849
+ catch (err) {
1850
+ this.emit("error", err, { context: "getSignatories" });
1851
+ throw err;
1852
+ }
1853
+ }
1854
+ /**
1855
+ * Returns only signatories who have already signed.
1856
+ * Alias for getSignatories(file, options, "signed").
1857
+ */
1858
+ async getSignedSignatories(file, options) {
1859
+ try {
1860
+ return MajikSignature.getSignedSignatories(file, options);
1861
+ }
1862
+ catch (err) {
1863
+ this.emit("error", err, { context: "getSignedSignatories" });
1864
+ throw err;
1865
+ }
1866
+ }
1867
+ /**
1868
+ * Returns only signatories who are expected but have not yet signed.
1869
+ * Alias for getSignatories(file, options, "pending").
1870
+ */
1871
+ async getPendingSignatories(file, options) {
1872
+ try {
1873
+ return MajikSignature.getPendingSignatories(file, options);
1874
+ }
1875
+ catch (err) {
1876
+ this.emit("error", err, { context: "getPendingSignatories" });
1877
+ throw err;
1878
+ }
1879
+ }
1880
+ /**
1881
+ * Returns all signatories with full status information.
1882
+ * Alias for getSignatories(file, options, "all").
1883
+ */
1884
+ async getAllSignatories(file, options) {
1885
+ try {
1886
+ return MajikSignature.getAllSignatories(file, options);
1887
+ }
1888
+ catch (err) {
1889
+ this.emit("error", err, { context: "getAllSignatories" });
1890
+ throw err;
1891
+ }
1892
+ }
1893
+ /**
1894
+ * Returns the issuer — the signer who established the allowlist and
1895
+ * controls sealing. Returns null for open-signing or unsigned files.
1896
+ *
1897
+ * @example
1898
+ * const issuer = await majik.getIssuer(file);
1899
+ * if (issuer) console.log("Issued by", majik.resolveSignerLabel(issuer.signerId));
1900
+ */
1901
+ async getIssuer(file, options) {
1902
+ try {
1903
+ return MajikSignature.getIssuer(file, options);
1904
+ }
1905
+ catch (err) {
1906
+ this.emit("error", err, { context: "getIssuer" });
1907
+ throw err;
1908
+ }
1909
+ }
1762
1910
  /**
1763
1911
  * Extract metadata from a file's embedded signature without verifying it.
1764
1912
  *
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.15",
5
+ "version": "0.2.17",
6
6
  "license": "Apache-2.0",
7
7
  "author": "Zelijah",
8
8
  "main": "./dist/index.js",
@@ -81,9 +81,9 @@
81
81
  "dependencies": {
82
82
  "@bokuweb/zstd-wasm": "^0.0.27",
83
83
  "@majikah/majik-envelope": "^0.0.1",
84
- "@majikah/majik-file": "^0.0.21",
84
+ "@majikah/majik-file": "^0.0.22",
85
85
  "@majikah/majik-key": "^0.2.3",
86
- "@majikah/majik-signature": "^0.0.14",
86
+ "@majikah/majik-signature": "^0.0.15",
87
87
  "@noble/hashes": "^2.0.1",
88
88
  "@noble/post-quantum": "^0.5.4",
89
89
  "@scure/bip39": "^1.6.0",