@noy-db/hub 0.1.0-pre.3 → 0.1.0-pre.5
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/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +3 -3
- package/dist/blobs/index.d.ts +3 -3
- package/dist/blobs/index.js +2 -2
- package/dist/bundle/index.cjs +26 -3
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +3 -3
- package/dist/bundle/index.d.ts +3 -3
- package/dist/bundle/index.js +3 -1
- package/dist/{chunk-M2F2JAWB.js → chunk-6NPQTBZN.js} +103 -8
- package/dist/chunk-6NPQTBZN.js.map +1 -0
- package/dist/{chunk-UQFSPSWG.js → chunk-E4OOAPBZ.js} +2 -2
- package/dist/chunk-EMIGCR7X.js +39 -0
- package/dist/chunk-EMIGCR7X.js.map +1 -0
- package/dist/{chunk-EXQRC2L4.js → chunk-H3DV46AQ.js} +2 -2
- package/dist/{chunk-XHFOENR2.js → chunk-LMKOSLJY.js} +2 -2
- package/dist/{chunk-GJILMRPO.js → chunk-LRN3PNI6.js} +42 -4
- package/dist/chunk-LRN3PNI6.js.map +1 -0
- package/dist/{chunk-4OWFYIDQ.js → chunk-MIRZMUSQ.js} +3 -3
- package/dist/{chunk-ZRG4V3F5.js → chunk-NXUVITPB.js} +1 -1
- package/dist/chunk-NXUVITPB.js.map +1 -0
- package/dist/{chunk-5AATM2M2.js → chunk-QUDXYI4W.js} +2 -2
- package/dist/{chunk-ZLMV3TUA.js → chunk-QV4WLLKB.js} +3 -3
- package/dist/{chunk-E445ICYI.js → chunk-UFL4DUEV.js} +5 -3
- package/dist/chunk-UFL4DUEV.js.map +1 -0
- package/dist/chunk-UQQ2XFXI.js +155 -0
- package/dist/chunk-UQQ2XFXI.js.map +1 -0
- package/dist/consent/index.d.cts +3 -3
- package/dist/consent/index.d.ts +3 -3
- package/dist/{dev-unlock-KrKkcqD3.d.ts → dev-unlock-BgFqShBi.d.ts} +1 -1
- package/dist/{dev-unlock-CeXic1xC.d.cts → dev-unlock-qVMxG2Je.d.cts} +1 -1
- package/dist/{hash-ChfJjRjQ.d.ts → hash-BhoL7iUE.d.ts} +1 -1
- package/dist/{hash-9KO1BGxh.d.cts → hash-Bpvl2eSe.d.cts} +1 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +4 -4
- package/dist/history/index.d.ts +4 -4
- package/dist/history/index.js +2 -2
- package/dist/i18n/index.cjs +3 -1
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +3 -3
- package/dist/i18n/index.d.ts +3 -3
- package/dist/i18n/index.js +3 -3
- package/dist/{index-DN-J-5wT.d.cts → index-6xNpPsxR.d.cts} +1 -1
- package/dist/{index-BRHBCmLt.d.ts → index-DJTf9yxn.d.ts} +1 -1
- package/dist/{index-DhjMjz7L.d.cts → index-DhK_zqOO.d.ts} +39 -5
- package/dist/{index-C8kQtmOk.d.ts → index-DyRt_5vM.d.cts} +39 -5
- package/dist/index.cjs +1501 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +261 -19
- package/dist/index.d.ts +261 -19
- package/dist/index.js +1118 -44
- package/dist/index.js.map +1 -1
- package/dist/{ledger-2NX4L7PN.js → ledger-GA4DMJS6.js} +3 -3
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +3 -3
- package/dist/periods/index.d.ts +3 -3
- package/dist/periods/index.js +3 -3
- package/dist/public-envelope-R4EIEQE6.js +31 -0
- package/dist/public-envelope-R4EIEQE6.js.map +1 -0
- package/dist/query/index.d.cts +1 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/session/index.cjs +4 -2
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +4 -4
- package/dist/session/index.d.ts +4 -4
- package/dist/session/index.js +1 -1
- package/dist/shadow/index.d.cts +3 -3
- package/dist/shadow/index.d.ts +3 -3
- package/dist/store/index.d.cts +3 -3
- package/dist/store/index.d.ts +3 -3
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +2 -2
- package/dist/sync/index.d.ts +2 -2
- package/dist/sync/index.js +2 -2
- package/dist/team/index.cjs +3 -1
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +3 -3
- package/dist/team/index.d.ts +3 -3
- package/dist/team/index.js +4 -4
- package/dist/tx/index.d.cts +3 -3
- package/dist/tx/index.d.ts +3 -3
- package/dist/{types-Bfs0qr5F.d.cts → types-BpyE4o_n.d.cts} +935 -4
- package/dist/{types-BZpCZB8N.d.ts → types-Df72wWCC.d.ts} +935 -4
- package/package.json +1 -1
- package/dist/chunk-E445ICYI.js.map +0 -1
- package/dist/chunk-GJILMRPO.js.map +0 -1
- package/dist/chunk-M2F2JAWB.js.map +0 -1
- package/dist/chunk-ZRG4V3F5.js.map +0 -1
- /package/dist/{chunk-UQFSPSWG.js.map → chunk-E4OOAPBZ.js.map} +0 -0
- /package/dist/{chunk-EXQRC2L4.js.map → chunk-H3DV46AQ.js.map} +0 -0
- /package/dist/{chunk-XHFOENR2.js.map → chunk-LMKOSLJY.js.map} +0 -0
- /package/dist/{chunk-4OWFYIDQ.js.map → chunk-MIRZMUSQ.js.map} +0 -0
- /package/dist/{chunk-5AATM2M2.js.map → chunk-QUDXYI4W.js.map} +0 -0
- /package/dist/{chunk-ZLMV3TUA.js.map → chunk-QV4WLLKB.js.map} +0 -0
- /package/dist/{ledger-2NX4L7PN.js.map → ledger-GA4DMJS6.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { I as IndexStrategy, d as LazyQuery } from './lazy-builder-CZVLKh0Z.cjs';
|
|
2
2
|
import { A as AggregateStrategy } from './strategy-D-SrOLCl.cjs';
|
|
3
3
|
import { C as CrdtStrategy, a as CrdtMode, b as CrdtState } from './strategy-BSxFXGzb.cjs';
|
|
4
|
-
import { U as RefDescriptor, p as JoinableSource, Z as RefViolation, Q as Query, $ as ScanBuilder } from './index-
|
|
4
|
+
import { N as NoydbError, U as RefDescriptor, p as JoinableSource, Z as RefViolation, Q as Query, $ as ScanBuilder } from './index-6xNpPsxR.cjs';
|
|
5
5
|
import { I as IndexDef, C as CollectionIndexes } from './predicate-SBHmi6D0.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1739,6 +1739,86 @@ declare class NoydbEventEmitter {
|
|
|
1739
1739
|
removeAllListeners(): void;
|
|
1740
1740
|
}
|
|
1741
1741
|
|
|
1742
|
+
/**
|
|
1743
|
+
* Passphrase validation — phrase format (per the three-tier session-tiers
|
|
1744
|
+
* design, locked 2026-05-04).
|
|
1745
|
+
*
|
|
1746
|
+
* Passphrases are **phrases**: multiple simple words, easy to remember,
|
|
1747
|
+
* structurally constrained so a weak choice cannot silently collapse the
|
|
1748
|
+
* security floor. The format is intentionally narrow: lowercase letters
|
|
1749
|
+
* and single spaces only, no punctuation, no symbols, no digits.
|
|
1750
|
+
*
|
|
1751
|
+
* - Default minimum: 6 words (~77 bits with the 7,776-word EFF list).
|
|
1752
|
+
* - Strict minimum: 8 words (~103 bits).
|
|
1753
|
+
* - Per-word minimum: 3 characters (excludes "a", "is", "of").
|
|
1754
|
+
* - Adjacent repeats rejected ("the the").
|
|
1755
|
+
*
|
|
1756
|
+
* The hub runs validation default-on at every passphrase ingress
|
|
1757
|
+
* (`createOwnerKeyring`, `grant`, `rotatePassphrase`); test fixtures and
|
|
1758
|
+
* CLI scripts override via `{ allowWeakPassphrase: true }`.
|
|
1759
|
+
*
|
|
1760
|
+
* @module
|
|
1761
|
+
*/
|
|
1762
|
+
|
|
1763
|
+
/** All reasons a phrase can be rejected. */
|
|
1764
|
+
type WeakPassphraseReason = 'empty' | 'invalid-chars' | 'leading-or-trailing-space' | 'double-space' | 'too-few-words' | 'word-too-short' | 'repeated-adjacent';
|
|
1765
|
+
/** Per-vault knobs. Aligns with `VaultPolicy.passphrase`. */
|
|
1766
|
+
interface PassphrasePolicy {
|
|
1767
|
+
/** Minimum number of words. Default 6. Strict policy uses 8. */
|
|
1768
|
+
readonly minWords?: number;
|
|
1769
|
+
/** Minimum characters per word. Default 3. */
|
|
1770
|
+
readonly minWordLength?: number;
|
|
1771
|
+
/** Reject adjacent identical words ("the the"). Default true. */
|
|
1772
|
+
readonly rejectRepeatedAdjacent?: boolean;
|
|
1773
|
+
}
|
|
1774
|
+
/** Result of a check. Discriminated union — compile-time exhaustive. */
|
|
1775
|
+
type PassphraseValidationResult = {
|
|
1776
|
+
readonly ok: true;
|
|
1777
|
+
readonly words: number;
|
|
1778
|
+
} | {
|
|
1779
|
+
readonly ok: false;
|
|
1780
|
+
readonly reason: WeakPassphraseReason;
|
|
1781
|
+
readonly minimum?: number;
|
|
1782
|
+
readonly got?: number;
|
|
1783
|
+
};
|
|
1784
|
+
/**
|
|
1785
|
+
* Thrown by `assertStrongPassphrase()` and by every hub ingress
|
|
1786
|
+
* point (`createOwnerKeyring`, `grant`, `rotatePassphrase`) when a
|
|
1787
|
+
* supplied phrase fails the structural rules above.
|
|
1788
|
+
*/
|
|
1789
|
+
declare class WeakPassphraseError extends NoydbError {
|
|
1790
|
+
readonly reason: WeakPassphraseReason;
|
|
1791
|
+
readonly suggestion: string;
|
|
1792
|
+
constructor(reason: WeakPassphraseReason, suggestion: string);
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Inspect a phrase against the format rules and return a structured
|
|
1796
|
+
* verdict. Never throws — callers either branch on `ok` or pass the
|
|
1797
|
+
* result to {@link assertStrongPassphrase} for the throwing flavour.
|
|
1798
|
+
*/
|
|
1799
|
+
declare function validatePassphrase(s: string, opts?: PassphrasePolicy): PassphraseValidationResult;
|
|
1800
|
+
/**
|
|
1801
|
+
* Throw {@link WeakPassphraseError} when the phrase fails. Used by
|
|
1802
|
+
* `createOwnerKeyring`, `grant`, and `rotatePassphrase` at ingress.
|
|
1803
|
+
*
|
|
1804
|
+
* Pass `{ allowWeakPassphrase: true }` to bypass — intended for test
|
|
1805
|
+
* fixtures, CLI scripts, and dev environments. The override never
|
|
1806
|
+
* loosens the cryptographic key derivation; it only relaxes the
|
|
1807
|
+
* structural-strength gate.
|
|
1808
|
+
*/
|
|
1809
|
+
declare function assertStrongPassphrase(s: string, opts?: PassphrasePolicy & {
|
|
1810
|
+
allowWeakPassphrase?: boolean;
|
|
1811
|
+
}): void;
|
|
1812
|
+
/**
|
|
1813
|
+
* Estimate the entropy of a phrase, given the EFF 7,776-word list as
|
|
1814
|
+
* the assumed wordlist. ~12.9 bits per word.
|
|
1815
|
+
*
|
|
1816
|
+
* Returns 0 for any input that fails the phrase format — character-class
|
|
1817
|
+
* estimates aren't comparable to phrase entropy, and surfacing 0 makes
|
|
1818
|
+
* weak inputs visible in any UI that displays an entropy meter.
|
|
1819
|
+
*/
|
|
1820
|
+
declare function estimateEntropy(passphrase: string): number;
|
|
1821
|
+
|
|
1742
1822
|
/** In-memory representation of an unlocked keyring. */
|
|
1743
1823
|
interface UnlockedKeyring {
|
|
1744
1824
|
readonly userId: string;
|
|
@@ -1761,6 +1841,20 @@ interface UnlockedKeyring {
|
|
|
1761
1841
|
* bundle import granted, regardless of role).
|
|
1762
1842
|
*/
|
|
1763
1843
|
readonly importCapability?: ImportCapability;
|
|
1844
|
+
/**
|
|
1845
|
+
* Tier-2 authenticator slots — readonly snapshot loaded from the
|
|
1846
|
+
* keyring file. Mutations go through `enrollAuthenticator` /
|
|
1847
|
+
* `removeAuthenticator` (issue #11), which write back via
|
|
1848
|
+
* `persistKeyring`. Always defined; loads with an empty array for
|
|
1849
|
+
* keyrings written before the multi-slot extension landed.
|
|
1850
|
+
*/
|
|
1851
|
+
readonly authenticators: readonly KeyringAuthenticator[];
|
|
1852
|
+
/**
|
|
1853
|
+
* Reserved per-keyring policy override (forward-compat for Option C
|
|
1854
|
+
* — see {@link VaultPolicyOnDisk}). v1.0 round-trips this field but
|
|
1855
|
+
* never enforces it; the gate engine uses `_meta/policy` only.
|
|
1856
|
+
*/
|
|
1857
|
+
readonly policy?: VaultPolicyOnDisk;
|
|
1764
1858
|
}
|
|
1765
1859
|
/**
|
|
1766
1860
|
* Recipient slot in a re-keyed `.noydb` bundle. Each slot becomes its
|
|
@@ -2715,6 +2809,347 @@ declare class SyncEngine {
|
|
|
2715
2809
|
private persistMeta;
|
|
2716
2810
|
}
|
|
2717
2811
|
|
|
2812
|
+
/**
|
|
2813
|
+
* Tier-1 change flows — `rotatePassphrase` (user remembers old) and
|
|
2814
|
+
* `recoverPassphrase` (user supplies a recovery proof). Issue #10.
|
|
2815
|
+
*
|
|
2816
|
+
* The two flows share the post-verification half — fresh salt, fresh
|
|
2817
|
+
* KEK, rewrap every DEK — and differ only in how they re-derive the
|
|
2818
|
+
* old KEK:
|
|
2819
|
+
*
|
|
2820
|
+
* - **Rotate**: derive from the supplied `oldPassphrase`.
|
|
2821
|
+
* - **Recover (paper)**: unwrap from a `RecoveryCodeEntry` using a
|
|
2822
|
+
* user-supplied recovery code. The entry is burned on success.
|
|
2823
|
+
*
|
|
2824
|
+
* The non-paper recovery profiles (Shamir, multi-channel,
|
|
2825
|
+
* admin-mediated) are not yet wired — calling them throws
|
|
2826
|
+
* {@link RecoveryProfileNotImplementedError} with a tracking link.
|
|
2827
|
+
*
|
|
2828
|
+
* @module
|
|
2829
|
+
*/
|
|
2830
|
+
|
|
2831
|
+
/** Caller payload for {@link rotatePassphrase}. */
|
|
2832
|
+
interface RotatePassphraseInput {
|
|
2833
|
+
readonly oldPassphrase: string;
|
|
2834
|
+
readonly newPassphrase: string;
|
|
2835
|
+
readonly passphrasePolicy?: PassphrasePolicy;
|
|
2836
|
+
readonly allowWeakPassphrase?: boolean;
|
|
2837
|
+
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Re-derive the user's KEK from `oldPassphrase`, rewrap every DEK
|
|
2840
|
+
* under a freshly-derived KEK from `newPassphrase`, and persist.
|
|
2841
|
+
*
|
|
2842
|
+
* Tier-2 authenticator slots are NOT preserved — each slot wraps the
|
|
2843
|
+
* old KEK and would need the user's per-slot derivation key to
|
|
2844
|
+
* re-wrap; the hub doesn't hold that. The user re-enrols any slots
|
|
2845
|
+
* after rotation. v0.1.0-pre.5 limitation.
|
|
2846
|
+
*
|
|
2847
|
+
* @throws `InvalidKeyError` if `oldPassphrase` does not unwrap the keyring.
|
|
2848
|
+
* @throws `WeakPassphraseError` if `newPassphrase` fails the strength rule.
|
|
2849
|
+
*/
|
|
2850
|
+
declare function rotatePassphrase(store: NoydbStore, vault: string, userId: string, input: RotatePassphraseInput): Promise<UnlockedKeyring>;
|
|
2851
|
+
/** Caller payload for {@link recoverPassphrase}. */
|
|
2852
|
+
type RecoveryProof = {
|
|
2853
|
+
readonly profile: 'paper';
|
|
2854
|
+
readonly payload: {
|
|
2855
|
+
readonly code: string;
|
|
2856
|
+
};
|
|
2857
|
+
} | {
|
|
2858
|
+
readonly profile: 'shamir';
|
|
2859
|
+
readonly payload: {
|
|
2860
|
+
readonly shares: ReadonlyArray<string>;
|
|
2861
|
+
};
|
|
2862
|
+
} | {
|
|
2863
|
+
readonly profile: 'multi-channel';
|
|
2864
|
+
readonly payload: {
|
|
2865
|
+
readonly proofs: ReadonlyArray<unknown>;
|
|
2866
|
+
};
|
|
2867
|
+
} | {
|
|
2868
|
+
readonly profile: 'admin-mediated';
|
|
2869
|
+
readonly payload: {
|
|
2870
|
+
readonly token: string;
|
|
2871
|
+
readonly factor?: unknown;
|
|
2872
|
+
};
|
|
2873
|
+
};
|
|
2874
|
+
interface RecoverPassphraseInput {
|
|
2875
|
+
readonly newPassphrase: string;
|
|
2876
|
+
readonly recoveryProof: RecoveryProof;
|
|
2877
|
+
readonly passphrasePolicy?: PassphrasePolicy;
|
|
2878
|
+
readonly allowWeakPassphrase?: boolean;
|
|
2879
|
+
}
|
|
2880
|
+
/**
|
|
2881
|
+
* Reset the user's passphrase using a recovery proof. v0.1.0-pre.5
|
|
2882
|
+
* supports the `'paper'` profile via `@noy-db/on-recovery` entries
|
|
2883
|
+
* persisted in `_meta/recovery-paper`. The other three profiles throw
|
|
2884
|
+
* {@link RecoveryProfileNotImplementedError}.
|
|
2885
|
+
*
|
|
2886
|
+
* On success, the used recovery entry is burned (deleted from the
|
|
2887
|
+
* stored set).
|
|
2888
|
+
*/
|
|
2889
|
+
declare function recoverPassphrase(store: NoydbStore, vault: string, userId: string, input: RecoverPassphraseInput): Promise<UnlockedKeyring>;
|
|
2890
|
+
|
|
2891
|
+
/**
|
|
2892
|
+
* Recovery profile persistence + dispatch — issue #10.
|
|
2893
|
+
*
|
|
2894
|
+
* v0.1.0-pre.5 wires the **paper** profile end-to-end through
|
|
2895
|
+
* `@noy-db/on-recovery`. The other three profiles (Shamir,
|
|
2896
|
+
* multi-channel, admin-mediated) ship the API surface and throw
|
|
2897
|
+
* {@link RecoveryProfileNotImplementedError} during use; per-profile
|
|
2898
|
+
* dispatch lands in follow-up issues.
|
|
2899
|
+
*
|
|
2900
|
+
* Storage layout:
|
|
2901
|
+
*
|
|
2902
|
+
* ```
|
|
2903
|
+
* _meta/recovery-paper — JSON { entries: RecoveryCodeEntry[] } produced by `on-recovery`.
|
|
2904
|
+
* _meta/recovery-shamir — reserved
|
|
2905
|
+
* _meta/recovery-multi — reserved
|
|
2906
|
+
* _meta/recovery-admin — reserved
|
|
2907
|
+
* ```
|
|
2908
|
+
*
|
|
2909
|
+
* Like `_meta/policy` and `_meta/handle`, the documents are plain JSON
|
|
2910
|
+
* with empty `_iv` — the recovery-code wrapping is what protects the
|
|
2911
|
+
* KEK; the entries themselves are inert without the user's code.
|
|
2912
|
+
*
|
|
2913
|
+
* @module
|
|
2914
|
+
*/
|
|
2915
|
+
|
|
2916
|
+
/**
|
|
2917
|
+
* One paper recovery code as persisted in `_meta/recovery-paper`.
|
|
2918
|
+
*
|
|
2919
|
+
* The hub's KEK is intentionally non-extractable (see `crypto.ts`),
|
|
2920
|
+
* so the recovery entry can't AES-KW-wrap the KEK directly. Instead
|
|
2921
|
+
* we wrap a serialized DEK set: the entry holds the AES-GCM
|
|
2922
|
+
* ciphertext of `{ deks: { collection: rawDekBase64 } }`. Recovery
|
|
2923
|
+
* deserializes the DEK set, then mints a fresh KEK from the new
|
|
2924
|
+
* passphrase and rewraps the DEKs under it.
|
|
2925
|
+
*
|
|
2926
|
+
* This is the same pattern `@noy-db/on-pin` uses for tier-3 quick
|
|
2927
|
+
* resume — the cryptographic guarantee is identical (AES-GCM with a
|
|
2928
|
+
* PBKDF2-derived key), and it sidesteps the non-extractable-KEK
|
|
2929
|
+
* constraint cleanly.
|
|
2930
|
+
*/
|
|
2931
|
+
interface PaperRecoveryEntry {
|
|
2932
|
+
readonly codeId: string;
|
|
2933
|
+
/** Base64 PBKDF2 salt. */
|
|
2934
|
+
readonly salt: string;
|
|
2935
|
+
/** Base64 AES-GCM IV used for the wrapped-DEK ciphertext. */
|
|
2936
|
+
readonly iv: string;
|
|
2937
|
+
/** Base64 AES-GCM ciphertext — JSON `{ deks: Record<string, base64> }`. */
|
|
2938
|
+
readonly wrappedDeks: string;
|
|
2939
|
+
readonly enrolledAt: string;
|
|
2940
|
+
}
|
|
2941
|
+
interface PaperRecoveryDoc {
|
|
2942
|
+
readonly _noydb_recovery: 1;
|
|
2943
|
+
readonly profile: 'paper';
|
|
2944
|
+
readonly entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
2945
|
+
}
|
|
2946
|
+
/** Read the paper-recovery entries. Returns empty array when absent. */
|
|
2947
|
+
declare function loadPaperRecoveryEntries(store: NoydbStore, vault: string): Promise<ReadonlyArray<PaperRecoveryEntry>>;
|
|
2948
|
+
/** Replace the paper-recovery entries (used after burn-on-recovery). */
|
|
2949
|
+
declare function savePaperRecoveryEntries(store: NoydbStore, vault: string, entries: ReadonlyArray<PaperRecoveryEntry>): Promise<void>;
|
|
2950
|
+
/** Drop a single paper-recovery entry (burn-on-use). */
|
|
2951
|
+
declare function burnPaperRecoveryEntry(store: NoydbStore, vault: string, codeId: string): Promise<void>;
|
|
2952
|
+
/** Whether at least one recovery profile has any enrolled entries. */
|
|
2953
|
+
declare function hasRecoveryEnrolled(store: NoydbStore, vault: string): Promise<boolean>;
|
|
2954
|
+
|
|
2955
|
+
/**
|
|
2956
|
+
* Public envelope — owner-curated plaintext metadata, readable
|
|
2957
|
+
* before vault unlock or bundle decryption.
|
|
2958
|
+
*
|
|
2959
|
+
* @see docs/subsystems/public-envelope.md
|
|
2960
|
+
*
|
|
2961
|
+
* @module
|
|
2962
|
+
*/
|
|
2963
|
+
/**
|
|
2964
|
+
* Either a single string (used when the developer's app is
|
|
2965
|
+
* single-locale) or a locale → string map for i18n. Mirrors the
|
|
2966
|
+
* shape `@noy-db/hub/i18n` already uses for record fields, so the
|
|
2967
|
+
* existing `resolveI18nText` resolver applies.
|
|
2968
|
+
*/
|
|
2969
|
+
type PublicEnvelopeText = string | Record<string, string>;
|
|
2970
|
+
/**
|
|
2971
|
+
* Persisted shape — both `_meta/public-envelope` and the bundle
|
|
2972
|
+
* header carry this. The version number is monotonic per vault and
|
|
2973
|
+
* helps cache invalidators detect change without hashing the JSON.
|
|
2974
|
+
*/
|
|
2975
|
+
interface PublicEnvelope {
|
|
2976
|
+
readonly _noydb_public: 1;
|
|
2977
|
+
readonly version: number;
|
|
2978
|
+
readonly name?: PublicEnvelopeText;
|
|
2979
|
+
readonly description?: PublicEnvelopeText;
|
|
2980
|
+
/** Inline `data:` URL (`data:image/png;base64,…` or `data:image/svg+xml;base64,…`). */
|
|
2981
|
+
readonly icon?: string;
|
|
2982
|
+
/** ISO-8601 timestamp; auto-set on first envelope write, immutable thereafter. */
|
|
2983
|
+
readonly createdAt?: string;
|
|
2984
|
+
/** ISO-8601 timestamp; auto-updated on every `setPublicEnvelope` call. */
|
|
2985
|
+
readonly updatedAt?: string;
|
|
2986
|
+
/** BCP-47 fallback locale for renderers when the user's locale isn't covered. */
|
|
2987
|
+
readonly defaultLocale?: string;
|
|
2988
|
+
}
|
|
2989
|
+
/** Field names the developer can allow in `PublicEnvelopeSchema.fields`. */
|
|
2990
|
+
declare const PUBLIC_ENVELOPE_FIELDS: readonly ["name", "description", "icon", "createdAt", "updatedAt", "defaultLocale"];
|
|
2991
|
+
type PublicEnvelopeField = (typeof PUBLIC_ENVELOPE_FIELDS)[number];
|
|
2992
|
+
/**
|
|
2993
|
+
* Build-time schema. The developer enables the feature and bounds
|
|
2994
|
+
* what the owner can set. `true` is shorthand for "all defaults" —
|
|
2995
|
+
* gives the owner the full field set with the standard caps.
|
|
2996
|
+
*/
|
|
2997
|
+
interface PublicEnvelopeSchema {
|
|
2998
|
+
/**
|
|
2999
|
+
* Allowed field names. Setting `name`/`description`/`icon`/`defaultLocale` is
|
|
3000
|
+
* gated on the field being listed here. `createdAt` / `updatedAt` are managed
|
|
3001
|
+
* by the hub; including them is a no-op (the owner cannot set them
|
|
3002
|
+
* directly). Default: every field above.
|
|
3003
|
+
*/
|
|
3004
|
+
readonly fields?: ReadonlyArray<PublicEnvelopeField>;
|
|
3005
|
+
/**
|
|
3006
|
+
* Maximum icon size — measured as the length of the data-URL
|
|
3007
|
+
* string. Default 256 KB.
|
|
3008
|
+
*/
|
|
3009
|
+
readonly maxIconBytes?: number;
|
|
3010
|
+
/** Allowed icon MIME types. Default ['image/png', 'image/svg+xml']. */
|
|
3011
|
+
readonly iconMimeTypes?: ReadonlyArray<string>;
|
|
3012
|
+
/** Maximum length of `name` / `description` per locale. Default 200. */
|
|
3013
|
+
readonly maxStringChars?: number;
|
|
3014
|
+
}
|
|
3015
|
+
/** Default schema values; merged onto every developer-supplied schema. */
|
|
3016
|
+
declare const DEFAULT_PUBLIC_ENVELOPE_SCHEMA: {
|
|
3017
|
+
readonly fields: readonly ["name", "description", "icon", "createdAt", "updatedAt", "defaultLocale"];
|
|
3018
|
+
readonly maxIconBytes: number;
|
|
3019
|
+
readonly iconMimeTypes: readonly ["image/png", "image/svg+xml"];
|
|
3020
|
+
readonly maxStringChars: 200;
|
|
3021
|
+
};
|
|
3022
|
+
/** Resolved schema after merging developer override onto defaults. */
|
|
3023
|
+
interface ResolvedPublicEnvelopeSchema {
|
|
3024
|
+
readonly fields: ReadonlyArray<PublicEnvelopeField>;
|
|
3025
|
+
readonly maxIconBytes: number;
|
|
3026
|
+
readonly iconMimeTypes: ReadonlyArray<string>;
|
|
3027
|
+
readonly maxStringChars: number;
|
|
3028
|
+
}
|
|
3029
|
+
/**
|
|
3030
|
+
* Merge developer schema onto the defaults. The shorthand `true`
|
|
3031
|
+
* resolves to the full default schema; an explicit object only
|
|
3032
|
+
* overrides the keys it provides.
|
|
3033
|
+
*/
|
|
3034
|
+
declare function resolveSchema(schema: true | PublicEnvelopeSchema | undefined): ResolvedPublicEnvelopeSchema | undefined;
|
|
3035
|
+
|
|
3036
|
+
/** Owner-supplied input — the subset of {@link PublicEnvelope} the owner can set. */
|
|
3037
|
+
interface SetPublicEnvelopeInput {
|
|
3038
|
+
readonly name?: PublicEnvelopeText;
|
|
3039
|
+
readonly description?: PublicEnvelopeText;
|
|
3040
|
+
readonly icon?: string;
|
|
3041
|
+
readonly defaultLocale?: string;
|
|
3042
|
+
}
|
|
3043
|
+
/**
|
|
3044
|
+
* Validate an owner-supplied envelope input against the developer's
|
|
3045
|
+
* resolved schema. Throws `ValidationError` on the first violation;
|
|
3046
|
+
* returns void on success.
|
|
3047
|
+
*
|
|
3048
|
+
* The validator is deliberately strict: every fail mode is a hard
|
|
3049
|
+
* error rather than a silent drop, so the owner finds out immediately
|
|
3050
|
+
* which field they oversized rather than discovering a truncated
|
|
3051
|
+
* label months later.
|
|
3052
|
+
*/
|
|
3053
|
+
declare function validatePublicEnvelopeInput(input: SetPublicEnvelopeInput, schema: ResolvedPublicEnvelopeSchema): void;
|
|
3054
|
+
/**
|
|
3055
|
+
* Lightweight runtime predicate — used by the bundle header
|
|
3056
|
+
* validator to recognise a public envelope without requiring it.
|
|
3057
|
+
*/
|
|
3058
|
+
declare function isPublicEnvelope(x: unknown): x is PublicEnvelope;
|
|
3059
|
+
|
|
3060
|
+
/**
|
|
3061
|
+
* Tier-2 authenticator slot management — issue #11.
|
|
3062
|
+
*
|
|
3063
|
+
* Each slot independently wraps the SAME KEK under a method-specific
|
|
3064
|
+
* derived key (LUKS pattern). Enrolling adds a slot; removing drops
|
|
3065
|
+
* one. Both are constant-time keyring writes — no DEK re-keying.
|
|
3066
|
+
*
|
|
3067
|
+
* The crypto for each method lives in its `@noy-db/on-*` package
|
|
3068
|
+
* (`on-webauthn`, `on-oidc`, `on-password`); this module accepts the
|
|
3069
|
+
* package's `wrapped_kek` ciphertext + `meta` payload and persists it.
|
|
3070
|
+
*
|
|
3071
|
+
* @see docs/subsystems/session-tiers.md → Tier 2 — Authenticate
|
|
3072
|
+
*
|
|
3073
|
+
* @module
|
|
3074
|
+
*/
|
|
3075
|
+
|
|
3076
|
+
/** Input shape for `enrollAuthenticator`. */
|
|
3077
|
+
interface EnrollAuthenticatorOptions {
|
|
3078
|
+
readonly id: string;
|
|
3079
|
+
readonly method: KeyringAuthenticator['method'];
|
|
3080
|
+
/** Already-wrapped KEK ciphertext (base64) — produced by the on-* package. */
|
|
3081
|
+
readonly wrapped_kek: string;
|
|
3082
|
+
/** Method-specific metadata (cred id, salt, …). */
|
|
3083
|
+
readonly meta: Record<string, unknown>;
|
|
3084
|
+
/** Tier the active session held when enrolling. Defaults to 1. */
|
|
3085
|
+
readonly enrolled_via_tier?: 1 | 2;
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* Append a new authenticator slot to the keyring file. Throws
|
|
3089
|
+
* `ValidationError` if a slot with the same id already exists — the
|
|
3090
|
+
* caller decides whether to remove + re-enroll.
|
|
3091
|
+
*/
|
|
3092
|
+
declare function enrollAuthenticator(store: NoydbStore, vault: string, keyring: UnlockedKeyring, options: EnrollAuthenticatorOptions): Promise<UnlockedKeyring>;
|
|
3093
|
+
/**
|
|
3094
|
+
* Drop a slot by id. No-op if the slot doesn't exist (idempotent —
|
|
3095
|
+
* removing a non-existent slot is a recoverable retry, not an error).
|
|
3096
|
+
*/
|
|
3097
|
+
declare function removeAuthenticator(store: NoydbStore, vault: string, keyring: UnlockedKeyring, slotId: string): Promise<UnlockedKeyring>;
|
|
3098
|
+
/**
|
|
3099
|
+
* Look up a slot by id. Returns `undefined` when no slot matches.
|
|
3100
|
+
* Used by tier-2 unlock dispatchers to fetch the wrapped KEK + meta
|
|
3101
|
+
* before invoking the method-specific verifier.
|
|
3102
|
+
*/
|
|
3103
|
+
declare function findAuthenticator(keyring: UnlockedKeyring, slotId: string): KeyringAuthenticator | undefined;
|
|
3104
|
+
|
|
3105
|
+
/**
|
|
3106
|
+
* Per-vault tier-3 (PIN / quick-resume) state — issue #11.
|
|
3107
|
+
*
|
|
3108
|
+
* The hub holds a `PinResumeState`-shaped record in memory, keyed by
|
|
3109
|
+
* vault. `enrollUnlock` populates it; `unlockViaPin` consumes it via
|
|
3110
|
+
* `@noy-db/on-pin`'s `resumePin`. The cached state is wiped when the
|
|
3111
|
+
* idle timer fires or `db.close()` is called.
|
|
3112
|
+
*
|
|
3113
|
+
* Importantly, this module does NOT depend on `@noy-db/on-pin` — the
|
|
3114
|
+
* caller passes the already-built state in. That keeps the hub's
|
|
3115
|
+
* `peerDependencies` empty for tier-3 and lets developers swap the
|
|
3116
|
+
* primitive (e.g. an OS biometric in place of a PIN).
|
|
3117
|
+
*
|
|
3118
|
+
* @module
|
|
3119
|
+
*/
|
|
3120
|
+
/**
|
|
3121
|
+
* Opaque `PinResumeState`-compatible record. Mirrored from
|
|
3122
|
+
* `@noy-db/on-pin/PinResumeState`. The hub treats the contents as
|
|
3123
|
+
* a black box.
|
|
3124
|
+
*/
|
|
3125
|
+
interface QuickUnlockState {
|
|
3126
|
+
readonly _noydb_on_pin: 1;
|
|
3127
|
+
readonly salt: string;
|
|
3128
|
+
readonly iv: string;
|
|
3129
|
+
readonly wrappedKeyring: string;
|
|
3130
|
+
readonly expiresAt: string;
|
|
3131
|
+
readonly maxAttempts: number;
|
|
3132
|
+
attempts: number;
|
|
3133
|
+
}
|
|
3134
|
+
/** In-memory store for tier-3 unlock state, keyed by vault. */
|
|
3135
|
+
declare class QuickUnlockStore {
|
|
3136
|
+
private readonly states;
|
|
3137
|
+
private readonly timers;
|
|
3138
|
+
/**
|
|
3139
|
+
* Register a quick-unlock state for a vault. Replaces any existing
|
|
3140
|
+
* state. Schedules an automatic clear when the state's `expiresAt`
|
|
3141
|
+
* elapses.
|
|
3142
|
+
*/
|
|
3143
|
+
set(vault: string, state: QuickUnlockState): void;
|
|
3144
|
+
/** Read the state for a vault. Returns undefined when none is registered. */
|
|
3145
|
+
get(vault: string): QuickUnlockState | undefined;
|
|
3146
|
+
/** Drop the state for a vault. Cancels the auto-clear timer. */
|
|
3147
|
+
delete(vault: string): void;
|
|
3148
|
+
/** Drop every cached state. Called on `db.close()`. */
|
|
3149
|
+
clear(): void;
|
|
3150
|
+
private clearTimer;
|
|
3151
|
+
}
|
|
3152
|
+
|
|
2718
3153
|
/**
|
|
2719
3154
|
* Multi-record atomic transactions.
|
|
2720
3155
|
*
|
|
@@ -2853,6 +3288,84 @@ declare class TxCollection<T> {
|
|
|
2853
3288
|
*/
|
|
2854
3289
|
declare function runTransaction<T>(db: Noydb, fn: (tx: TxContext) => Promise<T> | T): Promise<T>;
|
|
2855
3290
|
|
|
3291
|
+
/**
|
|
3292
|
+
* Policy gate DSL types — issue #9.
|
|
3293
|
+
*
|
|
3294
|
+
* Sensitive operations (rotate the passphrase, enroll an authenticator,
|
|
3295
|
+
* export plaintext, grant a user, …) are gated by a typed policy
|
|
3296
|
+
* object. The developer supplies a {@link VaultPolicy} at vault
|
|
3297
|
+
* creation; the hub merges it onto a built-in preset and persists the
|
|
3298
|
+
* merged document at `_meta/policy`.
|
|
3299
|
+
*
|
|
3300
|
+
* @see docs/subsystems/session-tiers.md → Policy gates DSL
|
|
3301
|
+
*
|
|
3302
|
+
* @module
|
|
3303
|
+
*/
|
|
3304
|
+
|
|
3305
|
+
/** A single off-device factor surface — the proof an actor presents at gate time. */
|
|
3306
|
+
type FactorKind = 'totp' | 'email-otp' | 'recovery' | 'shamir' | 'webauthn-roaming';
|
|
3307
|
+
/**
|
|
3308
|
+
* One factor requirement entry. The default is "any one of the listed
|
|
3309
|
+
* factors, fresh within the last 5 minutes". Bumping `count` requires N
|
|
3310
|
+
* distinct fresh proofs; bumping `freshnessMs` widens the acceptance
|
|
3311
|
+
* window.
|
|
3312
|
+
*/
|
|
3313
|
+
interface FactorRequirement {
|
|
3314
|
+
readonly anyOf: ReadonlyArray<FactorKind>;
|
|
3315
|
+
/** Number of distinct factors required. Default 1. */
|
|
3316
|
+
readonly count?: number;
|
|
3317
|
+
/** How recent each proof must be. Default 5 minutes. */
|
|
3318
|
+
readonly freshnessMs?: number;
|
|
3319
|
+
}
|
|
3320
|
+
/** Soft signals layered on top of the gate verdict — never block on their own. */
|
|
3321
|
+
interface WarningRules {
|
|
3322
|
+
/** Behavior on shared-device tier-1 ops. `'block'` raises a `PolicyDeniedError`. */
|
|
3323
|
+
readonly sharedDevice?: 'warn' | 'block';
|
|
3324
|
+
/** Behavior on weak tier-2 (e.g. password-only) for sensitive ops. */
|
|
3325
|
+
readonly weakAuthenticator?: 'warn' | 'block';
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Policy applied to one named gate. `enabled: false` disables the
|
|
3329
|
+
* action entirely (useful in managed-passphrase mode where rotation is
|
|
3330
|
+
* impossible by construction).
|
|
3331
|
+
*/
|
|
3332
|
+
interface GatePolicy {
|
|
3333
|
+
/** Minimum tier the active session must hold. */
|
|
3334
|
+
readonly minTier: 1 | 2 | 3;
|
|
3335
|
+
/** Extra freshness-bound proofs required at gate time. */
|
|
3336
|
+
readonly factors?: ReadonlyArray<FactorRequirement>;
|
|
3337
|
+
readonly warn?: WarningRules;
|
|
3338
|
+
readonly enabled?: boolean;
|
|
3339
|
+
}
|
|
3340
|
+
/**
|
|
3341
|
+
* Built-in gate names. App-defined gates live in the `app:*` namespace
|
|
3342
|
+
* and use the same engine; the engine treats unknown names with no
|
|
3343
|
+
* configured policy as "no gate" (no-op).
|
|
3344
|
+
*/
|
|
3345
|
+
type BuiltInGateName = 'rotate-passphrase' | 'recover-passphrase' | 'enroll-authenticator' | 'remove-authenticator' | 'rotate-unlock' | 'enroll-user' | 'revoke-user' | 'export-bundle' | 'export-plaintext' | 'view-user-auth';
|
|
3346
|
+
/** Either a built-in gate name or an `app:*` custom gate. */
|
|
3347
|
+
type GateName = BuiltInGateName | `app:${string}`;
|
|
3348
|
+
/**
|
|
3349
|
+
* Top-level policy object. Persisted at `_meta/policy` once at vault
|
|
3350
|
+
* creation. The `passphrase` block configures the strength rules
|
|
3351
|
+
* applied at every passphrase ingress (issue #7); `gates` configures
|
|
3352
|
+
* the action-level requirements.
|
|
3353
|
+
*/
|
|
3354
|
+
interface VaultPolicy {
|
|
3355
|
+
readonly passphrase?: PassphrasePolicy;
|
|
3356
|
+
readonly gates: Partial<Record<GateName, GatePolicy>>;
|
|
3357
|
+
}
|
|
3358
|
+
/** Concrete proof an actor presents to {@link checkGate}. */
|
|
3359
|
+
interface FactorProof {
|
|
3360
|
+
readonly kind: FactorKind;
|
|
3361
|
+
/** ISO-8601 timestamp the proof was minted at. Compared against `freshnessMs`. */
|
|
3362
|
+
readonly mintedAt?: string;
|
|
3363
|
+
/** Method-specific payload. The engine treats it as opaque — verification is delegated. */
|
|
3364
|
+
readonly payload?: unknown;
|
|
3365
|
+
}
|
|
3366
|
+
/** Active session tier — what the engine compares against `gate.minTier`. */
|
|
3367
|
+
type ActiveTier = 1 | 2 | 3;
|
|
3368
|
+
|
|
2856
3369
|
/** The top-level NOYDB instance. */
|
|
2857
3370
|
declare class Noydb {
|
|
2858
3371
|
private readonly options;
|
|
@@ -2860,6 +3373,25 @@ declare class Noydb {
|
|
|
2860
3373
|
private readonly vaultCache;
|
|
2861
3374
|
private readonly keyringCache;
|
|
2862
3375
|
private readonly syncEngines;
|
|
3376
|
+
/**
|
|
3377
|
+
* Per-vault active session tier — defaults to `1` after a passphrase
|
|
3378
|
+
* unlock; tier-2 / tier-3 unlocks (issue #11) downgrade it. Used by
|
|
3379
|
+
* {@link checkGate} to evaluate `gate.minTier`.
|
|
3380
|
+
*/
|
|
3381
|
+
private readonly activeTier;
|
|
3382
|
+
/**
|
|
3383
|
+
* Per-vault loaded policy. Cached after the first
|
|
3384
|
+
* `_meta/policy` load; replaced by `db.updatePolicy()`.
|
|
3385
|
+
*/
|
|
3386
|
+
private readonly policyCache;
|
|
3387
|
+
/** Per-vault tier-3 (PIN / quick-resume) state — issue #11. */
|
|
3388
|
+
private readonly quickUnlock;
|
|
3389
|
+
/**
|
|
3390
|
+
* Resolved public-envelope schema. Lazily computed once from
|
|
3391
|
+
* `NoydbOptions.publicEnvelope`; `undefined` when the developer
|
|
3392
|
+
* didn't opt in.
|
|
3393
|
+
*/
|
|
3394
|
+
private readonly publicEnvelopeSchema;
|
|
2863
3395
|
private closed;
|
|
2864
3396
|
private sessionTimer;
|
|
2865
3397
|
/** Per-vault policy enforcers. */
|
|
@@ -3113,6 +3645,211 @@ declare class Noydb {
|
|
|
3113
3645
|
* @internal — not part of the public API surface
|
|
3114
3646
|
*/
|
|
3115
3647
|
invokeTranslator(text: string, from: string, to: string, field: string, collection: string): Promise<string>;
|
|
3648
|
+
/**
|
|
3649
|
+
* Read the active policy for a vault. Loads from `_meta/policy` on
|
|
3650
|
+
* first call; subsequent calls hit the in-memory cache. Throws
|
|
3651
|
+
* `ValidationError` if the vault has not been opened.
|
|
3652
|
+
*/
|
|
3653
|
+
getPolicy(vault: string): Promise<VaultPolicy>;
|
|
3654
|
+
/**
|
|
3655
|
+
* Replace the policy document at `_meta/policy` and update the
|
|
3656
|
+
* in-memory cache. Gated by the `enroll-user` policy (a policy
|
|
3657
|
+
* change is fundamentally a privilege-management action).
|
|
3658
|
+
*/
|
|
3659
|
+
updatePolicy(vault: string, override: Partial<VaultPolicy>): Promise<VaultPolicy>;
|
|
3660
|
+
/**
|
|
3661
|
+
* Evaluate a policy gate against the active session tier and the
|
|
3662
|
+
* presented factor proofs. Throws {@link PolicyDeniedError} on
|
|
3663
|
+
* denial; resolves with `void` on success.
|
|
3664
|
+
*
|
|
3665
|
+
* @param vault The vault whose policy applies.
|
|
3666
|
+
* @param gate Gate name — built-in (e.g. `'rotate-passphrase'`)
|
|
3667
|
+
* or app-defined (`app:*`).
|
|
3668
|
+
* @param presented Caller-supplied factor proofs.
|
|
3669
|
+
*/
|
|
3670
|
+
checkGate(vault: string, gate: GateName, presented?: {
|
|
3671
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3672
|
+
sharedDevice?: boolean;
|
|
3673
|
+
}): Promise<void>;
|
|
3674
|
+
/** Read or persist the vault policy at `_meta/policy` on first open. */
|
|
3675
|
+
private bootstrapPolicy;
|
|
3676
|
+
/**
|
|
3677
|
+
* Throw {@link RecoveryNotEnrolledError} when the developer
|
|
3678
|
+
* explicitly opts into strict mandatory-recovery enforcement
|
|
3679
|
+
* (`createNoydb({ requireRecovery: true })`) and no recovery
|
|
3680
|
+
* entries are persisted.
|
|
3681
|
+
*
|
|
3682
|
+
* The default behavior is lenient — `recover-passphrase` is enabled
|
|
3683
|
+
* in `PERSONAL_POLICY` but the hub does not block vault open on
|
|
3684
|
+
* missing enrollment. v1.0 will flip the default to strict; for now,
|
|
3685
|
+
* apps that want the spec-mandated check turn it on per-vault.
|
|
3686
|
+
*/
|
|
3687
|
+
private assertRecoveryEnrolled;
|
|
3688
|
+
/**
|
|
3689
|
+
* Internal accessor used by tier-2/tier-3 unlock paths (issue #11)
|
|
3690
|
+
* to mark the active session tier.
|
|
3691
|
+
* @internal
|
|
3692
|
+
*/
|
|
3693
|
+
_setActiveTier(vault: string, tier: ActiveTier): void;
|
|
3694
|
+
/**
|
|
3695
|
+
* Add a tier-2 authenticator slot to the calling user's keyring.
|
|
3696
|
+
* Each slot independently wraps the SAME KEK under a method-specific
|
|
3697
|
+
* key — adding a slot is a constant-time keyring write.
|
|
3698
|
+
*
|
|
3699
|
+
* The wrapping ciphertext is produced by the corresponding
|
|
3700
|
+
* `@noy-db/on-*` package (e.g. `enrollPasswordAuthenticator` from
|
|
3701
|
+
* `@noy-db/on-password`); the hub persists the result.
|
|
3702
|
+
*
|
|
3703
|
+
* Gated by `enroll-authenticator`; `presented` carries any factor
|
|
3704
|
+
* proofs the active policy demands.
|
|
3705
|
+
*/
|
|
3706
|
+
enrollAuthenticator(vault: string, options: EnrollAuthenticatorOptions, presented?: {
|
|
3707
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3708
|
+
sharedDevice?: boolean;
|
|
3709
|
+
}): Promise<void>;
|
|
3710
|
+
/**
|
|
3711
|
+
* Remove a tier-2 authenticator slot. Idempotent — removing a
|
|
3712
|
+
* non-existent slot is a successful no-op. Gated by
|
|
3713
|
+
* `remove-authenticator`.
|
|
3714
|
+
*/
|
|
3715
|
+
removeAuthenticator(vault: string, slotId: string, presented?: {
|
|
3716
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3717
|
+
sharedDevice?: boolean;
|
|
3718
|
+
}): Promise<void>;
|
|
3719
|
+
/** Read the slot list for a vault. Internal — `describeAuthConfig` (#13) consumes this. */
|
|
3720
|
+
listAuthenticators(vault: string): Promise<ReadonlyArray<KeyringAuthenticator>>;
|
|
3721
|
+
/**
|
|
3722
|
+
* Resolve a slot by id, then hand the wrapped-KEK ciphertext + meta
|
|
3723
|
+
* to the caller-supplied verifier. The verifier is the
|
|
3724
|
+
* `unlockWith*` function from the corresponding `@noy-db/on-*`
|
|
3725
|
+
* package, e.g. `unlockWithPassword(slot, password)`.
|
|
3726
|
+
*
|
|
3727
|
+
* On success, mark the active session tier as 2 — subsequent
|
|
3728
|
+
* `checkGate` calls see a tier-2 unlock.
|
|
3729
|
+
*/
|
|
3730
|
+
unlockViaAuthenticator(vault: string, slotId: string, verify: (slot: KeyringAuthenticator) => Promise<UnlockedKeyring>): Promise<UnlockedKeyring>;
|
|
3731
|
+
/**
|
|
3732
|
+
* Set the owner-curated public envelope for a vault. Throws
|
|
3733
|
+
* `ValidationError` if the developer did not opt the hub into
|
|
3734
|
+
* `publicEnvelope` via `NoydbOptions`, or if the input violates
|
|
3735
|
+
* the resolved schema (oversized icon, disallowed MIME, oversized
|
|
3736
|
+
* string, unknown field).
|
|
3737
|
+
*
|
|
3738
|
+
* `createdAt` is set on the first write and preserved on every
|
|
3739
|
+
* subsequent write. `updatedAt` is refreshed on every write.
|
|
3740
|
+
* `version` is monotonic — increments on every successful write.
|
|
3741
|
+
*/
|
|
3742
|
+
setPublicEnvelope(vault: string, input: SetPublicEnvelopeInput): Promise<PublicEnvelope>;
|
|
3743
|
+
/**
|
|
3744
|
+
* Read the public envelope for a vault. Returns `undefined` when
|
|
3745
|
+
* none has been written. Pass `locale` to resolve any locale-map
|
|
3746
|
+
* fields to plain strings; omitting `locale` returns the raw map.
|
|
3747
|
+
*
|
|
3748
|
+
* Works even when the developer didn't enable
|
|
3749
|
+
* `publicEnvelope` — reads are passive and never throw on a
|
|
3750
|
+
* missing schema (the envelope is plaintext and exists on disk
|
|
3751
|
+
* regardless).
|
|
3752
|
+
*/
|
|
3753
|
+
getPublicEnvelope(vault: string, opts?: {
|
|
3754
|
+
readonly locale?: string;
|
|
3755
|
+
}): Promise<PublicEnvelope | undefined>;
|
|
3756
|
+
/** English summary of the configured auth model. */
|
|
3757
|
+
describeAuthConfig(vault: string): Promise<string>;
|
|
3758
|
+
/** Mermaid `flowchart TB` source for the auth graph. */
|
|
3759
|
+
diagramAuthConfig(vault: string): Promise<string>;
|
|
3760
|
+
/**
|
|
3761
|
+
* Per-user enrollment summary. Gated by `view-user-auth` (default:
|
|
3762
|
+
* disabled). Sanitization is allowlist-based — never renders cred
|
|
3763
|
+
* ids, password hashes, secrets, or any field outside the allowlist.
|
|
3764
|
+
*/
|
|
3765
|
+
describeUserAuth(vault: string, userId: string, factors?: {
|
|
3766
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3767
|
+
sharedDevice?: boolean;
|
|
3768
|
+
}): Promise<string>;
|
|
3769
|
+
/** Bulk variant for owner dashboards. Gated by `view-user-auth`. */
|
|
3770
|
+
describeAllUsersAuth(vault: string, factors?: {
|
|
3771
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3772
|
+
sharedDevice?: boolean;
|
|
3773
|
+
}): Promise<Array<{
|
|
3774
|
+
userId: string;
|
|
3775
|
+
description: string;
|
|
3776
|
+
}>>;
|
|
3777
|
+
/**
|
|
3778
|
+
* Rotate the user's passphrase (user remembers old). Validates the
|
|
3779
|
+
* new phrase against the configured `passphrase` policy, runs the
|
|
3780
|
+
* `rotate-passphrase` gate, then re-derives + re-wraps every DEK.
|
|
3781
|
+
*
|
|
3782
|
+
* Tier-2 authenticator slots are dropped — each slot wraps the old
|
|
3783
|
+
* KEK and would need its derivation key to be re-presented. Re-enrol
|
|
3784
|
+
* via `db.enrollAuthenticator` after rotation. Tracked as a
|
|
3785
|
+
* v0.1.0-pre.5 limitation.
|
|
3786
|
+
*
|
|
3787
|
+
* @throws `WeakPassphraseError` on a weak new phrase.
|
|
3788
|
+
* @throws `PolicyDeniedError` when the gate denies (missing factor, …).
|
|
3789
|
+
* @throws `InvalidKeyError` when `oldPassphrase` is wrong.
|
|
3790
|
+
*/
|
|
3791
|
+
rotatePassphrase(vault: string, input: RotatePassphraseInput, factors?: {
|
|
3792
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3793
|
+
sharedDevice?: boolean;
|
|
3794
|
+
}): Promise<void>;
|
|
3795
|
+
/**
|
|
3796
|
+
* Reset the passphrase using a recovery proof (user forgot the old).
|
|
3797
|
+
* v0.1.0-pre.5 supports the `'paper'` profile end-to-end; the
|
|
3798
|
+
* other three profiles throw {@link RecoveryProfileNotImplementedError}.
|
|
3799
|
+
*
|
|
3800
|
+
* Burns the used recovery entry on success.
|
|
3801
|
+
*/
|
|
3802
|
+
recoverPassphrase(vault: string, input: RecoverPassphraseInput, factors?: {
|
|
3803
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3804
|
+
sharedDevice?: boolean;
|
|
3805
|
+
}): Promise<void>;
|
|
3806
|
+
/**
|
|
3807
|
+
* Persist a recovery enrollment. v0.1.0-pre.5 accepts the `'paper'`
|
|
3808
|
+
* profile — the developer first calls
|
|
3809
|
+
* `@noy-db/on-recovery/generateRecoveryCodeSet` to mint codes +
|
|
3810
|
+
* entries, shows the codes to the user once, then hands the entries
|
|
3811
|
+
* here.
|
|
3812
|
+
*
|
|
3813
|
+
* ```ts
|
|
3814
|
+
* import { generateRecoveryCodeSet } from '@noy-db/on-recovery'
|
|
3815
|
+
* const { codes, entries } = await generateRecoveryCodeSet({ kek, count: 10 })
|
|
3816
|
+
* await db.enrollRecovery('acme', { profile: 'paper', entries })
|
|
3817
|
+
* showCodesToUser(codes)
|
|
3818
|
+
* ```
|
|
3819
|
+
*/
|
|
3820
|
+
enrollRecovery(vault: string, enrollment: {
|
|
3821
|
+
profile: 'paper';
|
|
3822
|
+
entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
3823
|
+
}): Promise<void>;
|
|
3824
|
+
/** Read the persisted paper-recovery entries. Used by `describeAuthConfig` (#13). */
|
|
3825
|
+
listRecoveryEntries(vault: string): Promise<{
|
|
3826
|
+
paper: ReadonlyArray<PaperRecoveryEntry>;
|
|
3827
|
+
}>;
|
|
3828
|
+
/**
|
|
3829
|
+
* Register a tier-3 quick-unlock state for the vault. The state is
|
|
3830
|
+
* an opaque blob produced by `@noy-db/on-pin/enrollPin` (or any
|
|
3831
|
+
* compatible primitive). It is held in memory only — never persisted
|
|
3832
|
+
* — and auto-clears when its `expiresAt` elapses.
|
|
3833
|
+
*
|
|
3834
|
+
* Gated by `rotate-unlock` (the same gate covers "set" and "rotate"
|
|
3835
|
+
* because tier-3 is a single-slot rolling secret).
|
|
3836
|
+
*/
|
|
3837
|
+
enrollUnlock(vault: string, state: QuickUnlockState, presented?: {
|
|
3838
|
+
factors?: ReadonlyArray<FactorProof>;
|
|
3839
|
+
sharedDevice?: boolean;
|
|
3840
|
+
}): Promise<void>;
|
|
3841
|
+
/**
|
|
3842
|
+
* Resume a session via the registered tier-3 state. The verifier is
|
|
3843
|
+
* `@noy-db/on-pin/resumePin` (or compatible). On success, mark the
|
|
3844
|
+
* active session tier as 3 — every operation must re-authenticate at
|
|
3845
|
+
* tier 2 to elevate.
|
|
3846
|
+
*
|
|
3847
|
+
* Returns `undefined` (caller should fall back to tier 2) when no
|
|
3848
|
+
* tier-3 state is registered.
|
|
3849
|
+
*/
|
|
3850
|
+
unlockViaPin(vault: string, resume: (state: QuickUnlockState) => Promise<UnlockedKeyring>): Promise<UnlockedKeyring | undefined>;
|
|
3851
|
+
/** Drop the tier-3 state for a vault — explicit logout. */
|
|
3852
|
+
clearQuickUnlock(vault: string): void;
|
|
3116
3853
|
/** Get or load the keyring for a vault. */
|
|
3117
3854
|
private getKeyring;
|
|
3118
3855
|
}
|
|
@@ -4368,6 +5105,22 @@ declare class Vault {
|
|
|
4368
5105
|
* separate vault instances now.
|
|
4369
5106
|
*/
|
|
4370
5107
|
getBundleHandle(): Promise<string>;
|
|
5108
|
+
/**
|
|
5109
|
+
* Read the owner-curated public envelope for this vault (or
|
|
5110
|
+
* `undefined` if none is persisted). The envelope lives in
|
|
5111
|
+
* `_meta/public-envelope` as plaintext — readable without any KEK
|
|
5112
|
+
* — so `getBundleHandle`-style callers can label a vault before
|
|
5113
|
+
* unlock.
|
|
5114
|
+
*
|
|
5115
|
+
* Mirrors `Noydb.getPublicEnvelope(vault, opts)` but scoped to a
|
|
5116
|
+
* single, already-opened `Vault` instance so the
|
|
5117
|
+
* bundle writer can snapshot it without holding a `Noydb` reference.
|
|
5118
|
+
*
|
|
5119
|
+
* @see docs/subsystems/public-envelope.md
|
|
5120
|
+
*/
|
|
5121
|
+
getPublicEnvelope(opts?: {
|
|
5122
|
+
readonly locale?: string;
|
|
5123
|
+
}): Promise<PublicEnvelope | undefined>;
|
|
4371
5124
|
/**
|
|
4372
5125
|
* Dump vault as a verifiable encrypted JSON backup string.
|
|
4373
5126
|
*
|
|
@@ -6448,6 +7201,71 @@ interface ImportCapability {
|
|
|
6448
7201
|
readonly plaintext?: readonly ExportFormat[];
|
|
6449
7202
|
readonly bundle?: boolean;
|
|
6450
7203
|
}
|
|
7204
|
+
/**
|
|
7205
|
+
* Forward-declared on-disk shape for `VaultPolicy` — the actual policy
|
|
7206
|
+
* model lives in `policy/types.ts` (#9). Declared here as `unknown`-typed
|
|
7207
|
+
* map so types.ts has no dependency on the policy module while the
|
|
7208
|
+
* `KeyringFile.policy` field can still round-trip foreign documents.
|
|
7209
|
+
*
|
|
7210
|
+
* @internal
|
|
7211
|
+
*/
|
|
7212
|
+
type VaultPolicyOnDisk = Record<string, unknown>;
|
|
7213
|
+
/**
|
|
7214
|
+
* Recovery profile enrolled at vault creation (issue #10).
|
|
7215
|
+
*
|
|
7216
|
+
* - `paper` — `on-recovery` codes (the only end-to-end profile in v0.1.0-pre.5).
|
|
7217
|
+
* - `shamir` / `multi-channel` / `admin-mediated` — API surface ships;
|
|
7218
|
+
* per-profile dispatch lands in follow-up issues. Calling
|
|
7219
|
+
* `db.recoverPassphrase` against these throws
|
|
7220
|
+
* {@link RecoveryProfileNotImplementedError}.
|
|
7221
|
+
*/
|
|
7222
|
+
type RecoveryEnrollment = {
|
|
7223
|
+
readonly profile: 'paper';
|
|
7224
|
+
/** Number of single-use codes to print at enrollment. */
|
|
7225
|
+
readonly codes: number;
|
|
7226
|
+
} | {
|
|
7227
|
+
readonly profile: 'shamir';
|
|
7228
|
+
readonly k: number;
|
|
7229
|
+
readonly n: number;
|
|
7230
|
+
readonly trustees: ReadonlyArray<string>;
|
|
7231
|
+
} | {
|
|
7232
|
+
readonly profile: 'multi-channel';
|
|
7233
|
+
readonly email?: string;
|
|
7234
|
+
readonly pin?: boolean;
|
|
7235
|
+
readonly paperCodes?: number;
|
|
7236
|
+
} | {
|
|
7237
|
+
readonly profile: 'admin-mediated';
|
|
7238
|
+
readonly grantorUserId: string;
|
|
7239
|
+
};
|
|
7240
|
+
/**
|
|
7241
|
+
* One tier-2 authenticator slot inside a keyring file. Each slot
|
|
7242
|
+
* independently wraps the SAME KEK under a method-specific derived key
|
|
7243
|
+
* (LUKS pattern). Adding or removing a slot is a constant-time keyring
|
|
7244
|
+
* write — no DEK re-keying required.
|
|
7245
|
+
*
|
|
7246
|
+
* @see docs/subsystems/session-tiers.md → Tier 2 — Authenticate (multi-slot)
|
|
7247
|
+
*/
|
|
7248
|
+
interface KeyringAuthenticator {
|
|
7249
|
+
/** Caller-chosen identifier — e.g. `'webauthn-yubikey-blue'`, `'oidc-google'`, `'password-daily'`. */
|
|
7250
|
+
readonly id: string;
|
|
7251
|
+
/** Method family — selects which `@noy-db/on-*` package handles unlock. */
|
|
7252
|
+
readonly method: 'webauthn' | 'oidc' | 'password';
|
|
7253
|
+
/** ISO-8601 timestamp at which the slot was added. */
|
|
7254
|
+
readonly enrolled_at: string;
|
|
7255
|
+
/**
|
|
7256
|
+
* Which session tier ENROLLED this slot. Tier 1 enrolls a fresh slot;
|
|
7257
|
+
* tier 2 may add a sibling slot when the active policy permits.
|
|
7258
|
+
*/
|
|
7259
|
+
readonly enrolled_via_tier: 1 | 2;
|
|
7260
|
+
/** Base64 wrapped-KEK ciphertext under the method-derived key. */
|
|
7261
|
+
readonly wrapped_kek: string;
|
|
7262
|
+
/**
|
|
7263
|
+
* Method-specific metadata: WebAuthn cred id, OIDC issuer/sub, PBKDF2
|
|
7264
|
+
* salt for `on-password`, etc. The schema is open by design — the
|
|
7265
|
+
* `@noy-db/on-*` package owns the contents.
|
|
7266
|
+
*/
|
|
7267
|
+
readonly meta: Record<string, unknown>;
|
|
7268
|
+
}
|
|
6451
7269
|
interface KeyringFile {
|
|
6452
7270
|
readonly _noydb_keyring: typeof NOYDB_KEYRING_VERSION;
|
|
6453
7271
|
readonly user_id: string;
|
|
@@ -6458,6 +7276,23 @@ interface KeyringFile {
|
|
|
6458
7276
|
readonly salt: string;
|
|
6459
7277
|
readonly created_at: string;
|
|
6460
7278
|
readonly granted_by: string;
|
|
7279
|
+
/**
|
|
7280
|
+
* Tier-2 authenticator slots (multi-slot keyring extension).
|
|
7281
|
+
* Optional / append-only: keyring files written before the
|
|
7282
|
+
* extension load with an empty list. Each slot independently wraps
|
|
7283
|
+
* the same KEK; any one of them unlocks.
|
|
7284
|
+
*
|
|
7285
|
+
* @see KeyringAuthenticator
|
|
7286
|
+
*/
|
|
7287
|
+
readonly authenticators?: readonly KeyringAuthenticator[];
|
|
7288
|
+
/**
|
|
7289
|
+
* Per-keyring policy override (reserved). The on-disk format
|
|
7290
|
+
* accepts the field for forward compatibility with the Option C
|
|
7291
|
+
* merge engine deferred to a later release; v1.0 reads only the
|
|
7292
|
+
* vault-level `_meta/policy` document, so this field is parsed and
|
|
7293
|
+
* round-tripped but never enforced.
|
|
7294
|
+
*/
|
|
7295
|
+
readonly policy?: VaultPolicyOnDisk;
|
|
6461
7296
|
/**
|
|
6462
7297
|
* Optional — authorization spec capability bits. Absent on keyrings written
|
|
6463
7298
|
* before the RFC implementation. Loading falls back to role-based
|
|
@@ -6812,6 +7647,12 @@ interface GrantOptions {
|
|
|
6812
7647
|
* is grantable until positively listed; bundle import is denied.
|
|
6813
7648
|
*/
|
|
6814
7649
|
readonly importCapability?: ImportCapability;
|
|
7650
|
+
/**
|
|
7651
|
+
* Skip phrase-format strength validation (issue #7). Defaults to
|
|
7652
|
+
* false — `grant()` rejects phrases that don't meet the configured
|
|
7653
|
+
* `PassphrasePolicy`. Test fixtures and CLI scripts pass `true`.
|
|
7654
|
+
*/
|
|
7655
|
+
readonly allowWeakPassphrase?: boolean;
|
|
6815
7656
|
}
|
|
6816
7657
|
interface RevokeOptions {
|
|
6817
7658
|
readonly userId: string;
|
|
@@ -7385,8 +8226,47 @@ interface NoydbOptions {
|
|
|
7385
8226
|
readonly sync?: NoydbStore | SyncTarget | SyncTarget[];
|
|
7386
8227
|
/** User identifier. */
|
|
7387
8228
|
readonly user: string;
|
|
7388
|
-
/** Passphrase for key derivation. Required unless encrypt is false. */
|
|
8229
|
+
/** Passphrase for key derivation. Required unless encrypt is false or `getKeyring` is provided. */
|
|
7389
8230
|
readonly secret?: string;
|
|
8231
|
+
/**
|
|
8232
|
+
* Optional callback that returns an unlocked keyring for a given vault.
|
|
8233
|
+
* Use this to plug in WebAuthn / OIDC / Shamir / any unlock path that
|
|
8234
|
+
* produces an `UnlockedKeyring` outside the passphrase model.
|
|
8235
|
+
*
|
|
8236
|
+
* When set, `secret` MUST NOT also be set — `createNoydb` throws if both
|
|
8237
|
+
* are supplied. When neither is set (and `encrypt !== false`), `createNoydb`
|
|
8238
|
+
* also throws.
|
|
8239
|
+
*
|
|
8240
|
+
* The callback is called lazily, on the first operation that needs the
|
|
8241
|
+
* keyring for a given vault. Noydb caches the returned keyring per-vault
|
|
8242
|
+
* for the lifetime of the instance, so the callback is invoked at most
|
|
8243
|
+
* once per `(instance, vault)` pair (assuming the callback resolves
|
|
8244
|
+
* successfully). If the callback rejects, the rejection surfaces from the
|
|
8245
|
+
* first vault operation that triggered the unlock; subsequent operations
|
|
8246
|
+
* will retry the callback.
|
|
8247
|
+
*
|
|
8248
|
+
* @example
|
|
8249
|
+
* ```ts
|
|
8250
|
+
* import { createNoydb } from '@noy-db/hub'
|
|
8251
|
+
* import { unlockWebAuthn } from '@noy-db/on-webauthn'
|
|
8252
|
+
*
|
|
8253
|
+
* const enrollment = await loadEnrollment()
|
|
8254
|
+
* const db = await createNoydb({
|
|
8255
|
+
* store,
|
|
8256
|
+
* user: 'alice',
|
|
8257
|
+
* getKeyring: (vault) => unlockWebAuthn(enrollment),
|
|
8258
|
+
* })
|
|
8259
|
+
* ```
|
|
8260
|
+
*
|
|
8261
|
+
* Note: this callback is responsible for both the "open existing vault"
|
|
8262
|
+
* and the "create new vault" cases. Unlike the passphrase path, there is
|
|
8263
|
+
* no automatic `NoAccessError` → `createOwnerKeyring` fallback, because
|
|
8264
|
+
* the callback owner has the UI context to decide which path to run.
|
|
8265
|
+
* For first-time bootstrap, use a passphrase or recovery code, enroll
|
|
8266
|
+
* WebAuthn from the unlocked keyring, then swap to `getKeyring` on
|
|
8267
|
+
* subsequent sessions.
|
|
8268
|
+
*/
|
|
8269
|
+
readonly getKeyring?: (vault: string) => Promise<UnlockedKeyring>;
|
|
7390
8270
|
/** Auth method. Default: 'passphrase'. */
|
|
7391
8271
|
readonly auth?: 'passphrase' | 'biometric';
|
|
7392
8272
|
/** Enable encryption. Default: true. */
|
|
@@ -7421,8 +8301,59 @@ interface NoydbOptions {
|
|
|
7421
8301
|
* legacy `sessionTimeout` field.
|
|
7422
8302
|
*/
|
|
7423
8303
|
readonly sessionPolicy?: SessionPolicy;
|
|
7424
|
-
/**
|
|
8304
|
+
/**
|
|
8305
|
+
* Validate passphrase strength against the phrase format
|
|
8306
|
+
* (`@noy-db/hub` issue #7) on first-time keyring creation. When
|
|
8307
|
+
* `true`, weak phrases throw {@link WeakPassphraseError} from
|
|
8308
|
+
* `createNoydb()` / `db.rotatePassphrase()`. Default: `false` for
|
|
8309
|
+
* back-compat in v0.1.x; planned to flip to `true` at v1.0.
|
|
8310
|
+
*/
|
|
7425
8311
|
readonly validatePassphrase?: boolean;
|
|
8312
|
+
/**
|
|
8313
|
+
* Vault-level policy gate document (issue #9). When present, the hub
|
|
8314
|
+
* persists the merged policy at `_meta/policy` on first-time vault
|
|
8315
|
+
* creation and gates sensitive operations (`db.rotatePassphrase`,
|
|
8316
|
+
* `db.export*`, …) against it. Omitted ⇒ the engine uses
|
|
8317
|
+
* {@link PERSONAL_POLICY}. Use {@link STRICT_POLICY} for regulated
|
|
8318
|
+
* deployments.
|
|
8319
|
+
*
|
|
8320
|
+
* The on-disk document is the source of truth — the policy field
|
|
8321
|
+
* is only honored at vault creation; subsequent runs read from
|
|
8322
|
+
* `_meta/policy`. Use `db.updatePolicy()` to change it deliberately.
|
|
8323
|
+
*
|
|
8324
|
+
* Imported from `@noy-db/hub` as a type-only reference; the runtime
|
|
8325
|
+
* import lives in `policy/index.ts`.
|
|
8326
|
+
*/
|
|
8327
|
+
readonly policy?: VaultPolicy;
|
|
8328
|
+
/**
|
|
8329
|
+
* Mandatory recovery profile enrollment (issue #10). Vaults with
|
|
8330
|
+
* `recover-passphrase` enabled MUST register at least one profile
|
|
8331
|
+
* before being production-ready, otherwise `createNoydb()` throws
|
|
8332
|
+
* {@link RecoveryNotEnrolledError}. Set
|
|
8333
|
+
* `policy.gates['recover-passphrase'].enabled = false` to
|
|
8334
|
+
* deliberately opt out of recovery (passphrase loss = data loss).
|
|
8335
|
+
*
|
|
8336
|
+
* v0.1.0-pre.5 supports the `'paper'` profile end-to-end. Other
|
|
8337
|
+
* profiles ship the API shape and throw
|
|
8338
|
+
* {@link RecoveryProfileNotImplementedError} during use.
|
|
8339
|
+
*/
|
|
8340
|
+
readonly recovery?: ReadonlyArray<RecoveryEnrollment>;
|
|
8341
|
+
/**
|
|
8342
|
+
* When `true`, `createNoydb` rejects vaults with no recovery
|
|
8343
|
+
* entries persisted (per the spec's mandatory-enrollment
|
|
8344
|
+
* requirement). Default `false` for v0.1.x back-compat; planned to
|
|
8345
|
+
* flip to `true` at v1.0. Apps in regulated environments should
|
|
8346
|
+
* turn this on now.
|
|
8347
|
+
*/
|
|
8348
|
+
readonly requireRecovery?: boolean;
|
|
8349
|
+
/**
|
|
8350
|
+
* Enable the public envelope subsystem (`docs/subsystems/public-envelope.md`).
|
|
8351
|
+
* Pass `true` for the default schema (every standard field, 256 KB
|
|
8352
|
+
* icon cap, 200-char text cap), or a `PublicEnvelopeSchema` to
|
|
8353
|
+
* narrow what the owner can set. Off by default — vaults written
|
|
8354
|
+
* by hubs without this option carry no envelope, full stop.
|
|
8355
|
+
*/
|
|
8356
|
+
readonly publicEnvelope?: true | PublicEnvelopeSchema;
|
|
7426
8357
|
/** Audit history configuration. */
|
|
7427
8358
|
readonly history?: HistoryConfig;
|
|
7428
8359
|
/**
|
|
@@ -7523,4 +8454,4 @@ interface DeleteManyResult {
|
|
|
7523
8454
|
}>;
|
|
7524
8455
|
}
|
|
7525
8456
|
|
|
7526
|
-
export { type ConsentAuditEntry as $, type BlobObject as A, type BlobStrategy as B, type BlobPutOptions as C, DICT_COLLECTION_PREFIX as D, type BlobResponseOptions as E, BlobSet as F, type BlobStrategyOpenArgs as G, type CompactRunOptions as H, type I18nStrategy as I, type CompactionContext as J, type CompactionResult as K, DEFAULT_CHUNK_SIZE as L, EXPORT_AUDIT_COLLECTION as M, ExportBlobsAbortedError as N, type ExportBlobsAuditEntry as O, PolicyEnforcer as P, type ExportBlobsHandle as Q, type ExportBlobsOptions as R, type SessionStrategy as S, type ExportedBlob as T, type SlotInfo as U, type SlotRecord as V, type VersionRecord as W, createExportBlobsHandle as X, runCompaction as Y, type ConsentStrategy as Z, CONSENT_AUDIT_COLLECTION as _, type DictEntry as a, type
|
|
8457
|
+
export { type ConsentAuditEntry as $, type BlobObject as A, type BlobStrategy as B, type BlobPutOptions as C, DICT_COLLECTION_PREFIX as D, type BlobResponseOptions as E, BlobSet as F, type BlobStrategyOpenArgs as G, type CompactRunOptions as H, type I18nStrategy as I, type CompactionContext as J, type CompactionResult as K, DEFAULT_CHUNK_SIZE as L, EXPORT_AUDIT_COLLECTION as M, ExportBlobsAbortedError as N, type ExportBlobsAuditEntry as O, PolicyEnforcer as P, type ExportBlobsHandle as Q, type ExportBlobsOptions as R, type SessionStrategy as S, type ExportedBlob as T, type SlotInfo as U, type SlotRecord as V, type VersionRecord as W, createExportBlobsHandle as X, runCompaction as Y, type ConsentStrategy as Z, CONSENT_AUDIT_COLLECTION as _, type DictEntry as a, type BundleRecipient as a$, type ConsentAuditFilter as a0, type ConsentContext as a1, type ConsentOp as a2, loadConsentEntries as a3, writeConsentEntry as a4, type PeriodsStrategy as a5, type CarryForwardContext as a6, type ClosePeriodOptions as a7, type OpenPeriodOptions as a8, PERIODS_COLLECTION as a9, type DiffEntry as aA, type JsonPatch as aB, type JsonPatchOp as aC, type LedgerEntry as aD, LedgerStore as aE, type VaultEngine as aF, VaultInstant as aG, type VerifyResult as aH, applyPatch as aI, canonicalJson as aJ, computePatch as aK, diff as aL, formatDiff as aM, hashEntry as aN, paddedIndex as aO, parseIndex as aP, sha256Hex as aQ, type PublicEnvelope as aR, type GateName as aS, type GatePolicy as aT, type VaultPolicy as aU, type ActiveTier as aV, type FactorProof as aW, Vault as aX, type AccessibleVault as aY, BUNDLE_STORE_POLICY as aZ, type BuiltInGateName as a_, type PeriodRecord as aa, type ReadOnlyCollection as ab, appendPeriodLedgerEntry as ac, assertTsWritable as ad, chainAnchor as ae, loadPeriods as af, validatePeriodName as ag, type ShadowStrategy as ah, CollectionFrame as ai, VaultFrame as aj, type TxStrategy as ak, TxCollection as al, TxContext as am, TxVault as an, runTransaction as ao, type SyncStrategy as ap, type Role as aq, type UnlockedKeyring as ar, type HistoryStrategy as as, type NoydbStore as at, type HistoryOptions as au, type EncryptedEnvelope as av, type PruneOptions as aw, type AppendInput as ax, type ChangeType as ay, CollectionInstant as az, type DictKeyDescriptor as b, PresenceHandle as b$, type CacheOptions as b0, type CacheStats as b1, type ChangeEvent as b2, Collection as b3, type CollectionChangeEvent as b4, type CollectionConflictResolver as b5, type Conflict as b6, type ConflictPolicy as b7, type ConflictStrategy as b8, type CrossTierAccessEvent as b9, type ListPageResult as bA, type LocaleReadOptions as bB, Lru as bC, type LruOptions as bD, type LruStats as bE, MAGIC_LINK_CONTENT_INFO_PREFIX as bF, MAGIC_LINK_GRANTS_COLLECTION as bG, MAGIC_LINK_KEK_INFO_PREFIX as bH, type MagicLinkGrantPayload as bI, type MagicLinkGrantRecord as bJ, NOYDB_BACKUP_VERSION as bK, NOYDB_FORMAT_VERSION as bL, NOYDB_KEYRING_VERSION as bM, NOYDB_SYNC_VERSION as bN, Noydb as bO, type NoydbBundleStore as bP, type NoydbEventMap as bQ, type NoydbOptions as bR, PUBLIC_ENVELOPE_FIELDS as bS, type PaperRecoveryDoc as bT, type PaperRecoveryEntry as bU, type PassphrasePolicy as bV, type PassphraseValidationResult as bW, type Permission as bX, type Permissions as bY, type PlaintextTranslatorContext as bZ, type PlaintextTranslatorFn as b_, DEFAULT_PUBLIC_ENVELOPE_SCHEMA as ba, DELEGATIONS_COLLECTION as bb, type DelegationToken as bc, type DeleteManyResult as bd, type DirtyEntry as be, ELEVATION_AUDIT_COLLECTION as bf, ElevatedHandle as bg, type EnrollAuthenticatorOptions as bh, type ExportCapability as bi, type ExportChunk as bj, type ExportFormat as bk, type ExportStreamOptions as bl, type FactorKind as bm, type FactorRequirement as bn, type GhostRecord as bo, type GrantOptions as bp, type HistoryConfig as bq, type HistoryEntry as br, INDEXED_STORE_POLICY as bs, type ImportCapability as bt, type InferOutput as bu, type IssueDelegationOptions as bv, type IssueMagicLinkGrantOptions as bw, type KeyringAuthenticator as bx, type KeyringFile as by, type ListAccessibleVaultsOptions as bz, DictionaryHandle as c, findAuthenticator as c$, type PresencePeer as c0, type PublicEnvelopeField as c1, type PublicEnvelopeSchema as c2, type PublicEnvelopeText as c3, type PullMode as c4, type PullOptions as c5, type PullPolicy as c6, type PullResult as c7, type PushMode as c8, type PushOptions as c9, SyncScheduler as cA, type SyncSchedulerStatus as cB, type SyncStatus as cC, type SyncTarget as cD, type SyncTargetRole as cE, SyncTransaction as cF, type SyncTransactionResult as cG, type TierMode as cH, type TranslatorAuditEntry as cI, type TxOp as cJ, type UserInfo as cK, type VaultBackup as cL, type VaultPolicyOnDisk as cM, type VaultSnapshot as cN, type WarningRules as cO, WeakPassphraseError as cP, type WeakPassphraseReason as cQ, assertStrongPassphrase as cR, buildRecipientKeyringFile as cS, burnPaperRecoveryEntry as cT, createNoydb as cU, createStore as cV, deriveMagicLinkContentKey as cW, enrollAuthenticator as cX, estimateEntropy as cY, evaluateExportCapability as cZ, evaluateImportCapability as c_, type PushPolicy as ca, type PushResult as cb, type PutManyItemOptions as cc, type PutManyOptions as cd, type PutManyResult as ce, type QueryAcrossOptions as cf, type QueryAcrossResult as cg, type QuickUnlockState as ch, QuickUnlockStore as ci, type ReAuthOperation as cj, type RecoverPassphraseInput as ck, type RecoveryProof as cl, type ResolvedPublicEnvelopeSchema as cm, type RevokeOptions as cn, type RotatePassphraseInput as co, type SessionPolicy as cp, type SetPublicEnvelopeInput as cq, type StandardSchemaV1 as cr, type StandardSchemaV1Issue as cs, type StandardSchemaV1SyncResult as ct, type StoreAuth as cu, type StoreAuthKind as cv, type StoreCapabilities as cw, SyncEngine as cx, type SyncMetadata as cy, type SyncPolicy as cz, type DictionaryOptions as d, hasExportCapability as d0, hasImportCapability as d1, hasRecoveryEnrolled as d2, isMagicLinkGrantExpired as d3, isPublicEnvelope as d4, issueDelegation as d5, recoverPassphrase as d6, rotatePassphrase as d7, listMagicLinkGrants as d8, loadActiveDelegations as d9, loadPaperRecoveryEntries as da, magicLinkGrantRecordId as db, readMagicLinkGrantRecord as dc, removeAuthenticator as dd, resolveSchema as de, revokeDelegation as df, revokeMagicLinkGrant as dg, savePaperRecoveryEntries as dh, unwrapMagicLinkGrant as di, validatePassphrase as dj, validatePublicEnvelopeInput as dk, validateSchemaInput as dl, validateSchemaOutput as dm, writeMagicLinkGrant as dn, type I18nTextDescriptor as e, type I18nTextOptions as f, applyI18nLocale as g, dictCollectionName as h, dictKey as i, i18nText as j, isDictCollectionName as k, isDictKeyDescriptor as l, isI18nTextDescriptor as m, createEnforcer as n, validateSessionPolicy as o, BLOB_CHUNKS_COLLECTION as p, BLOB_COLLECTION as q, resolveI18nText as r, BLOB_EVICTION_AUDIT_COLLECTION as s, BLOB_INDEX_COLLECTION as t, BLOB_SLOTS_PREFIX as u, validateI18nTextValue as v, BLOB_VERSIONS_PREFIX as w, type BlobEvictionEntry as x, type BlobFieldPolicy as y, type BlobFieldsConfig as z };
|