@noy-db/hub 0.1.0-pre.14 → 0.1.0-pre.16
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/aggregate/index.cjs +91 -36
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +2 -2
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/aggregate/index.js +15 -8
- package/dist/aggregate/index.js.map +1 -1
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +5 -4
- package/dist/blobs/index.d.ts +5 -4
- package/dist/blobs/index.js +4 -4
- package/dist/bundle/index.cjs +214 -7
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +5 -4
- package/dist/bundle/index.d.ts +5 -4
- package/dist/bundle/index.js +6 -4
- package/dist/{chunk-CX2S2IBB.js → chunk-23TTQXVO.js} +53 -79
- package/dist/chunk-23TTQXVO.js.map +1 -0
- package/dist/{chunk-WLZWITX3.js → chunk-2AXFIYHT.js} +1 -1
- package/dist/chunk-2AXFIYHT.js.map +1 -0
- package/dist/{chunk-SBOSKCXD.js → chunk-2R6G2WST.js} +209 -13
- package/dist/chunk-2R6G2WST.js.map +1 -0
- package/dist/{chunk-HENWE2QQ.js → chunk-34YSDCDP.js} +2 -2
- package/dist/{chunk-3J5PYYUL.js → chunk-5DWL3JBF.js} +2 -2
- package/dist/{chunk-562AT3V6.js → chunk-5NGHX6ME.js} +5 -5
- package/dist/chunk-5ZGZ6HIZ.js +100 -0
- package/dist/chunk-5ZGZ6HIZ.js.map +1 -0
- package/dist/{chunk-ZJICDHNH.js → chunk-6HPZY4ON.js} +5 -4
- package/dist/chunk-6HPZY4ON.js.map +1 -0
- package/dist/{chunk-LTKFPLTW.js → chunk-A3K2ECAM.js} +192 -11
- package/dist/chunk-A3K2ECAM.js.map +1 -0
- package/dist/{chunk-W7M3E5M5.js → chunk-ADQ5MQ54.js} +48 -1
- package/dist/{chunk-W7M3E5M5.js.map → chunk-ADQ5MQ54.js.map} +1 -1
- package/dist/{chunk-Q3OWJPJI.js → chunk-DPMFBCV6.js} +32 -19
- package/dist/chunk-DPMFBCV6.js.map +1 -0
- package/dist/{chunk-AD4FMCXZ.js → chunk-DYBQG5PQ.js} +2 -2
- package/dist/{chunk-PNTWORBA.js → chunk-DYECX3IX.js} +2 -2
- package/dist/chunk-EGQYGYIU.js +51 -0
- package/dist/chunk-EGQYGYIU.js.map +1 -0
- package/dist/{chunk-RGHN6WV7.js → chunk-FCXOFQAJ.js} +2 -2
- package/dist/{chunk-PMMNH7VZ.js → chunk-H7XROQJM.js} +1 -1
- package/dist/chunk-H7XROQJM.js.map +1 -0
- package/dist/chunk-HB3Z2GCR.js +124 -0
- package/dist/chunk-HB3Z2GCR.js.map +1 -0
- package/dist/{chunk-CRNMA2FB.js → chunk-I6MX32UC.js} +4 -4
- package/dist/{chunk-PHSGPPV7.js → chunk-KESP7GOK.js} +3 -3
- package/dist/{chunk-FB34MDSJ.js → chunk-KJJKHKFP.js} +4 -4
- package/dist/{chunk-J3E2UMET.js → chunk-MIQHZESA.js} +3 -3
- package/dist/{chunk-TNYWH7Z2.js → chunk-MKSA2V7A.js} +2 -2
- package/dist/{chunk-E4ZSYZSN.js → chunk-NVBUGT76.js} +4 -4
- package/dist/{chunk-XFVOTOYQ.js → chunk-O4RHR7FV.js} +6 -6
- package/dist/{chunk-EEEFQTYN.js → chunk-OMLIZL2P.js} +2 -2
- package/dist/{chunk-GVPFL6XF.js → chunk-P7EQ2S5O.js} +2 -2
- package/dist/{chunk-E3VAKWJ7.js → chunk-QQUUAXDY.js} +7 -6
- package/dist/chunk-QQUUAXDY.js.map +1 -0
- package/dist/chunk-RD5LYKD6.js +82 -0
- package/dist/chunk-RD5LYKD6.js.map +1 -0
- package/dist/{chunk-7QGJ7RTL.js → chunk-RRMDLTIL.js} +4 -4
- package/dist/{chunk-432R4RDC.js → chunk-SIZWEV2Y.js} +35 -5
- package/dist/chunk-SIZWEV2Y.js.map +1 -0
- package/dist/{chunk-U7YDBNFC.js → chunk-UZXLQCHP.js} +2 -2
- package/dist/{chunk-PPJA7KL6.js → chunk-V6SGP2KX.js} +3 -3
- package/dist/{chunk-7AQKLLI5.js → chunk-WCA2NROQ.js} +2 -2
- package/dist/{chunk-ERV4AXVO.js → chunk-XGSOTWYX.js} +90 -131
- package/dist/chunk-XGSOTWYX.js.map +1 -0
- package/dist/{chunk-5Y4AKEZ6.js → chunk-Z72JH4KG.js} +2 -2
- package/dist/{chunk-IXFP66OV.js → chunk-ZNOEIM6Y.js} +2 -2
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +5 -4
- package/dist/consent/index.d.ts +5 -4
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-VTEMMJK6.js → crypto-A7FRXYHC.js} +3 -3
- package/dist/{delegation-HYQULPZR.js → delegation-YBA4X4JN.js} +5 -5
- package/dist/derivations/index.cjs +97 -1
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +37 -10
- package/dist/derivations/index.d.ts +37 -10
- package/dist/derivations/index.js +6 -4
- package/dist/{dev-unlock-CpJ9rHW2.d.ts → dev-unlock-C8u6MRfS.d.ts} +1 -1
- package/dist/{dev-unlock-DEUUpWoR.d.cts → dev-unlock-gBjwzB6A.d.cts} +1 -1
- package/dist/executor-7E3VFGW7.js +11 -0
- package/dist/executor-CEWX2FQI.js +8 -0
- package/dist/executor-X4SQ3ZLC.js +8 -0
- package/dist/fanout-sidecar-ACJNXFU6.js +51 -0
- package/dist/fanout-sidecar-ACJNXFU6.js.map +1 -0
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +6 -5
- package/dist/guards/index.d.ts +6 -5
- package/dist/guards/index.js +6 -6
- package/dist/{hash-_9VyW44M.d.cts → hash-BXy5DuTD.d.cts} +1 -1
- package/dist/{hash-CJ9LfuY5.d.ts → hash-C6KOPK9Q.d.ts} +1 -1
- package/dist/history/index.cjs +2 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +6 -5
- package/dist/history/index.d.ts +6 -5
- package/dist/history/index.js +6 -6
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +5 -4
- package/dist/i18n/index.d.ts +5 -4
- package/dist/i18n/index.js +6 -6
- package/dist/{index-s31g3m-D.d.cts → index-BA7A-MJs.d.cts} +96 -4
- package/dist/{index-BWAXR9tV.d.ts → index-CLK67MZE.d.ts} +96 -4
- package/dist/{index-7nd15fgy.d.ts → index-CNwA-B6-.d.ts} +70 -2
- package/dist/{index-CFJKJXWa.d.cts → index-CmVgTkqk.d.cts} +70 -2
- package/dist/index.cjs +2400 -571
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +128 -18
- package/dist/index.d.ts +128 -18
- package/dist/index.js +1217 -107
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs.map +1 -1
- package/dist/indexing/index.js +2 -2
- package/dist/{ledger-LHLIVPJ3.js → ledger-GHIZQLKR.js} +6 -6
- package/dist/materialized-views/index.cjs +255 -21
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +7 -6
- package/dist/materialized-views/index.d.ts +7 -6
- package/dist/materialized-views/index.js +9 -5
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +6 -5
- package/dist/overlay-views/index.d.ts +6 -5
- package/dist/overlay-views/index.js +3 -3
- package/dist/periods/index.cjs +2 -1
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +5 -4
- package/dist/periods/index.d.ts +5 -4
- package/dist/periods/index.js +6 -6
- package/dist/{public-envelope-66ZBXVXK.js → public-envelope-CRJAVW3E.js} +4 -4
- package/dist/query/index.cjs +139 -113
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +13 -9
- package/dist/{registry-JYALMHGM.js → registry-3L3N3PTG.js} +3 -3
- package/dist/registry-O47PUPSY.js +8 -0
- package/dist/registry-WLLMODKN.js +8 -0
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +6 -5
- package/dist/session/index.d.ts +6 -5
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +5 -4
- package/dist/shadow/index.d.ts +5 -4
- package/dist/shadow/index.js +2 -2
- package/dist/{stale-EET5YFYL.js → stale-HSC5YO2O.js} +2 -2
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +5 -4
- package/dist/store/index.d.ts +5 -4
- package/dist/store/index.js +2 -2
- package/dist/{strategy-D-SrOLCl.d.cts → strategy-DSTrsZ8t.d.cts} +72 -19
- package/dist/{strategy-D-SrOLCl.d.ts → strategy-DSTrsZ8t.d.ts} +72 -19
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +4 -3
- package/dist/sync/index.d.ts +4 -3
- package/dist/sync/index.js +4 -4
- package/dist/team/index.cjs +136 -6
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +5 -4
- package/dist/team/index.d.ts +5 -4
- package/dist/team/index.js +7 -7
- package/dist/tx/index.cjs +2 -1
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +5 -4
- package/dist/tx/index.d.ts +5 -4
- package/dist/tx/index.js +2 -2
- package/dist/{types-2JGVRzO2.d.cts → types-DDy02bWN.d.cts} +1159 -257
- package/dist/{types-DIOLYPUq.d.ts → types-DImsOlJe.d.ts} +1159 -257
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.js +1 -1
- package/dist/{with-derivation-ClhfQvRa.d.ts → with-derivation-3AdLeSw8.d.ts} +1 -1
- package/dist/{with-derivation-3JX8SMxY.d.cts → with-derivation-CkCHx_J8.d.cts} +1 -1
- package/dist/{with-guard-Br3YPxRW.d.ts → with-guard-Br9zLEdi.d.ts} +1 -1
- package/dist/{with-guard-fJVfWBLs.d.cts → with-guard-DtKsFExw.d.cts} +1 -1
- package/dist/with-materialized-view-CMhEX4FK.d.cts +27 -0
- package/dist/with-materialized-view-Zal2bE1T.d.ts +27 -0
- package/dist/{with-overlayed-view-BLUKxdiJ.d.cts → with-overlayed-view-CA6zHrBt.d.cts} +1 -1
- package/dist/{with-overlayed-view-CtvJxhU3.d.ts → with-overlayed-view-R4BNG9OB.d.ts} +1 -1
- package/package.json +14 -2
- package/dist/chunk-432R4RDC.js.map +0 -1
- package/dist/chunk-CX2S2IBB.js.map +0 -1
- package/dist/chunk-E3VAKWJ7.js.map +0 -1
- package/dist/chunk-ERV4AXVO.js.map +0 -1
- package/dist/chunk-GV47JHIF.js +0 -29
- package/dist/chunk-GV47JHIF.js.map +0 -1
- package/dist/chunk-LTKFPLTW.js.map +0 -1
- package/dist/chunk-PMMNH7VZ.js.map +0 -1
- package/dist/chunk-Q2L5ZYX7.js +0 -66
- package/dist/chunk-Q2L5ZYX7.js.map +0 -1
- package/dist/chunk-Q3OWJPJI.js.map +0 -1
- package/dist/chunk-SBK6CETA.js +0 -30
- package/dist/chunk-SBK6CETA.js.map +0 -1
- package/dist/chunk-SBOSKCXD.js.map +0 -1
- package/dist/chunk-WLZWITX3.js.map +0 -1
- package/dist/chunk-ZJICDHNH.js.map +0 -1
- package/dist/executor-3H3NSIVZ.js +0 -8
- package/dist/executor-7ZOXGY7P.js +0 -8
- package/dist/executor-A5LTUAG2.js +0 -9
- package/dist/registry-J2UI37XJ.js +0 -8
- package/dist/registry-UMAL72WL.js +0 -8
- package/dist/with-materialized-view-CHho83hN.d.cts +0 -15
- package/dist/with-materialized-view-CgPphnza.d.ts +0 -15
- /package/dist/{chunk-HENWE2QQ.js.map → chunk-34YSDCDP.js.map} +0 -0
- /package/dist/{chunk-3J5PYYUL.js.map → chunk-5DWL3JBF.js.map} +0 -0
- /package/dist/{chunk-562AT3V6.js.map → chunk-5NGHX6ME.js.map} +0 -0
- /package/dist/{chunk-AD4FMCXZ.js.map → chunk-DYBQG5PQ.js.map} +0 -0
- /package/dist/{chunk-PNTWORBA.js.map → chunk-DYECX3IX.js.map} +0 -0
- /package/dist/{chunk-RGHN6WV7.js.map → chunk-FCXOFQAJ.js.map} +0 -0
- /package/dist/{chunk-CRNMA2FB.js.map → chunk-I6MX32UC.js.map} +0 -0
- /package/dist/{chunk-PHSGPPV7.js.map → chunk-KESP7GOK.js.map} +0 -0
- /package/dist/{chunk-FB34MDSJ.js.map → chunk-KJJKHKFP.js.map} +0 -0
- /package/dist/{chunk-J3E2UMET.js.map → chunk-MIQHZESA.js.map} +0 -0
- /package/dist/{chunk-TNYWH7Z2.js.map → chunk-MKSA2V7A.js.map} +0 -0
- /package/dist/{chunk-E4ZSYZSN.js.map → chunk-NVBUGT76.js.map} +0 -0
- /package/dist/{chunk-XFVOTOYQ.js.map → chunk-O4RHR7FV.js.map} +0 -0
- /package/dist/{chunk-EEEFQTYN.js.map → chunk-OMLIZL2P.js.map} +0 -0
- /package/dist/{chunk-GVPFL6XF.js.map → chunk-P7EQ2S5O.js.map} +0 -0
- /package/dist/{chunk-7QGJ7RTL.js.map → chunk-RRMDLTIL.js.map} +0 -0
- /package/dist/{chunk-U7YDBNFC.js.map → chunk-UZXLQCHP.js.map} +0 -0
- /package/dist/{chunk-PPJA7KL6.js.map → chunk-V6SGP2KX.js.map} +0 -0
- /package/dist/{chunk-7AQKLLI5.js.map → chunk-WCA2NROQ.js.map} +0 -0
- /package/dist/{chunk-5Y4AKEZ6.js.map → chunk-Z72JH4KG.js.map} +0 -0
- /package/dist/{chunk-IXFP66OV.js.map → chunk-ZNOEIM6Y.js.map} +0 -0
- /package/dist/{crypto-VTEMMJK6.js.map → crypto-A7FRXYHC.js.map} +0 -0
- /package/dist/{delegation-HYQULPZR.js.map → delegation-YBA4X4JN.js.map} +0 -0
- /package/dist/{executor-3H3NSIVZ.js.map → executor-7E3VFGW7.js.map} +0 -0
- /package/dist/{executor-7ZOXGY7P.js.map → executor-CEWX2FQI.js.map} +0 -0
- /package/dist/{executor-A5LTUAG2.js.map → executor-X4SQ3ZLC.js.map} +0 -0
- /package/dist/{ledger-LHLIVPJ3.js.map → ledger-GHIZQLKR.js.map} +0 -0
- /package/dist/{public-envelope-66ZBXVXK.js.map → public-envelope-CRJAVW3E.js.map} +0 -0
- /package/dist/{registry-J2UI37XJ.js.map → registry-3L3N3PTG.js.map} +0 -0
- /package/dist/{registry-JYALMHGM.js.map → registry-O47PUPSY.js.map} +0 -0
- /package/dist/{registry-UMAL72WL.js.map → registry-WLLMODKN.js.map} +0 -0
- /package/dist/{stale-EET5YFYL.js.map → stale-HSC5YO2O.js.map} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { I as IndexStrategy, d as LazyQuery } from './lazy-builder-Rpd-V3jP.js';
|
|
2
|
-
import { A as AggregateStrategy } from './strategy-
|
|
2
|
+
import { b as AggregateSpec, A as AggregateStrategy } from './strategy-DSTrsZ8t.js';
|
|
3
3
|
import { C as CrdtStrategy, a as CrdtMode, b as CrdtState } from './strategy-BSxFXGzb.js';
|
|
4
|
-
import { N as NoydbError, Q as Query,
|
|
4
|
+
import { N as NoydbError, Q as Query, ak as RefRegistry, ah as RefDescriptor, _ as JoinableSource, am as RefViolation, an as ScanBuilder } from './index-CNwA-B6-.js';
|
|
5
5
|
import { F as FieldClause, I as IndexDef, C as CollectionIndexes } from './predicate-Dnu81tsS.js';
|
|
6
|
+
import { RawShare } from '@noy-db/on-shamir';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Standard Schema v1 integration.
|
|
@@ -819,6 +820,17 @@ interface LedgerEntry {
|
|
|
819
820
|
* the file docstring.
|
|
820
821
|
*/
|
|
821
822
|
readonly payloadHash: string;
|
|
823
|
+
/**
|
|
824
|
+
* Optional human-readable tag describing why this mutation happened
|
|
825
|
+
* (#1). Threaded through `collection.put(_, _, { reason })`. Common
|
|
826
|
+
* values include `'import:csv'`, `'import:json'`, `'import:xlsx'` from
|
|
827
|
+
* `as-*` ImportPlan.apply(), but consumers can use any string for
|
|
828
|
+
* domain-specific audit filtering. Auto-strip via `canonicalJson` —
|
|
829
|
+
* absent on the wire, never serialized as `null`.
|
|
830
|
+
*
|
|
831
|
+
* Audit consumers filter: `entries.filter(e => e.reason?.startsWith('import:'))`.
|
|
832
|
+
*/
|
|
833
|
+
readonly reason?: string;
|
|
822
834
|
/**
|
|
823
835
|
* Optional hex-encoded sha256 of the encrypted JSON Patch delta
|
|
824
836
|
* blob stored alongside this entry in `_ledger_deltas/`. Present
|
|
@@ -1086,6 +1098,13 @@ interface AppendInput {
|
|
|
1086
1098
|
* resulting ledger entry.
|
|
1087
1099
|
*/
|
|
1088
1100
|
amendment?: LedgerEntry['amendment'];
|
|
1101
|
+
/**
|
|
1102
|
+
* Optional human-readable tag describing why this mutation happened
|
|
1103
|
+
* (#1). Threaded from `collection.put(_, _, { reason })`.
|
|
1104
|
+
* Carried verbatim onto the resulting ledger entry's `reason` field;
|
|
1105
|
+
* omitted from canonical JSON when undefined.
|
|
1106
|
+
*/
|
|
1107
|
+
reason?: string;
|
|
1089
1108
|
}
|
|
1090
1109
|
/**
|
|
1091
1110
|
* Result of `LedgerStore.verify()`. On success, `head` is the hash of
|
|
@@ -3072,6 +3091,266 @@ declare class SyncEngine {
|
|
|
3072
3091
|
private persistMeta;
|
|
3073
3092
|
}
|
|
3074
3093
|
|
|
3094
|
+
/**
|
|
3095
|
+
* **Wrap-DEKs primitive (#44)** — a single canonical shape for the
|
|
3096
|
+
* pattern of "serialize a DEK set, encrypt it under a credential-derived
|
|
3097
|
+
* AES-GCM key." Used by:
|
|
3098
|
+
*
|
|
3099
|
+
* - **tier-0** — paper recovery entries (`_meta/recovery-paper`),
|
|
3100
|
+
* credential = the printed code.
|
|
3101
|
+
* - **tier-2** — password authenticator slots (`KeyringFile.authenticators`,
|
|
3102
|
+
* `wrapKind: 'deks'`), credential = the user's password.
|
|
3103
|
+
*
|
|
3104
|
+
* **Not** used by `@noy-db/on-pin` — tier-3 wraps the DEK set under
|
|
3105
|
+
* the same conceptual pattern but at **100,000 PBKDF2 iterations**
|
|
3106
|
+
* (vs the 600,000 here), because the protection window for a PIN
|
|
3107
|
+
* slot is short (idle-timeout-bounded, typically 15 min) and 600k
|
|
3108
|
+
* iterations would make every PIN-resume noticeably slow. The wire
|
|
3109
|
+
* formats are deliberately incompatible. See `@noy-db/on-pin`'s
|
|
3110
|
+
* `PIN_PBKDF2_ITERATIONS` and the threat-model rationale in its
|
|
3111
|
+
* module docstring.
|
|
3112
|
+
*
|
|
3113
|
+
* Before #44, the same crypto lived in two places: `mintPaperRecoveryEntry`
|
|
3114
|
+
* (in `team/recovery.ts`) and `enrollPasswordAuthenticator` (in
|
|
3115
|
+
* `@noy-db/on-password`). Both functions did identical work — PBKDF2
|
|
3116
|
+
* the credential, AES-GCM-encrypt the JSON-serialized DEK set — but
|
|
3117
|
+
* their implementations had drifted apart enough that fixing a bug
|
|
3118
|
+
* in one wouldn't fix the other.
|
|
3119
|
+
*
|
|
3120
|
+
* This module owns the canonical implementation. Consumers compose:
|
|
3121
|
+
*
|
|
3122
|
+
* - `mintPaperRecoveryEntry` is now a thin wrapper that calls
|
|
3123
|
+
* `mintWrappedDeksBlob` and adds `{ codeId, enrolledAt }`.
|
|
3124
|
+
* - `enrollPasswordAuthenticator` calls `mintWrappedDeksBlob` and
|
|
3125
|
+
* wraps the result in the slot envelope.
|
|
3126
|
+
*
|
|
3127
|
+
* @module
|
|
3128
|
+
*/
|
|
3129
|
+
/**
|
|
3130
|
+
* The wrap-DEKs primitive — a serialized + AES-GCM-encrypted DEK set
|
|
3131
|
+
* keyed under a credential-derived key.
|
|
3132
|
+
*
|
|
3133
|
+
* All three fields are base64-encoded so the blob is JSON-safe and
|
|
3134
|
+
* round-trips through `_meta/*` envelopes (which carry plaintext
|
|
3135
|
+
* JSON in `_data`).
|
|
3136
|
+
*
|
|
3137
|
+
* Composition: `PaperRecoveryEntry extends WrappedDeksBlob` plus
|
|
3138
|
+
* `{ codeId, enrolledAt }`. `KeyringAuthenticatorWrappingDEKs`
|
|
3139
|
+
* carries the same three fields with `salt` stored in `meta` for
|
|
3140
|
+
* slot-format back-compat (#44 defers moving it to top-level).
|
|
3141
|
+
*/
|
|
3142
|
+
interface WrappedDeksBlob {
|
|
3143
|
+
/** Base64 PBKDF2 salt for the credential-derived wrapping key. */
|
|
3144
|
+
readonly salt: string;
|
|
3145
|
+
/** Base64 AES-GCM IV used for the `wrappedDeks` ciphertext. */
|
|
3146
|
+
readonly iv: string;
|
|
3147
|
+
/** Base64 AES-GCM ciphertext of `{ deks: { collection: base64rawDek } }`. */
|
|
3148
|
+
readonly wrappedDeks: string;
|
|
3149
|
+
}
|
|
3150
|
+
/**
|
|
3151
|
+
* Mint a fresh `WrappedDeksBlob` from a DEK set + a string credential.
|
|
3152
|
+
*
|
|
3153
|
+
* Generates a random salt + IV, derives a 256-bit AES-GCM key via
|
|
3154
|
+
* PBKDF2-SHA256(credential, salt, 600K), serializes the DEK set as
|
|
3155
|
+
* `{ deks: { coll: rawBase64 } }`, and AES-GCM-encrypts.
|
|
3156
|
+
*
|
|
3157
|
+
* The `credential` is the user-typed string (recovery code, password,
|
|
3158
|
+
* PIN). Caller normalization rules apply (e.g. paper
|
|
3159
|
+
* recovery uppercase-strips the code before reaching this function).
|
|
3160
|
+
*
|
|
3161
|
+
* @param deks - DEK set to wrap. Each DEK must be exportable via
|
|
3162
|
+
* `subtle.exportKey('raw', dek)` (the hub mints DEKs
|
|
3163
|
+
* this way; consumers feeding non-extractable keys
|
|
3164
|
+
* will get `InvalidAccessError` from WebCrypto).
|
|
3165
|
+
* @param credential - String input the consumer minted (paper code,
|
|
3166
|
+
* password, PIN). Treated as opaque bytes by PBKDF2.
|
|
3167
|
+
*/
|
|
3168
|
+
declare function mintWrappedDeksBlob(deks: Map<string, CryptoKey>, credential: string): Promise<WrappedDeksBlob>;
|
|
3169
|
+
/**
|
|
3170
|
+
* Reverse of {@link mintWrappedDeksBlob}. Re-derives the wrapping key
|
|
3171
|
+
* from the credential + stored salt, AES-GCM-decrypts the wrapped DEK
|
|
3172
|
+
* set, and re-imports each DEK as an extractable AES-GCM CryptoKey.
|
|
3173
|
+
*
|
|
3174
|
+
* Throws (AES-GCM auth tag failure) when the credential doesn't
|
|
3175
|
+
* match the blob. Callers iterating over multiple blobs (e.g. paper
|
|
3176
|
+
* recovery's "try every entry until one matches") should catch.
|
|
3177
|
+
*/
|
|
3178
|
+
declare function unwrapDeksFromBlob(blob: WrappedDeksBlob, credential: string): Promise<Map<string, CryptoKey>>;
|
|
3179
|
+
|
|
3180
|
+
/**
|
|
3181
|
+
* Recovery profile persistence + dispatch — issue #10.
|
|
3182
|
+
*
|
|
3183
|
+
* v0.1.0-pre.5 wires the **paper** profile end-to-end through
|
|
3184
|
+
* `@noy-db/on-recovery`. The other three profiles (Shamir,
|
|
3185
|
+
* multi-channel, admin-mediated) ship the API surface and throw
|
|
3186
|
+
* {@link RecoveryProfileNotImplementedError} during use; per-profile
|
|
3187
|
+
* dispatch lands in follow-up issues.
|
|
3188
|
+
*
|
|
3189
|
+
* Storage layout:
|
|
3190
|
+
*
|
|
3191
|
+
* ```
|
|
3192
|
+
* _meta/recovery-paper — JSON { entries: RecoveryCodeEntry[] } produced by `on-recovery`.
|
|
3193
|
+
* _meta/recovery-shamir — reserved
|
|
3194
|
+
* _meta/recovery-multi — reserved
|
|
3195
|
+
* _meta/recovery-admin — reserved
|
|
3196
|
+
* ```
|
|
3197
|
+
*
|
|
3198
|
+
* Like `_meta/policy` and `_meta/handle`, the documents are plain JSON
|
|
3199
|
+
* with empty `_iv` — the recovery-code wrapping is what protects the
|
|
3200
|
+
* KEK; the entries themselves are inert without the user's code.
|
|
3201
|
+
*
|
|
3202
|
+
* @module
|
|
3203
|
+
*/
|
|
3204
|
+
|
|
3205
|
+
/**
|
|
3206
|
+
* One paper recovery code as persisted in `_meta/recovery-paper`.
|
|
3207
|
+
*
|
|
3208
|
+
* The hub's KEK is intentionally non-extractable (see `crypto.ts`),
|
|
3209
|
+
* so the recovery entry can't AES-KW-wrap the KEK directly. Instead
|
|
3210
|
+
* we wrap a serialized DEK set: the entry holds the AES-GCM
|
|
3211
|
+
* ciphertext of `{ deks: { collection: rawDekBase64 } }`. Recovery
|
|
3212
|
+
* deserializes the DEK set, then mints a fresh KEK from the new
|
|
3213
|
+
* passphrase and rewraps the DEKs under it.
|
|
3214
|
+
*
|
|
3215
|
+
* This is the same pattern `@noy-db/on-pin` uses for tier-3 quick
|
|
3216
|
+
* resume — the cryptographic guarantee is identical (AES-GCM with a
|
|
3217
|
+
* PBKDF2-derived key), and it sidesteps the non-extractable-KEK
|
|
3218
|
+
* constraint cleanly.
|
|
3219
|
+
*
|
|
3220
|
+
* Type-level composition (#44): `PaperRecoveryEntry extends
|
|
3221
|
+
* WrappedDeksBlob` — the three crypto fields (`salt`, `iv`,
|
|
3222
|
+
* `wrappedDeks`) come from the shared primitive; `codeId` and
|
|
3223
|
+
* `enrolledAt` are paper-recovery's own metadata. Wire format
|
|
3224
|
+
* unchanged.
|
|
3225
|
+
*/
|
|
3226
|
+
interface PaperRecoveryEntry extends WrappedDeksBlob {
|
|
3227
|
+
readonly codeId: string;
|
|
3228
|
+
readonly enrolledAt: string;
|
|
3229
|
+
}
|
|
3230
|
+
interface PaperRecoveryDoc {
|
|
3231
|
+
readonly _noydb_recovery: 1;
|
|
3232
|
+
readonly profile: 'paper';
|
|
3233
|
+
readonly entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
3234
|
+
}
|
|
3235
|
+
/** Read the paper-recovery entries. Returns empty array when absent. */
|
|
3236
|
+
declare function loadPaperRecoveryEntries(store: NoydbStore, vault: string): Promise<ReadonlyArray<PaperRecoveryEntry>>;
|
|
3237
|
+
/** Replace the paper-recovery entries (used after burn-on-recovery). */
|
|
3238
|
+
declare function savePaperRecoveryEntries(store: NoydbStore, vault: string, entries: ReadonlyArray<PaperRecoveryEntry>): Promise<void>;
|
|
3239
|
+
/** Drop a single paper-recovery entry (burn-on-use). */
|
|
3240
|
+
declare function burnPaperRecoveryEntry(store: NoydbStore, vault: string, codeId: string): Promise<void>;
|
|
3241
|
+
/** Whether at least one recovery profile has any enrolled entries. */
|
|
3242
|
+
declare function hasRecoveryEnrolled(store: NoydbStore, vault: string): Promise<boolean>;
|
|
3243
|
+
/**
|
|
3244
|
+
* One Shamir-recovery entry as persisted in `_meta/recovery-shamir`.
|
|
3245
|
+
*
|
|
3246
|
+
* Like {@link PaperRecoveryEntry}, the entry composes
|
|
3247
|
+
* {@link WrappedDeksBlob} (DEKs wrapped under a fresh ephemeral
|
|
3248
|
+
* recovery secret) with profile-specific metadata. Unlike paper, the
|
|
3249
|
+
* "credential" was never visible to the user — it was 32 random
|
|
3250
|
+
* bytes split into N Shamir shares at enrollment. The shares ARE
|
|
3251
|
+
* the credential; the user holds them, the hub never sees them
|
|
3252
|
+
* again after `enrollRecovery` returns.
|
|
3253
|
+
*
|
|
3254
|
+
* Per the spec §5: the recovery secret is base64-encoded and
|
|
3255
|
+
* passed as the `credential` arg to
|
|
3256
|
+
* {@link mintWrappedDeksBlob} / {@link unwrapDeksFromBlob}. The
|
|
3257
|
+
* PBKDF2 round over high-entropy input is harmless overhead — it
|
|
3258
|
+
* keeps the shared primitive unchanged while letting Shamir reuse
|
|
3259
|
+
* the same wrapping pipeline as paper.
|
|
3260
|
+
*/
|
|
3261
|
+
interface ShamirRecoveryEntry extends WrappedDeksBlob {
|
|
3262
|
+
/** Stable id for this entry. Allows multiple Shamir splits to coexist. */
|
|
3263
|
+
readonly entryId: string;
|
|
3264
|
+
/** Threshold — minimum shares to reconstruct. */
|
|
3265
|
+
readonly k: number;
|
|
3266
|
+
/** Total shares minted at enrollment. */
|
|
3267
|
+
readonly n: number;
|
|
3268
|
+
/** x-coordinates of the n minted shares (audit metadata; not used at unlock). */
|
|
3269
|
+
readonly xCoords: ReadonlyArray<number>;
|
|
3270
|
+
/** ISO timestamp. */
|
|
3271
|
+
readonly enrolledAt: string;
|
|
3272
|
+
/** Optional caller-supplied label (e.g., "2-of-3 board escrow"). */
|
|
3273
|
+
readonly label?: string;
|
|
3274
|
+
}
|
|
3275
|
+
interface ShamirRecoveryDoc {
|
|
3276
|
+
readonly _noydb_recovery: 1;
|
|
3277
|
+
readonly profile: 'shamir';
|
|
3278
|
+
readonly entries: ReadonlyArray<ShamirRecoveryEntry>;
|
|
3279
|
+
}
|
|
3280
|
+
/** Read the Shamir-recovery entries. Returns empty array when absent. */
|
|
3281
|
+
declare function loadShamirRecoveryEntries(store: NoydbStore, vault: string): Promise<ReadonlyArray<ShamirRecoveryEntry>>;
|
|
3282
|
+
/** Replace the Shamir-recovery entries (used by enrollment and rotation). */
|
|
3283
|
+
declare function saveShamirRecoveryEntries(store: NoydbStore, vault: string, entries: ReadonlyArray<ShamirRecoveryEntry>): Promise<void>;
|
|
3284
|
+
/**
|
|
3285
|
+
* Mint a fresh Shamir recovery entry from a DEK set.
|
|
3286
|
+
*
|
|
3287
|
+
* 1. Generates a 32-byte recovery secret.
|
|
3288
|
+
* 2. Wraps the DEK set under that secret via
|
|
3289
|
+
* {@link mintWrappedDeksBlob} (the recovery secret is base64-
|
|
3290
|
+
* encoded as the credential string — PBKDF2 over high-entropy
|
|
3291
|
+
* input is harmless overhead).
|
|
3292
|
+
* 3. Splits the recovery secret via Shamir into `n` shares with
|
|
3293
|
+
* threshold `k`.
|
|
3294
|
+
* 4. Zeros the in-memory recovery secret after wrapping + splitting.
|
|
3295
|
+
*
|
|
3296
|
+
* Returns:
|
|
3297
|
+
* - `entry` — the {@link ShamirRecoveryEntry} to persist.
|
|
3298
|
+
* - `shareStrings` — the `n` Base32-encoded share strings to
|
|
3299
|
+
* return to the caller. The HUB MUST NOT PERSIST THESE; once
|
|
3300
|
+
* returned they are the user's responsibility.
|
|
3301
|
+
*
|
|
3302
|
+
* @param deks - DEK set to wrap.
|
|
3303
|
+
* @param entryId - Stable id for this entry (caller-supplied or
|
|
3304
|
+
* hub-generated).
|
|
3305
|
+
* @param k - Threshold (>= 2).
|
|
3306
|
+
* @param n - Total shares (k <= n <= 255).
|
|
3307
|
+
* @param label - Optional caller label.
|
|
3308
|
+
*/
|
|
3309
|
+
declare function mintShamirRecoveryEntry(deks: Map<string, CryptoKey>, entryId: string, k: number, n: number, label?: string): Promise<{
|
|
3310
|
+
entry: ShamirRecoveryEntry;
|
|
3311
|
+
shareStrings: string[];
|
|
3312
|
+
}>;
|
|
3313
|
+
/**
|
|
3314
|
+
* Decrypt a Shamir recovery entry to recover the raw DEK set.
|
|
3315
|
+
*
|
|
3316
|
+
* Combines K or more `shares`, reconstructs the recovery secret,
|
|
3317
|
+
* unwraps the DEKs via {@link unwrapDeksFromBlob}.
|
|
3318
|
+
*
|
|
3319
|
+
* Throws (AES-GCM auth-tag mismatch) when the shares don't combine
|
|
3320
|
+
* to the secret originally used to mint the entry — typically
|
|
3321
|
+
* because they came from a different enrollment or were tampered
|
|
3322
|
+
* with. Callers iterating multiple entries should catch.
|
|
3323
|
+
*/
|
|
3324
|
+
declare function unwrapDeksFromShamirEntry(entry: ShamirRecoveryEntry, shares: readonly RawShare[]): Promise<Map<string, CryptoKey>>;
|
|
3325
|
+
|
|
3326
|
+
/**
|
|
3327
|
+
* Generate one paper-recovery entry from an unlocked DEK set.
|
|
3328
|
+
*
|
|
3329
|
+
* Returns the serializable entry (persisted via
|
|
3330
|
+
* {@link savePaperRecoveryEntries}). The recovery flow unwraps the
|
|
3331
|
+
* DEK set, then mints a fresh KEK from the user's new passphrase.
|
|
3332
|
+
*
|
|
3333
|
+
* Thin wrapper over {@link mintWrappedDeksBlob} (#44) — the crypto
|
|
3334
|
+
* lives in the shared primitive; this function just adds paper-
|
|
3335
|
+
* recovery's own metadata (`codeId`, `enrolledAt`).
|
|
3336
|
+
*
|
|
3337
|
+
* @param deks Map of collection-name → DEK (extractable).
|
|
3338
|
+
* @param code The plaintext recovery code (caller-supplied;
|
|
3339
|
+
* pair this with `@noy-db/on-recovery`'s code
|
|
3340
|
+
* generator/parser if available).
|
|
3341
|
+
* @param codeId Stable id used by `burnPaperRecoveryEntry`.
|
|
3342
|
+
*/
|
|
3343
|
+
declare function mintPaperRecoveryEntry(deks: Map<string, CryptoKey>, code: string, codeId: string): Promise<PaperRecoveryEntry>;
|
|
3344
|
+
/**
|
|
3345
|
+
* Decrypt a recovery entry to recover the raw DEK set. Used by the
|
|
3346
|
+
* `recoverPassphrase` flow after the user's code has been parsed.
|
|
3347
|
+
*
|
|
3348
|
+
* Thin wrapper over {@link unwrapDeksFromBlob} (#44).
|
|
3349
|
+
*
|
|
3350
|
+
* @throws when the code does not match the entry (AES-GCM auth tag fail).
|
|
3351
|
+
*/
|
|
3352
|
+
declare function unwrapDeksFromPaperEntry(entry: PaperRecoveryEntry, code: string): Promise<Map<string, CryptoKey>>;
|
|
3353
|
+
|
|
3075
3354
|
/**
|
|
3076
3355
|
* Tier-2 authenticator slot management — issue #11.
|
|
3077
3356
|
*
|
|
@@ -3272,20 +3551,26 @@ declare function rotatePassphrase(store: NoydbStore, vault: string, userId: stri
|
|
|
3272
3551
|
/**
|
|
3273
3552
|
* Caller payload for {@link recoverPassphrase}.
|
|
3274
3553
|
*
|
|
3275
|
-
*
|
|
3276
|
-
* (`
|
|
3277
|
-
*
|
|
3278
|
-
* {@link
|
|
3279
|
-
*
|
|
3280
|
-
* guard ({@link RecoveryProfileNotImplementedError}) remains so
|
|
3281
|
-
* consumers who bypass TS via `as unknown as RecoveryProof` still
|
|
3282
|
-
* receive a clear error.
|
|
3554
|
+
* As of #196 slice 1, `paper` and `shamir` are wired end-to-end.
|
|
3555
|
+
* The remaining two profiles (`multi-channel`, `admin-mediated`)
|
|
3556
|
+
* stay outside the union and throw
|
|
3557
|
+
* {@link RecoveryProfileNotImplementedError} at the runtime guard
|
|
3558
|
+
* when bypassed via `as unknown as RecoveryProof`.
|
|
3283
3559
|
*/
|
|
3284
3560
|
type RecoveryProof = {
|
|
3285
3561
|
readonly profile: 'paper';
|
|
3286
3562
|
readonly payload: {
|
|
3287
3563
|
readonly code: string;
|
|
3288
3564
|
};
|
|
3565
|
+
} | {
|
|
3566
|
+
readonly profile: 'shamir';
|
|
3567
|
+
readonly payload: {
|
|
3568
|
+
/** Optional disambiguator when multiple Shamir entries are enrolled.
|
|
3569
|
+
* When omitted, hub tries each entry until one combines. */
|
|
3570
|
+
readonly entryId?: string;
|
|
3571
|
+
/** K or more share strings (Base32-encoded per @noy-db/on-shamir). */
|
|
3572
|
+
readonly shares: ReadonlyArray<string>;
|
|
3573
|
+
};
|
|
3289
3574
|
};
|
|
3290
3575
|
interface RecoverPassphraseInput {
|
|
3291
3576
|
readonly newPassphrase: string;
|
|
@@ -3345,6 +3630,83 @@ interface RecoverPassphraseInput {
|
|
|
3345
3630
|
interface RecoverPassphraseResult {
|
|
3346
3631
|
readonly newCodes: readonly string[];
|
|
3347
3632
|
}
|
|
3633
|
+
/**
|
|
3634
|
+
* Input for {@link Noydb.rotateRecovery} (#121) — deliberate
|
|
3635
|
+
* recovery-credential regeneration when the user knows their
|
|
3636
|
+
* passphrase but wants a fresh sheet (paper) or fresh shares
|
|
3637
|
+
* (shamir). Symmetric to {@link RotatePassphraseInput}.
|
|
3638
|
+
*/
|
|
3639
|
+
type RotateRecoveryOptions = {
|
|
3640
|
+
readonly profile: 'paper';
|
|
3641
|
+
/** How many fresh codes to mint. Default: existing sheet size. */
|
|
3642
|
+
readonly count?: number;
|
|
3643
|
+
/** Optional code generator — see {@link RecoverPassphraseInput.codeGenerator}. */
|
|
3644
|
+
readonly codeGenerator?: () => string;
|
|
3645
|
+
} | {
|
|
3646
|
+
readonly profile: 'shamir';
|
|
3647
|
+
/** New threshold. */
|
|
3648
|
+
readonly k: number;
|
|
3649
|
+
/** New total share count. */
|
|
3650
|
+
readonly n: number;
|
|
3651
|
+
/** Disambiguator when multiple Shamir entries exist; required if there are 2+. */
|
|
3652
|
+
readonly entryId?: string;
|
|
3653
|
+
/** Optional updated label. */
|
|
3654
|
+
readonly label?: string;
|
|
3655
|
+
};
|
|
3656
|
+
/**
|
|
3657
|
+
* Result of {@link Noydb.rotateRecovery}. Shape varies by profile:
|
|
3658
|
+
*
|
|
3659
|
+
* - `paper` → `{ newCodes: string[] }` (and `entryId === 'paper-batch'`)
|
|
3660
|
+
* - `shamir` → `{ newShares: string[], entryId }`
|
|
3661
|
+
*
|
|
3662
|
+
* `newCodes` is populated for paper rotations; `newShares` for
|
|
3663
|
+
* Shamir rotations. Both are show-once — the hub does not
|
|
3664
|
+
* retain them.
|
|
3665
|
+
*/
|
|
3666
|
+
interface RotateRecoveryResult {
|
|
3667
|
+
readonly newCodes?: readonly string[];
|
|
3668
|
+
readonly newShares?: readonly string[];
|
|
3669
|
+
readonly entryId?: string;
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Result of {@link Noydb.enrollRecovery}. Shape varies by profile:
|
|
3673
|
+
*
|
|
3674
|
+
* - `paper` → `{ entryId: 'paper-batch' }` (caller minted the
|
|
3675
|
+
* entries; this is a sentinel since paper enrollments are batch-shaped).
|
|
3676
|
+
* - `shamir` → `{ entryId, shares: string[] }` — shares are
|
|
3677
|
+
* show-once; the hub does not retain them.
|
|
3678
|
+
*/
|
|
3679
|
+
interface EnrollRecoveryResult {
|
|
3680
|
+
readonly entryId: string;
|
|
3681
|
+
readonly shares?: readonly string[];
|
|
3682
|
+
}
|
|
3683
|
+
/**
|
|
3684
|
+
* Input shape for {@link Noydb.enrollRecovery} and
|
|
3685
|
+
* {@link Noydb.openVaultAndEnrollRecovery} (#195). Discriminated
|
|
3686
|
+
* union over recovery profiles.
|
|
3687
|
+
*
|
|
3688
|
+
* - `paper`: caller pre-mints entries (typically via
|
|
3689
|
+
* `mintPaperRecoveryEntry` or `@noy-db/on-recovery`'s
|
|
3690
|
+
* `generateRecoveryCodeSet`) and passes them in. The hub stores
|
|
3691
|
+
* them and surfaces an opaque batch id.
|
|
3692
|
+
* - `shamir`: hub mints the recovery secret + the shares at
|
|
3693
|
+
* enrollment time. The shares are returned in
|
|
3694
|
+
* {@link EnrollRecoveryResult.shares} (show-once); the hub never
|
|
3695
|
+
* retains them.
|
|
3696
|
+
*
|
|
3697
|
+
* Multi-channel and admin-mediated will be added when the respective
|
|
3698
|
+
* dispatch slices ship.
|
|
3699
|
+
*/
|
|
3700
|
+
type RecoveryEnrollmentInput = {
|
|
3701
|
+
readonly profile: 'paper';
|
|
3702
|
+
readonly entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
3703
|
+
} | {
|
|
3704
|
+
readonly profile: 'shamir';
|
|
3705
|
+
readonly k: number;
|
|
3706
|
+
readonly n: number;
|
|
3707
|
+
readonly label?: string;
|
|
3708
|
+
readonly entryId?: string;
|
|
3709
|
+
};
|
|
3348
3710
|
/**
|
|
3349
3711
|
* Reset the user's passphrase using a recovery proof. v0.1.0-pre.5
|
|
3350
3712
|
* supports the `'paper'` profile via `@noy-db/on-recovery` entries
|
|
@@ -3385,233 +3747,56 @@ declare function recoverPassphrase(store: NoydbStore, vault: string, userId: str
|
|
|
3385
3747
|
* their own phrase.
|
|
3386
3748
|
*
|
|
3387
3749
|
* Caller must be at least as privileged as the target. The hub
|
|
3388
|
-
* `db.recoverUser` method gates this with the `peer-recover-user`
|
|
3389
|
-
* policy gate (#33's factor-proof requirement); the function below
|
|
3390
|
-
* enforces only the role + anti-privilege-escalation invariants.
|
|
3391
|
-
*
|
|
3392
|
-
* @module
|
|
3393
|
-
*/
|
|
3394
|
-
|
|
3395
|
-
/** Input shape for {@link recoverUser}. */
|
|
3396
|
-
interface RecoverUserOptions {
|
|
3397
|
-
/** Target user id whose keyring is being recovered. */
|
|
3398
|
-
readonly userId: string;
|
|
3399
|
-
/**
|
|
3400
|
-
* Temporary passphrase under which the new keyring is wrapped.
|
|
3401
|
-
* The recipient should call `db.rotatePassphrase` immediately on
|
|
3402
|
-
* acceptance to choose their own phrase — this temp acts as a
|
|
3403
|
-
* single-use bridge in invite / peer-recovery flows.
|
|
3404
|
-
*/
|
|
3405
|
-
readonly passphrase: string;
|
|
3406
|
-
/** Override the target's role. Defaults to the existing target's role. */
|
|
3407
|
-
readonly role?: Role;
|
|
3408
|
-
/** Override the target's display name. Defaults to existing. */
|
|
3409
|
-
readonly displayName?: string;
|
|
3410
|
-
/** Validate phrase strength against the configured policy. */
|
|
3411
|
-
readonly validatePassphrase?: boolean;
|
|
3412
|
-
/**
|
|
3413
|
-
* Skip phrase strength validation even when `validatePassphrase` is
|
|
3414
|
-
* set. The escape hatch matches `grant`'s shape — used when the
|
|
3415
|
-
* temp phrase is a high-entropy one-shot string that doesn't need
|
|
3416
|
-
* to satisfy the human-typeable rules.
|
|
3417
|
-
*/
|
|
3418
|
-
readonly allowWeakPassphrase?: boolean;
|
|
3419
|
-
/**
|
|
3420
|
-
* Optional explicit phrase policy override (passed through to
|
|
3421
|
-
* `assertStrongPassphrase`). Mirrors how `grant` accepts a custom
|
|
3422
|
-
* `PassphrasePolicy` for app-specific tightening.
|
|
3423
|
-
*/
|
|
3424
|
-
readonly passphrasePolicy?: PassphrasePolicy;
|
|
3425
|
-
}
|
|
3426
|
-
/**
|
|
3427
|
-
* Atomically rewrap the target user's keyring under a fresh temp
|
|
3428
|
-
* passphrase. Single store write; no revoke step; no key rotation.
|
|
3429
|
-
*
|
|
3430
|
-
* Caller's responsibilities (NOT enforced here):
|
|
3431
|
-
* - Run the `peer-recover-user` policy gate first via
|
|
3432
|
-
* `Noydb.checkGate` to enforce the freshness factor proof.
|
|
3433
|
-
* - Communicate the temp passphrase to the recipient via a secure
|
|
3434
|
-
* channel (URL fragment, in-person, etc.) — the hub does not
|
|
3435
|
-
* transport secrets.
|
|
3436
|
-
*/
|
|
3437
|
-
declare function recoverUser(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, options: RecoverUserOptions): Promise<void>;
|
|
3438
|
-
|
|
3439
|
-
/**
|
|
3440
|
-
* **Wrap-DEKs primitive (#44)** — a single canonical shape for the
|
|
3441
|
-
* pattern of "serialize a DEK set, encrypt it under a credential-derived
|
|
3442
|
-
* AES-GCM key." Used by:
|
|
3443
|
-
*
|
|
3444
|
-
* - **tier-0** — paper recovery entries (`_meta/recovery-paper`),
|
|
3445
|
-
* credential = the printed code.
|
|
3446
|
-
* - **tier-2** — password authenticator slots (`KeyringFile.authenticators`,
|
|
3447
|
-
* `wrapKind: 'deks'`), credential = the user's password.
|
|
3448
|
-
*
|
|
3449
|
-
* **Not** used by `@noy-db/on-pin` — tier-3 wraps the DEK set under
|
|
3450
|
-
* the same conceptual pattern but at **100,000 PBKDF2 iterations**
|
|
3451
|
-
* (vs the 600,000 here), because the protection window for a PIN
|
|
3452
|
-
* slot is short (idle-timeout-bounded, typically 15 min) and 600k
|
|
3453
|
-
* iterations would make every PIN-resume noticeably slow. The wire
|
|
3454
|
-
* formats are deliberately incompatible. See `@noy-db/on-pin`'s
|
|
3455
|
-
* `PIN_PBKDF2_ITERATIONS` and the threat-model rationale in its
|
|
3456
|
-
* module docstring.
|
|
3457
|
-
*
|
|
3458
|
-
* Before #44, the same crypto lived in two places: `mintPaperRecoveryEntry`
|
|
3459
|
-
* (in `team/recovery.ts`) and `enrollPasswordAuthenticator` (in
|
|
3460
|
-
* `@noy-db/on-password`). Both functions did identical work — PBKDF2
|
|
3461
|
-
* the credential, AES-GCM-encrypt the JSON-serialized DEK set — but
|
|
3462
|
-
* their implementations had drifted apart enough that fixing a bug
|
|
3463
|
-
* in one wouldn't fix the other.
|
|
3464
|
-
*
|
|
3465
|
-
* This module owns the canonical implementation. Consumers compose:
|
|
3466
|
-
*
|
|
3467
|
-
* - `mintPaperRecoveryEntry` is now a thin wrapper that calls
|
|
3468
|
-
* `mintWrappedDeksBlob` and adds `{ codeId, enrolledAt }`.
|
|
3469
|
-
* - `enrollPasswordAuthenticator` calls `mintWrappedDeksBlob` and
|
|
3470
|
-
* wraps the result in the slot envelope.
|
|
3471
|
-
*
|
|
3472
|
-
* @module
|
|
3473
|
-
*/
|
|
3474
|
-
/**
|
|
3475
|
-
* The wrap-DEKs primitive — a serialized + AES-GCM-encrypted DEK set
|
|
3476
|
-
* keyed under a credential-derived key.
|
|
3477
|
-
*
|
|
3478
|
-
* All three fields are base64-encoded so the blob is JSON-safe and
|
|
3479
|
-
* round-trips through `_meta/*` envelopes (which carry plaintext
|
|
3480
|
-
* JSON in `_data`).
|
|
3481
|
-
*
|
|
3482
|
-
* Composition: `PaperRecoveryEntry extends WrappedDeksBlob` plus
|
|
3483
|
-
* `{ codeId, enrolledAt }`. `KeyringAuthenticatorWrappingDEKs`
|
|
3484
|
-
* carries the same three fields with `salt` stored in `meta` for
|
|
3485
|
-
* slot-format back-compat (#44 defers moving it to top-level).
|
|
3486
|
-
*/
|
|
3487
|
-
interface WrappedDeksBlob {
|
|
3488
|
-
/** Base64 PBKDF2 salt for the credential-derived wrapping key. */
|
|
3489
|
-
readonly salt: string;
|
|
3490
|
-
/** Base64 AES-GCM IV used for the `wrappedDeks` ciphertext. */
|
|
3491
|
-
readonly iv: string;
|
|
3492
|
-
/** Base64 AES-GCM ciphertext of `{ deks: { collection: base64rawDek } }`. */
|
|
3493
|
-
readonly wrappedDeks: string;
|
|
3494
|
-
}
|
|
3495
|
-
/**
|
|
3496
|
-
* Mint a fresh `WrappedDeksBlob` from a DEK set + a string credential.
|
|
3497
|
-
*
|
|
3498
|
-
* Generates a random salt + IV, derives a 256-bit AES-GCM key via
|
|
3499
|
-
* PBKDF2-SHA256(credential, salt, 600K), serializes the DEK set as
|
|
3500
|
-
* `{ deks: { coll: rawBase64 } }`, and AES-GCM-encrypts.
|
|
3501
|
-
*
|
|
3502
|
-
* The `credential` is the user-typed string (recovery code, password,
|
|
3503
|
-
* PIN). Caller normalization rules apply (e.g. paper
|
|
3504
|
-
* recovery uppercase-strips the code before reaching this function).
|
|
3505
|
-
*
|
|
3506
|
-
* @param deks - DEK set to wrap. Each DEK must be exportable via
|
|
3507
|
-
* `subtle.exportKey('raw', dek)` (the hub mints DEKs
|
|
3508
|
-
* this way; consumers feeding non-extractable keys
|
|
3509
|
-
* will get `InvalidAccessError` from WebCrypto).
|
|
3510
|
-
* @param credential - String input the consumer minted (paper code,
|
|
3511
|
-
* password, PIN). Treated as opaque bytes by PBKDF2.
|
|
3512
|
-
*/
|
|
3513
|
-
declare function mintWrappedDeksBlob(deks: Map<string, CryptoKey>, credential: string): Promise<WrappedDeksBlob>;
|
|
3514
|
-
/**
|
|
3515
|
-
* Reverse of {@link mintWrappedDeksBlob}. Re-derives the wrapping key
|
|
3516
|
-
* from the credential + stored salt, AES-GCM-decrypts the wrapped DEK
|
|
3517
|
-
* set, and re-imports each DEK as an extractable AES-GCM CryptoKey.
|
|
3518
|
-
*
|
|
3519
|
-
* Throws (AES-GCM auth tag failure) when the credential doesn't
|
|
3520
|
-
* match the blob. Callers iterating over multiple blobs (e.g. paper
|
|
3521
|
-
* recovery's "try every entry until one matches") should catch.
|
|
3522
|
-
*/
|
|
3523
|
-
declare function unwrapDeksFromBlob(blob: WrappedDeksBlob, credential: string): Promise<Map<string, CryptoKey>>;
|
|
3524
|
-
|
|
3525
|
-
/**
|
|
3526
|
-
* Recovery profile persistence + dispatch — issue #10.
|
|
3527
|
-
*
|
|
3528
|
-
* v0.1.0-pre.5 wires the **paper** profile end-to-end through
|
|
3529
|
-
* `@noy-db/on-recovery`. The other three profiles (Shamir,
|
|
3530
|
-
* multi-channel, admin-mediated) ship the API surface and throw
|
|
3531
|
-
* {@link RecoveryProfileNotImplementedError} during use; per-profile
|
|
3532
|
-
* dispatch lands in follow-up issues.
|
|
3533
|
-
*
|
|
3534
|
-
* Storage layout:
|
|
3535
|
-
*
|
|
3536
|
-
* ```
|
|
3537
|
-
* _meta/recovery-paper — JSON { entries: RecoveryCodeEntry[] } produced by `on-recovery`.
|
|
3538
|
-
* _meta/recovery-shamir — reserved
|
|
3539
|
-
* _meta/recovery-multi — reserved
|
|
3540
|
-
* _meta/recovery-admin — reserved
|
|
3541
|
-
* ```
|
|
3542
|
-
*
|
|
3543
|
-
* Like `_meta/policy` and `_meta/handle`, the documents are plain JSON
|
|
3544
|
-
* with empty `_iv` — the recovery-code wrapping is what protects the
|
|
3545
|
-
* KEK; the entries themselves are inert without the user's code.
|
|
3546
|
-
*
|
|
3547
|
-
* @module
|
|
3548
|
-
*/
|
|
3549
|
-
|
|
3550
|
-
/**
|
|
3551
|
-
* One paper recovery code as persisted in `_meta/recovery-paper`.
|
|
3552
|
-
*
|
|
3553
|
-
* The hub's KEK is intentionally non-extractable (see `crypto.ts`),
|
|
3554
|
-
* so the recovery entry can't AES-KW-wrap the KEK directly. Instead
|
|
3555
|
-
* we wrap a serialized DEK set: the entry holds the AES-GCM
|
|
3556
|
-
* ciphertext of `{ deks: { collection: rawDekBase64 } }`. Recovery
|
|
3557
|
-
* deserializes the DEK set, then mints a fresh KEK from the new
|
|
3558
|
-
* passphrase and rewraps the DEKs under it.
|
|
3559
|
-
*
|
|
3560
|
-
* This is the same pattern `@noy-db/on-pin` uses for tier-3 quick
|
|
3561
|
-
* resume — the cryptographic guarantee is identical (AES-GCM with a
|
|
3562
|
-
* PBKDF2-derived key), and it sidesteps the non-extractable-KEK
|
|
3563
|
-
* constraint cleanly.
|
|
3564
|
-
*
|
|
3565
|
-
* Type-level composition (#44): `PaperRecoveryEntry extends
|
|
3566
|
-
* WrappedDeksBlob` — the three crypto fields (`salt`, `iv`,
|
|
3567
|
-
* `wrappedDeks`) come from the shared primitive; `codeId` and
|
|
3568
|
-
* `enrolledAt` are paper-recovery's own metadata. Wire format
|
|
3569
|
-
* unchanged.
|
|
3570
|
-
*/
|
|
3571
|
-
interface PaperRecoveryEntry extends WrappedDeksBlob {
|
|
3572
|
-
readonly codeId: string;
|
|
3573
|
-
readonly enrolledAt: string;
|
|
3574
|
-
}
|
|
3575
|
-
interface PaperRecoveryDoc {
|
|
3576
|
-
readonly _noydb_recovery: 1;
|
|
3577
|
-
readonly profile: 'paper';
|
|
3578
|
-
readonly entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
3579
|
-
}
|
|
3580
|
-
/** Read the paper-recovery entries. Returns empty array when absent. */
|
|
3581
|
-
declare function loadPaperRecoveryEntries(store: NoydbStore, vault: string): Promise<ReadonlyArray<PaperRecoveryEntry>>;
|
|
3582
|
-
/** Replace the paper-recovery entries (used after burn-on-recovery). */
|
|
3583
|
-
declare function savePaperRecoveryEntries(store: NoydbStore, vault: string, entries: ReadonlyArray<PaperRecoveryEntry>): Promise<void>;
|
|
3584
|
-
/** Drop a single paper-recovery entry (burn-on-use). */
|
|
3585
|
-
declare function burnPaperRecoveryEntry(store: NoydbStore, vault: string, codeId: string): Promise<void>;
|
|
3586
|
-
/** Whether at least one recovery profile has any enrolled entries. */
|
|
3587
|
-
declare function hasRecoveryEnrolled(store: NoydbStore, vault: string): Promise<boolean>;
|
|
3588
|
-
/**
|
|
3589
|
-
* Generate one paper-recovery entry from an unlocked DEK set.
|
|
3590
|
-
*
|
|
3591
|
-
* Returns the serializable entry (persisted via
|
|
3592
|
-
* {@link savePaperRecoveryEntries}). The recovery flow unwraps the
|
|
3593
|
-
* DEK set, then mints a fresh KEK from the user's new passphrase.
|
|
3594
|
-
*
|
|
3595
|
-
* Thin wrapper over {@link mintWrappedDeksBlob} (#44) — the crypto
|
|
3596
|
-
* lives in the shared primitive; this function just adds paper-
|
|
3597
|
-
* recovery's own metadata (`codeId`, `enrolledAt`).
|
|
3750
|
+
* `db.recoverUser` method gates this with the `peer-recover-user`
|
|
3751
|
+
* policy gate (#33's factor-proof requirement); the function below
|
|
3752
|
+
* enforces only the role + anti-privilege-escalation invariants.
|
|
3598
3753
|
*
|
|
3599
|
-
* @
|
|
3600
|
-
* @param code The plaintext recovery code (caller-supplied;
|
|
3601
|
-
* pair this with `@noy-db/on-recovery`'s code
|
|
3602
|
-
* generator/parser if available).
|
|
3603
|
-
* @param codeId Stable id used by `burnPaperRecoveryEntry`.
|
|
3754
|
+
* @module
|
|
3604
3755
|
*/
|
|
3605
|
-
|
|
3756
|
+
|
|
3757
|
+
/** Input shape for {@link recoverUser}. */
|
|
3758
|
+
interface RecoverUserOptions {
|
|
3759
|
+
/** Target user id whose keyring is being recovered. */
|
|
3760
|
+
readonly userId: string;
|
|
3761
|
+
/**
|
|
3762
|
+
* Temporary passphrase under which the new keyring is wrapped.
|
|
3763
|
+
* The recipient should call `db.rotatePassphrase` immediately on
|
|
3764
|
+
* acceptance to choose their own phrase — this temp acts as a
|
|
3765
|
+
* single-use bridge in invite / peer-recovery flows.
|
|
3766
|
+
*/
|
|
3767
|
+
readonly passphrase: string;
|
|
3768
|
+
/** Override the target's role. Defaults to the existing target's role. */
|
|
3769
|
+
readonly role?: Role;
|
|
3770
|
+
/** Override the target's display name. Defaults to existing. */
|
|
3771
|
+
readonly displayName?: string;
|
|
3772
|
+
/** Validate phrase strength against the configured policy. */
|
|
3773
|
+
readonly validatePassphrase?: boolean;
|
|
3774
|
+
/**
|
|
3775
|
+
* Skip phrase strength validation even when `validatePassphrase` is
|
|
3776
|
+
* set. The escape hatch matches `grant`'s shape — used when the
|
|
3777
|
+
* temp phrase is a high-entropy one-shot string that doesn't need
|
|
3778
|
+
* to satisfy the human-typeable rules.
|
|
3779
|
+
*/
|
|
3780
|
+
readonly allowWeakPassphrase?: boolean;
|
|
3781
|
+
/**
|
|
3782
|
+
* Optional explicit phrase policy override (passed through to
|
|
3783
|
+
* `assertStrongPassphrase`). Mirrors how `grant` accepts a custom
|
|
3784
|
+
* `PassphrasePolicy` for app-specific tightening.
|
|
3785
|
+
*/
|
|
3786
|
+
readonly passphrasePolicy?: PassphrasePolicy;
|
|
3787
|
+
}
|
|
3606
3788
|
/**
|
|
3607
|
-
*
|
|
3608
|
-
*
|
|
3609
|
-
*
|
|
3610
|
-
* Thin wrapper over {@link unwrapDeksFromBlob} (#44).
|
|
3789
|
+
* Atomically rewrap the target user's keyring under a fresh temp
|
|
3790
|
+
* passphrase. Single store write; no revoke step; no key rotation.
|
|
3611
3791
|
*
|
|
3612
|
-
*
|
|
3792
|
+
* Caller's responsibilities (NOT enforced here):
|
|
3793
|
+
* - Run the `peer-recover-user` policy gate first via
|
|
3794
|
+
* `Noydb.checkGate` to enforce the freshness factor proof.
|
|
3795
|
+
* - Communicate the temp passphrase to the recipient via a secure
|
|
3796
|
+
* channel (URL fragment, in-person, etc.) — the hub does not
|
|
3797
|
+
* transport secrets.
|
|
3613
3798
|
*/
|
|
3614
|
-
declare function
|
|
3799
|
+
declare function recoverUser(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, options: RecoverUserOptions): Promise<void>;
|
|
3615
3800
|
|
|
3616
3801
|
/**
|
|
3617
3802
|
* Public envelope — owner-curated plaintext metadata, readable
|
|
@@ -3833,6 +4018,12 @@ interface StagedOp {
|
|
|
3833
4018
|
id: string;
|
|
3834
4019
|
record?: unknown;
|
|
3835
4020
|
expectedVersion?: number;
|
|
4021
|
+
/**
|
|
4022
|
+
* Optional human-readable tag forwarded to the resulting ledger
|
|
4023
|
+
* entry's `reason` field (#1). Set by callers via
|
|
4024
|
+
* `tx.vault(v).collection(c).put(id, record, { reason })`.
|
|
4025
|
+
*/
|
|
4026
|
+
reason?: string;
|
|
3836
4027
|
}
|
|
3837
4028
|
/**
|
|
3838
4029
|
* One executed op (main staged op or recursive side-effect like a
|
|
@@ -3922,6 +4113,7 @@ declare class TxCollection<T> {
|
|
|
3922
4113
|
*/
|
|
3923
4114
|
put(id: string, record: T, options?: {
|
|
3924
4115
|
expectedVersion?: number;
|
|
4116
|
+
reason?: string;
|
|
3925
4117
|
}): void;
|
|
3926
4118
|
/**
|
|
3927
4119
|
* Stage a delete. Does not write until the transaction body returns.
|
|
@@ -4026,6 +4218,16 @@ interface GatePolicy {
|
|
|
4026
4218
|
* configured policy as "no gate" (no-op).
|
|
4027
4219
|
*/
|
|
4028
4220
|
type BuiltInGateName = 'rotate-passphrase' | 'recover-passphrase' | 'enroll-authenticator' | 'remove-authenticator'
|
|
4221
|
+
/**
|
|
4222
|
+
* Authorize a deliberate paper-recovery-code regeneration —
|
|
4223
|
+
* `db.rotateRecovery` (#121). Symmetric to `rotate-passphrase` for
|
|
4224
|
+
* the case where the user remembers their passphrase but wants a
|
|
4225
|
+
* fresh sheet (lost the printout, suspect compromise of the off-site
|
|
4226
|
+
* copy). PERSONAL allows tier-1; STRICT requires an off-device
|
|
4227
|
+
* factor so a stolen unlocked laptop cannot silently mint a new
|
|
4228
|
+
* sheet for an attacker.
|
|
4229
|
+
*/
|
|
4230
|
+
| 'rotate-recovery'
|
|
4029
4231
|
/**
|
|
4030
4232
|
* Authorize a meta-only mutation on an existing authenticator slot —
|
|
4031
4233
|
* `db.updateAuthenticator` (#55). The slot's wrap material, id, and
|
|
@@ -4118,6 +4320,14 @@ declare class Noydb {
|
|
|
4118
4320
|
* `_meta/policy` load; replaced by `db.updatePolicy()`.
|
|
4119
4321
|
*/
|
|
4120
4322
|
private readonly policyCache;
|
|
4323
|
+
/**
|
|
4324
|
+
* One-shot bypass for the managed-mode strong-recovery check (#195).
|
|
4325
|
+
* Set true by {@link openVaultAndEnrollRecovery} for the duration of
|
|
4326
|
+
* the bootstrap window so the keyring can be created before the
|
|
4327
|
+
* strong recovery is enrolled. Always cleared (try/finally).
|
|
4328
|
+
* @internal
|
|
4329
|
+
*/
|
|
4330
|
+
private _skipNextManagedRecoveryCheck;
|
|
4121
4331
|
/** Per-vault tier-3 (PIN / quick-resume) state — issue #11. */
|
|
4122
4332
|
private readonly quickUnlock;
|
|
4123
4333
|
/**
|
|
@@ -4581,15 +4791,29 @@ declare class Noydb {
|
|
|
4581
4791
|
/** Read or persist the vault policy at `_meta/policy` on first open. */
|
|
4582
4792
|
private bootstrapPolicy;
|
|
4583
4793
|
/**
|
|
4584
|
-
* Throw {@link RecoveryNotEnrolledError}
|
|
4585
|
-
*
|
|
4586
|
-
*
|
|
4587
|
-
* entries are persisted.
|
|
4794
|
+
* Throw {@link RecoveryNotEnrolledError} or
|
|
4795
|
+
* {@link ManagedRecoveryNotEnrolledError} when recovery enrollment
|
|
4796
|
+
* is missing.
|
|
4588
4797
|
*
|
|
4589
|
-
*
|
|
4590
|
-
*
|
|
4591
|
-
*
|
|
4592
|
-
*
|
|
4798
|
+
* Two enforcement modes:
|
|
4799
|
+
*
|
|
4800
|
+
* 1. **Managed-mode mandatory strong-recovery (#195).** When
|
|
4801
|
+
* `passphraseMode === 'managed'`, the vault MUST have at least
|
|
4802
|
+
* one **strong** recovery profile (Shamir today). Paper alone is
|
|
4803
|
+
* rejected because under managed mode the user has no memorized
|
|
4804
|
+
* passphrase, so losing the paper sheet = losing every record.
|
|
4805
|
+
* This check is unconditional — independent of `requireRecovery`
|
|
4806
|
+
* and the `recover-passphrase` gate.
|
|
4807
|
+
*
|
|
4808
|
+
* 2. **Opt-in strict mandatory-recovery.** When
|
|
4809
|
+
* `requireRecovery: true` is set on createNoydb (and the gate is
|
|
4810
|
+
* not explicitly disabled), require ANY recovery profile (paper
|
|
4811
|
+
* or shamir). This is the v0.x default-off behavior; v1.0 may
|
|
4812
|
+
* flip it default-on.
|
|
4813
|
+
*
|
|
4814
|
+
* The managed-mode check fires from {@link bootstrapPolicy} unless
|
|
4815
|
+
* the `skipManagedCheck` flag is set (used by
|
|
4816
|
+
* {@link openVaultAndEnrollRecovery} to allow atomic create-and-enroll).
|
|
4593
4817
|
*/
|
|
4594
4818
|
private assertRecoveryEnrolled;
|
|
4595
4819
|
/**
|
|
@@ -4785,6 +5009,123 @@ declare class Noydb {
|
|
|
4785
5009
|
* Burns the used recovery entry on success.
|
|
4786
5010
|
*/
|
|
4787
5011
|
recoverPassphrase(vault: string, input: RecoverPassphraseInput, factors?: FactorProofBundle): Promise<RecoverPassphraseResult>;
|
|
5012
|
+
/**
|
|
5013
|
+
* Deliberate paper-recovery-code regeneration (#121). User knows their
|
|
5014
|
+
* passphrase but wants a fresh sheet — they lost the printout or
|
|
5015
|
+
* suspect compromise of the off-site copy.
|
|
5016
|
+
*
|
|
5017
|
+
* Symmetric to {@link rotatePassphrase} for the recovery profile:
|
|
5018
|
+
* gated, audit-trackable, ergonomic. Replaces (not appends) the
|
|
5019
|
+
* paper sheet under `_meta/recovery-paper` in a single envelope `put`.
|
|
5020
|
+
*
|
|
5021
|
+
* Gated by the `rotate-recovery` policy gate:
|
|
5022
|
+
* - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the passphrase
|
|
5023
|
+
* suffices, matching the pre-#121 low-level flow's bar.
|
|
5024
|
+
* - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',
|
|
5025
|
+
* 'email-otp', 'webauthn-roaming'] }] }` — rotation is an
|
|
5026
|
+
* off-site-trust event; require an off-device factor so a
|
|
5027
|
+
* stolen unlocked laptop cannot silently mint a sheet for the
|
|
5028
|
+
* attacker.
|
|
5029
|
+
*
|
|
5030
|
+
* Defaults `count` to the existing sheet size so consumers aren't
|
|
5031
|
+
* surprised by a different code count. Explicit `count` overrides.
|
|
5032
|
+
*
|
|
5033
|
+
* @throws {@link RecoveryProfileNotImplementedError} when `profile`
|
|
5034
|
+
* is anything other than `'paper'` (v1 dispatch limit).
|
|
5035
|
+
* @throws {@link PolicyDeniedError} when the gate denies (missing
|
|
5036
|
+
* factor, tier mismatch, ...).
|
|
5037
|
+
* @throws on missing paper sheet — "nothing to rotate" surfaces as
|
|
5038
|
+
* an error rather than silently minting an entire new sheet.
|
|
5039
|
+
*
|
|
5040
|
+
* @example Default count + show-once UI
|
|
5041
|
+
* ```ts
|
|
5042
|
+
* const { newCodes } = await db.rotateRecovery('acme', { profile: 'paper' })
|
|
5043
|
+
* showCodesToUser(newCodes)
|
|
5044
|
+
* ```
|
|
5045
|
+
*
|
|
5046
|
+
* @example STRICT-policy site with TOTP factor proof
|
|
5047
|
+
* ```ts
|
|
5048
|
+
* await db.rotateRecovery(
|
|
5049
|
+
* 'acme',
|
|
5050
|
+
* { profile: 'paper', count: 10 },
|
|
5051
|
+
* { factors: [{ kind: 'totp', proof: '123456' }] },
|
|
5052
|
+
* )
|
|
5053
|
+
* ```
|
|
5054
|
+
*/
|
|
5055
|
+
rotateRecovery(vault: string, options: RotateRecoveryOptions, factors?: FactorProofBundle): Promise<RotateRecoveryResult>;
|
|
5056
|
+
private rotateRecoveryPaper;
|
|
5057
|
+
private rotateRecoveryShamir;
|
|
5058
|
+
/**
|
|
5059
|
+
* **Atomic create-and-enroll for managed-mode vaults (#195).**
|
|
5060
|
+
*
|
|
5061
|
+
* Bootstraps a managed-mode vault and enrolls strong recovery in
|
|
5062
|
+
* a single ceremony. Under `passphraseMode: 'managed'`, every
|
|
5063
|
+
* `openVault` call requires a strong recovery profile (Shamir
|
|
5064
|
+
* today) to be enrolled — otherwise it throws
|
|
5065
|
+
* {@link ManagedRecoveryNotEnrolledError}. This method bypasses
|
|
5066
|
+
* the check temporarily so the keyring can be created, enrolls
|
|
5067
|
+
* the supplied recovery profile(s), then returns the vault.
|
|
5068
|
+
*
|
|
5069
|
+
* For Shamir enrollments, the show-once share strings come back
|
|
5070
|
+
* in `recoveryEnrollments[i].shares`. The hub never retains them
|
|
5071
|
+
* — the caller MUST display them to the user (once) before any
|
|
5072
|
+
* subsequent operation.
|
|
5073
|
+
*
|
|
5074
|
+
* Paper alone is NOT a strong profile under managed mode; passing
|
|
5075
|
+
* `{ profile: 'paper', ... }` without an accompanying shamir entry
|
|
5076
|
+
* is rejected at validation time.
|
|
5077
|
+
*
|
|
5078
|
+
* ```ts
|
|
5079
|
+
* const db = await createNoydb({
|
|
5080
|
+
* store, user: 'alice',
|
|
5081
|
+
* passphraseMode: 'managed',
|
|
5082
|
+
* sealingKey: macosKeychainSealingProvider({ ... }),
|
|
5083
|
+
* })
|
|
5084
|
+
*
|
|
5085
|
+
* const { vault, recoveryEnrollments } = await db.openVaultAndEnrollRecovery('acme', {
|
|
5086
|
+
* recovery: [{ profile: 'shamir', k: 2, n: 3 }],
|
|
5087
|
+
* })
|
|
5088
|
+
* for (const r of recoveryEnrollments) {
|
|
5089
|
+
* if (r.shares) showSharesToUser(r.shares) // ONCE
|
|
5090
|
+
* }
|
|
5091
|
+
* ```
|
|
5092
|
+
*
|
|
5093
|
+
* @throws ValidationError if recovery is empty, or contains no
|
|
5094
|
+
* strong profile under managed mode.
|
|
5095
|
+
*/
|
|
5096
|
+
openVaultAndEnrollRecovery(vault: string, opts: {
|
|
5097
|
+
readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>;
|
|
5098
|
+
readonly locale?: string;
|
|
5099
|
+
}): Promise<{
|
|
5100
|
+
readonly vault: Vault;
|
|
5101
|
+
readonly recoveryEnrollments: ReadonlyArray<EnrollRecoveryResult>;
|
|
5102
|
+
}>;
|
|
5103
|
+
/**
|
|
5104
|
+
* **Recovery flow under managed-passphrase mode (#195).**
|
|
5105
|
+
*
|
|
5106
|
+
* Replaces the sealed passphrase of a managed-mode vault with a
|
|
5107
|
+
* fresh 256-bit random, sealed under the configured
|
|
5108
|
+
* `SealingKeyProvider`. The user never sees the new passphrase.
|
|
5109
|
+
*
|
|
5110
|
+
* Internally:
|
|
5111
|
+
* 1. Verify the recovery proof (Shamir today) and unwrap the
|
|
5112
|
+
* DEK set.
|
|
5113
|
+
* 2. Mint a fresh 256-bit random as the new effective passphrase.
|
|
5114
|
+
* 3. Rewrap the DEK set under a fresh KEK derived from the new
|
|
5115
|
+
* passphrase (via the existing `recoverPassphrase` path).
|
|
5116
|
+
* 4. Seal the random bytes under the provider and overwrite
|
|
5117
|
+
* `_meta/sealed-passphrase`.
|
|
5118
|
+
* 5. Drop the keyring cache so the next operation re-derives.
|
|
5119
|
+
*
|
|
5120
|
+
* The vault's strong-recovery enrollment is preserved across
|
|
5121
|
+
* recovery (Shamir entries are not burned on use — see #196).
|
|
5122
|
+
*
|
|
5123
|
+
* @throws ValidationError if the Noydb instance is not in managed mode.
|
|
5124
|
+
*/
|
|
5125
|
+
recoverManagedPassphrase(vault: string, options: {
|
|
5126
|
+
readonly recoveryProof: RecoveryProof;
|
|
5127
|
+
readonly passphrasePolicy?: PassphrasePolicy;
|
|
5128
|
+
}): Promise<void>;
|
|
4788
5129
|
/**
|
|
4789
5130
|
* Atomic peer-recovery — re-wraps an EXISTING user's keyring under
|
|
4790
5131
|
* a fresh temp passphrase in a single store write. Closes #34's
|
|
@@ -4860,13 +5201,11 @@ declare class Noydb {
|
|
|
4860
5201
|
* await db.enrollRecovery('acme', { profile: 'paper', entries })
|
|
4861
5202
|
* ```
|
|
4862
5203
|
*/
|
|
4863
|
-
enrollRecovery(vault: string, enrollment:
|
|
4864
|
-
|
|
4865
|
-
entries: ReadonlyArray<PaperRecoveryEntry>;
|
|
4866
|
-
}): Promise<void>;
|
|
4867
|
-
/** Read the persisted paper-recovery entries. Used by `describeAuthConfig` (#13). */
|
|
5204
|
+
enrollRecovery(vault: string, enrollment: RecoveryEnrollmentInput): Promise<EnrollRecoveryResult>;
|
|
5205
|
+
/** Read the persisted recovery entries (paper + Shamir). Used by `describeAuthConfig` (#13). */
|
|
4868
5206
|
listRecoveryEntries(vault: string): Promise<{
|
|
4869
5207
|
paper: ReadonlyArray<PaperRecoveryEntry>;
|
|
5208
|
+
shamir: ReadonlyArray<ShamirRecoveryEntry>;
|
|
4870
5209
|
}>;
|
|
4871
5210
|
/**
|
|
4872
5211
|
* Register a tier-3 quick-unlock state for the vault. The state is
|
|
@@ -5062,6 +5401,39 @@ interface GuardStrategyHandle<T extends Record<string, unknown>> {
|
|
|
5062
5401
|
readonly __noydb_strategy: 'guard';
|
|
5063
5402
|
readonly spec: GuardStrategy<T>;
|
|
5064
5403
|
}
|
|
5404
|
+
/**
|
|
5405
|
+
* Existential erasure of `GuardStrategyHandle<T>` — used as the
|
|
5406
|
+
* element type of `ReadonlyArray<>` fields where the per-handle T
|
|
5407
|
+
* differs (e.g. `guardStrategies: [invoiceGuard, disbursementGuard]`).
|
|
5408
|
+
*
|
|
5409
|
+
* Background: `GuardStrategyHandle<T>` is INVARIANT in T because T
|
|
5410
|
+
* appears in callback positions on the spec (`check(incoming: T, ctx)`,
|
|
5411
|
+
* `invariant(changes: ReadonlyArray<GuardChange<T>>, ctx)`). So
|
|
5412
|
+
* `Handle<Invoice>` is not assignable to `Handle<Record<string, unknown>>`.
|
|
5413
|
+
* A bounded existential ("there exists some T satisfying the constraint
|
|
5414
|
+
* such that this is a Handle<T>") is the right shape; TypeScript has
|
|
5415
|
+
* no first-class existentials, so we fake it with a structurally narrow
|
|
5416
|
+
* interface that ERASES T from both the discriminant and the spec.
|
|
5417
|
+
*
|
|
5418
|
+
* Consumers continue to construct typed handles via `withGuard<T>(...)`
|
|
5419
|
+
* which returns `GuardStrategyHandle<T>`. Both `Handle<Invoice>` and
|
|
5420
|
+
* `Handle<Disbursement>` structurally assign to `GuardStrategyHandleAny`,
|
|
5421
|
+
* so an array of them is `GuardStrategyHandleAny[]`.
|
|
5422
|
+
*
|
|
5423
|
+
* Internal code that needs T re-narrows via the runtime discriminant
|
|
5424
|
+
* (`__noydb_strategy === 'guard'`) plus per-handle type information
|
|
5425
|
+
* carried by the registry.
|
|
5426
|
+
*
|
|
5427
|
+
* NOT exported from the public barrel — keeping this internal
|
|
5428
|
+
* discourages consumers from constructing it directly. Used only as
|
|
5429
|
+
* the array-element type on `Vault` / `NoydbOptions.guardStrategies`.
|
|
5430
|
+
*
|
|
5431
|
+
* @internal
|
|
5432
|
+
*/
|
|
5433
|
+
interface GuardStrategyHandleAny {
|
|
5434
|
+
readonly __noydb_strategy: 'guard';
|
|
5435
|
+
readonly spec: GuardStrategy<any>;
|
|
5436
|
+
}
|
|
5065
5437
|
/** Public registration shape. See `withGuard()`. */
|
|
5066
5438
|
interface GuardStrategy<T extends Record<string, unknown>> {
|
|
5067
5439
|
collection: string;
|
|
@@ -5154,8 +5526,8 @@ interface DerivedFromMeta {
|
|
|
5154
5526
|
*/
|
|
5155
5527
|
readonly strategyHash: string;
|
|
5156
5528
|
}
|
|
5157
|
-
/**
|
|
5158
|
-
interface
|
|
5529
|
+
/** Record-shape output — one source row produces (optionally) one output row at the source's id. */
|
|
5530
|
+
interface RecordOutputSpec {
|
|
5159
5531
|
shape: 'record';
|
|
5160
5532
|
collection: string;
|
|
5161
5533
|
/**
|
|
@@ -5169,6 +5541,50 @@ interface OutputSpec {
|
|
|
5169
5541
|
*/
|
|
5170
5542
|
optional?: boolean;
|
|
5171
5543
|
}
|
|
5544
|
+
/**
|
|
5545
|
+
* Array-shape output (#200) — one source row produces a variable-length
|
|
5546
|
+
* list of output rows, each with its own id (from the `key` extractor).
|
|
5547
|
+
*
|
|
5548
|
+
* On every source-row change, the dispatcher diffs the previously
|
|
5549
|
+
* emitted key set against the new one: removed keys are deleted via
|
|
5550
|
+
* `_internalDelete`, new and unchanged keys are upserted via
|
|
5551
|
+
* `Collection.put`. Strict-mode rollback is preserved via the existing
|
|
5552
|
+
* `_executed` tracking.
|
|
5553
|
+
*
|
|
5554
|
+
* Storage of the per-source-row key set lives at
|
|
5555
|
+
* `_meta/derivations-fanout/<source>/<sourceId>/<outputKey>` as a
|
|
5556
|
+
* plain JSON sidecar — keeps dispatch cost O(1) per source row.
|
|
5557
|
+
*
|
|
5558
|
+
* **Slice 1 limitation**: only `lifecycle: 'eager'` is supported.
|
|
5559
|
+
* Registering an array-shape output with `lifecycle: 'lazy'` throws
|
|
5560
|
+
* at `withDerivation` construction time.
|
|
5561
|
+
*/
|
|
5562
|
+
interface ArrayOutputSpec {
|
|
5563
|
+
shape: 'array';
|
|
5564
|
+
collection: string;
|
|
5565
|
+
/**
|
|
5566
|
+
* Stable identity extractor for each derived row. Called on every
|
|
5567
|
+
* row returned by `derive`. The string MUST be unique within a
|
|
5568
|
+
* single invocation — duplicate keys throw
|
|
5569
|
+
* `DerivationOutputShapeError`.
|
|
5570
|
+
*
|
|
5571
|
+
* Type is intentionally `(out: Record<string, unknown>) => string`
|
|
5572
|
+
* (not generic) because OutputSpec is type-erased at the registry
|
|
5573
|
+
* level. Strategy-level inference still produces typed `out`
|
|
5574
|
+
* through the strategy's `outputs` map.
|
|
5575
|
+
*/
|
|
5576
|
+
key: (output: Record<string, unknown>) => string;
|
|
5577
|
+
/**
|
|
5578
|
+
* Cap on derived rows per source-row invocation. Defaults to 64.
|
|
5579
|
+
* Raise for carry-forward cases (e.g. monthly expansion of
|
|
5580
|
+
* multi-year contracts). Exceeding the cap throws
|
|
5581
|
+
* `DerivationCapExceededError` BEFORE any writes — partial fanout
|
|
5582
|
+
* is never persisted.
|
|
5583
|
+
*/
|
|
5584
|
+
maxFanout?: number;
|
|
5585
|
+
}
|
|
5586
|
+
/** Discriminated union — record + array. */
|
|
5587
|
+
type OutputSpec = RecordOutputSpec | ArrayOutputSpec;
|
|
5172
5588
|
/**
|
|
5173
5589
|
* Registration shape passed to `withDerivation()`.
|
|
5174
5590
|
*
|
|
@@ -5298,6 +5714,28 @@ interface MaterializedViewOutput {
|
|
|
5298
5714
|
value: unknown;
|
|
5299
5715
|
};
|
|
5300
5716
|
}
|
|
5717
|
+
/**
|
|
5718
|
+
* One arm of a UNION materialized view. Reads rows from `collection`,
|
|
5719
|
+
* then maps each into the MV's row shape via `map`.
|
|
5720
|
+
*
|
|
5721
|
+
* The per-source `map` is the schema-unification boundary — sibling
|
|
5722
|
+
* collections can have different schemas, and `map` is where they
|
|
5723
|
+
* meet the MV's row type. The hub does NOT compare schemas across
|
|
5724
|
+
* arms; consumer responsibility is that every arm's `map` returns
|
|
5725
|
+
* the same shape (the strategy's `TRow` type parameter enforces this
|
|
5726
|
+
* at compile time).
|
|
5727
|
+
*/
|
|
5728
|
+
interface UnionSource<TRow extends Record<string, unknown>> {
|
|
5729
|
+
/** Source collection name. Must exist in the vault. */
|
|
5730
|
+
readonly collection: string;
|
|
5731
|
+
/**
|
|
5732
|
+
* Pure function from a source row to the unified MV row shape.
|
|
5733
|
+
* Called once per source row at materialization time. Each arm's
|
|
5734
|
+
* mapped output is concatenated into a single stream before
|
|
5735
|
+
* `groupBy` + `aggregate` run.
|
|
5736
|
+
*/
|
|
5737
|
+
readonly map: (sourceRow: Record<string, unknown>) => TRow;
|
|
5738
|
+
}
|
|
5301
5739
|
/**
|
|
5302
5740
|
* Registration shape passed to `withMaterializedView()`.
|
|
5303
5741
|
*
|
|
@@ -5310,16 +5748,59 @@ interface MaterializedViewStrategy<TRow extends Record<string, unknown>> {
|
|
|
5310
5748
|
*/
|
|
5311
5749
|
name: string;
|
|
5312
5750
|
/**
|
|
5313
|
-
* Declared query. Called at registration time
|
|
5314
|
-
* accessor so the closure can compose collections
|
|
5315
|
-
* pre-existing in-scope references; called again at each
|
|
5751
|
+
* Declared query (single-source mode). Called at registration time
|
|
5752
|
+
* with a vault-shaped accessor so the closure can compose collections
|
|
5753
|
+
* without pre-existing in-scope references; called again at each
|
|
5754
|
+
* refresh.
|
|
5316
5755
|
*
|
|
5317
5756
|
* Built via the same `Query<T>` chainable builder used elsewhere —
|
|
5318
5757
|
* `.where()`, `.join()`, `.groupBy()`, `.aggregate()`. The
|
|
5319
5758
|
* dependency analyzer walks the returned plan to determine source
|
|
5320
5759
|
* collections.
|
|
5760
|
+
*
|
|
5761
|
+
* Mutually exclusive with {@link unionSources}: a strategy must
|
|
5762
|
+
* declare exactly one of `query` (single-source) or `unionSources`
|
|
5763
|
+
* (multi-source UNION). Registration throws
|
|
5764
|
+
* `MaterializedViewConfigError` if both are set or neither is set.
|
|
5765
|
+
*/
|
|
5766
|
+
query?: (db: MVQueryContext) => Query<TRow>;
|
|
5767
|
+
/**
|
|
5768
|
+
* UNION-form sources (#165): an explicit list of sibling collections
|
|
5769
|
+
* that contribute rows to a single MV. Each arm's `map` projects a
|
|
5770
|
+
* source row into the MV's unified row shape; the mapped streams are
|
|
5771
|
+
* concatenated, then {@link groupBy} + {@link aggregate} run on the
|
|
5772
|
+
* combined output.
|
|
5773
|
+
*
|
|
5774
|
+
* Mutually exclusive with {@link query}. Registration throws
|
|
5775
|
+
* `MaterializedViewConfigError` if both are set, if `unionSources`
|
|
5776
|
+
* has fewer than 2 arms, or if two arms name the same `collection`.
|
|
5777
|
+
*
|
|
5778
|
+
* UNION mode replaces the dependency-analyzer path: the source
|
|
5779
|
+
* collections come directly from `unionSources[].collection`, and
|
|
5780
|
+
* {@link sources} is ignored.
|
|
5781
|
+
*/
|
|
5782
|
+
unionSources?: ReadonlyArray<UnionSource<TRow>>;
|
|
5783
|
+
/**
|
|
5784
|
+
* Group-key field(s) for UNION mode (#165). Applied to the
|
|
5785
|
+
* concatenated mapped-row stream from {@link unionSources} before
|
|
5786
|
+
* {@link aggregate} runs. Accepts a single field name or a tuple of
|
|
5787
|
+
* field names for multi-key grouping (same shape as
|
|
5788
|
+
* `Query.groupBy(...fields)`).
|
|
5789
|
+
*
|
|
5790
|
+
* UNION-mode only. Ignored if {@link query} is set — single-source
|
|
5791
|
+
* grouping is expressed inside the `Query<T>` returned from `query()`
|
|
5792
|
+
* via `.groupBy(...).aggregate(...)`.
|
|
5793
|
+
*/
|
|
5794
|
+
groupBy?: string | ReadonlyArray<string>;
|
|
5795
|
+
/**
|
|
5796
|
+
* Aggregation spec for UNION mode (#165). Applied per-group after
|
|
5797
|
+
* {@link groupBy} buckets the concatenated mapped-row stream from
|
|
5798
|
+
* {@link unionSources}. Same shape as the `AggregateSpec` passed to
|
|
5799
|
+
* `Query.aggregate()`.
|
|
5800
|
+
*
|
|
5801
|
+
* UNION-mode only. Ignored if {@link query} is set.
|
|
5321
5802
|
*/
|
|
5322
|
-
|
|
5803
|
+
aggregate?: AggregateSpec;
|
|
5323
5804
|
/**
|
|
5324
5805
|
* Pure function from a materialized row → stable id used in the
|
|
5325
5806
|
* output collection. Required — explicit always beats default-with-pitfalls
|
|
@@ -6268,6 +6749,159 @@ declare class UserApi {
|
|
|
6268
6749
|
private fireChange;
|
|
6269
6750
|
}
|
|
6270
6751
|
|
|
6752
|
+
/**
|
|
6753
|
+
* Persisted-schema envelope shape.
|
|
6754
|
+
*
|
|
6755
|
+
* Stored encrypted under `_schemas/<collection>` with the same DEK as the
|
|
6756
|
+
* collection's records. Auditors who can unlock the collection's data can
|
|
6757
|
+
* also read its schema; nothing more.
|
|
6758
|
+
*
|
|
6759
|
+
* @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
|
|
6760
|
+
*
|
|
6761
|
+
* @module
|
|
6762
|
+
*/
|
|
6763
|
+
/** Family of Standard Schema v1 validator the persisted snapshot was derived from. */
|
|
6764
|
+
type PersistedSchemaKind = 'Zod' | 'Valibot' | 'ArkType' | 'Effect' | 'Unknown';
|
|
6765
|
+
/**
|
|
6766
|
+
* Plaintext payload encrypted into the `_data` field of the
|
|
6767
|
+
* `_schemas/<collection>` envelope. The wrapper `EncryptedEnvelope` adds
|
|
6768
|
+
* `_noydb`, `_v`, `_ts`, `_iv`, `_data` per the standard noy-db record
|
|
6769
|
+
* format.
|
|
6770
|
+
*/
|
|
6771
|
+
interface PersistedSchemaEnvelope {
|
|
6772
|
+
readonly _noydb_schema: 1;
|
|
6773
|
+
/** Detected validator family. */
|
|
6774
|
+
readonly kind: PersistedSchemaKind;
|
|
6775
|
+
/**
|
|
6776
|
+
* JSON Schema (Draft 2020-12) derived from the validator. Null when
|
|
6777
|
+
* derivation isn't yet supported for `kind`; in that case `reason` is
|
|
6778
|
+
* populated.
|
|
6779
|
+
*/
|
|
6780
|
+
readonly jsonSchema: object | null;
|
|
6781
|
+
/** SHA-256 (hex) of the canonicalised JSON Schema, or null when unavailable. */
|
|
6782
|
+
readonly hash: string | null;
|
|
6783
|
+
/** Human-readable reason when `jsonSchema` is null. */
|
|
6784
|
+
readonly reason?: string;
|
|
6785
|
+
/** ISO-8601 timestamp of the most recent derivation write. */
|
|
6786
|
+
readonly derivedAt: string;
|
|
6787
|
+
}
|
|
6788
|
+
|
|
6789
|
+
/**
|
|
6790
|
+
* Types for {@link VaultSchemaSnapshot} — the structured object returned
|
|
6791
|
+
* by `vault.dumpSchema()`. Consumed by the upcoming `noydb describe`
|
|
6792
|
+
* CLI to emit human-readable YAML/JSON audit output.
|
|
6793
|
+
*
|
|
6794
|
+
* @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
|
|
6795
|
+
*
|
|
6796
|
+
* @module
|
|
6797
|
+
*/
|
|
6798
|
+
|
|
6799
|
+
/** Where the field-level info in the snapshot came from. */
|
|
6800
|
+
type FieldSource = 'persisted' | 'live-validator' | 'sampled' | 'unknown';
|
|
6801
|
+
interface FieldDescriptor {
|
|
6802
|
+
/** Inferred type tag: 'string' | 'number' | 'boolean' | 'enum' | 'object' | 'array' | 'null' | 'opaque'. */
|
|
6803
|
+
readonly type: string;
|
|
6804
|
+
/** Where this field info was sourced from. */
|
|
6805
|
+
readonly source: FieldSource;
|
|
6806
|
+
/** Optional constraints — minLength, maxLength, enum values, gt, etc. */
|
|
6807
|
+
readonly constraints?: Record<string, unknown>;
|
|
6808
|
+
/** True when the schema marks this field optional. */
|
|
6809
|
+
readonly optional?: boolean;
|
|
6810
|
+
/** Foreign-key target as `<collection>.<field>` when declared. */
|
|
6811
|
+
readonly references?: string;
|
|
6812
|
+
}
|
|
6813
|
+
interface CollectionStats {
|
|
6814
|
+
readonly records: number;
|
|
6815
|
+
readonly bytes: number;
|
|
6816
|
+
readonly bytesAvg: number;
|
|
6817
|
+
readonly bytesMin: number;
|
|
6818
|
+
readonly bytesMax: number;
|
|
6819
|
+
/** ISO-8601 from min(_ts) across envelopes. Empty string when no records. */
|
|
6820
|
+
readonly oldest: string;
|
|
6821
|
+
/** ISO-8601 from max(_ts) across envelopes. Empty string when no records. */
|
|
6822
|
+
readonly newest: string;
|
|
6823
|
+
}
|
|
6824
|
+
interface CollectionDescriptor {
|
|
6825
|
+
readonly fields: Record<string, FieldDescriptor>;
|
|
6826
|
+
readonly indexes: ReadonlyArray<{
|
|
6827
|
+
readonly fields: ReadonlyArray<string>;
|
|
6828
|
+
readonly unique?: boolean;
|
|
6829
|
+
}>;
|
|
6830
|
+
readonly refs: Record<string, {
|
|
6831
|
+
readonly target: string;
|
|
6832
|
+
readonly mode: 'strict' | 'warn' | 'cascade';
|
|
6833
|
+
}>;
|
|
6834
|
+
readonly validator?: {
|
|
6835
|
+
readonly kind: PersistedSchemaKind;
|
|
6836
|
+
readonly source: 'persisted' | 'live-validator';
|
|
6837
|
+
};
|
|
6838
|
+
readonly stats?: CollectionStats;
|
|
6839
|
+
}
|
|
6840
|
+
interface MaterializedViewDescriptor {
|
|
6841
|
+
readonly sources: ReadonlyArray<string>;
|
|
6842
|
+
readonly groupBy?: ReadonlyArray<string>;
|
|
6843
|
+
readonly aggregate?: Record<string, string>;
|
|
6844
|
+
readonly refresh: string;
|
|
6845
|
+
readonly stats?: CollectionStats;
|
|
6846
|
+
}
|
|
6847
|
+
interface OverlayViewDescriptor {
|
|
6848
|
+
readonly base: string;
|
|
6849
|
+
readonly overlay: string;
|
|
6850
|
+
}
|
|
6851
|
+
interface DerivationDescriptor {
|
|
6852
|
+
readonly source: string;
|
|
6853
|
+
readonly outputs: ReadonlyArray<string>;
|
|
6854
|
+
}
|
|
6855
|
+
interface InternalCollectionStats {
|
|
6856
|
+
readonly records: number;
|
|
6857
|
+
readonly bytes: number;
|
|
6858
|
+
}
|
|
6859
|
+
interface VaultSchemaSnapshot {
|
|
6860
|
+
readonly _noydb_snapshot: 1;
|
|
6861
|
+
readonly vault: string;
|
|
6862
|
+
readonly emittedAt: string;
|
|
6863
|
+
readonly subsystems: Record<string, boolean>;
|
|
6864
|
+
readonly aclRoles?: ReadonlyArray<string>;
|
|
6865
|
+
readonly collections: Record<string, CollectionDescriptor>;
|
|
6866
|
+
readonly materializedViews: Record<string, MaterializedViewDescriptor>;
|
|
6867
|
+
readonly overlayViews: Record<string, OverlayViewDescriptor>;
|
|
6868
|
+
readonly derivations: Record<string, DerivationDescriptor>;
|
|
6869
|
+
/** Only present when `dumpSchema({ withStats: true })` was called. */
|
|
6870
|
+
readonly internal?: Record<string, InternalCollectionStats>;
|
|
6871
|
+
}
|
|
6872
|
+
interface DumpSchemaOptions {
|
|
6873
|
+
/** When true, walk every collection's envelopes to compute counters. Default `false`. */
|
|
6874
|
+
readonly withStats?: boolean;
|
|
6875
|
+
/** Sample N records per collection lacking a persisted/live schema. Default 50. `0` disables sampling. */
|
|
6876
|
+
readonly sampleSize?: number;
|
|
6877
|
+
}
|
|
6878
|
+
|
|
6879
|
+
/**
|
|
6880
|
+
* Orchestrate the structural walk of a Vault, producing a
|
|
6881
|
+
* {@link VaultSchemaSnapshot}. Called from `Vault.dumpSchema()`.
|
|
6882
|
+
*
|
|
6883
|
+
* @module
|
|
6884
|
+
*/
|
|
6885
|
+
|
|
6886
|
+
/**
|
|
6887
|
+
* The minimal slice of Vault internal state the walker needs.
|
|
6888
|
+
* Exposed via `vault._introspectState()` to keep the public Vault
|
|
6889
|
+
* surface narrow.
|
|
6890
|
+
*
|
|
6891
|
+
* @internal
|
|
6892
|
+
*/
|
|
6893
|
+
interface VaultIntrospectState {
|
|
6894
|
+
readonly name: string;
|
|
6895
|
+
readonly adapter: NoydbStore;
|
|
6896
|
+
readonly collectionCache: Map<string, Collection<unknown>>;
|
|
6897
|
+
readonly refRegistry: RefRegistry;
|
|
6898
|
+
readonly getDEK: (collectionName: string) => Promise<CryptoKey>;
|
|
6899
|
+
readonly subsystems: Record<string, boolean>;
|
|
6900
|
+
readonly mvRegistry: unknown;
|
|
6901
|
+
readonly overlayRegistry: unknown;
|
|
6902
|
+
readonly derivationRegistry: unknown;
|
|
6903
|
+
}
|
|
6904
|
+
|
|
6271
6905
|
/** A vault (tenant namespace) containing collections. */
|
|
6272
6906
|
declare class Vault {
|
|
6273
6907
|
private readonly adapter;
|
|
@@ -6391,6 +7025,16 @@ declare class Vault {
|
|
|
6391
7025
|
* docstring.
|
|
6392
7026
|
*/
|
|
6393
7027
|
private ledgerStore;
|
|
7028
|
+
/**
|
|
7029
|
+
* Background writes for persisted-schema envelopes (#schema-dump v0
|
|
7030
|
+
* slice 1). One promise per `collection({ persistJsonSchema: true })`
|
|
7031
|
+
* registration that actually fired a derive call. Fire-and-forget
|
|
7032
|
+
* from the collection factory; tests await
|
|
7033
|
+
* {@link _drainPendingSchemaWrites} before asserting on storage.
|
|
7034
|
+
* Production code does not need to drain — the writes are
|
|
7035
|
+
* idempotent fingerprints, not correctness invariants.
|
|
7036
|
+
*/
|
|
7037
|
+
private _pendingSchemaWrites;
|
|
6394
7038
|
/**
|
|
6395
7039
|
* Per-vault foreign-key reference registry. Collections
|
|
6396
7040
|
* register their `refs` option here on construction; the
|
|
@@ -6502,7 +7146,7 @@ declare class Vault {
|
|
|
6502
7146
|
historyStrategy?: HistoryStrategy | undefined;
|
|
6503
7147
|
i18nStrategy?: I18nStrategy | undefined;
|
|
6504
7148
|
syncStrategy?: SyncStrategy | undefined;
|
|
6505
|
-
guardStrategies?: ReadonlyArray<
|
|
7149
|
+
guardStrategies?: ReadonlyArray<GuardStrategyHandleAny> | undefined;
|
|
6506
7150
|
});
|
|
6507
7151
|
/**
|
|
6508
7152
|
* Construct (or reconstruct) the lazy DEK resolver. Captures the
|
|
@@ -6575,7 +7219,26 @@ declare class Vault {
|
|
|
6575
7219
|
tiers?: readonly number[];
|
|
6576
7220
|
/** — how lower-tier reads see above-tier records. */
|
|
6577
7221
|
tierMode?: TierMode;
|
|
7222
|
+
/**
|
|
7223
|
+
* Opt-in persisted JSON Schema. When `true` AND a Zod `schema` is
|
|
7224
|
+
* provided, hub derives a JSON Schema via `zod-to-json-schema`
|
|
7225
|
+
* (optional peer-dep) and writes an encrypted snapshot to
|
|
7226
|
+
* `_schemas/<collectionName>`. Re-runs on every open; hash-skip
|
|
7227
|
+
* avoids write churn when the schema is unchanged.
|
|
7228
|
+
*
|
|
7229
|
+
* Default: `false`. Non-Zod Standard Schema validators receive a
|
|
7230
|
+
* stub envelope flagging the kind without a JSON Schema body.
|
|
7231
|
+
*
|
|
7232
|
+
* @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
|
|
7233
|
+
*/
|
|
7234
|
+
persistJsonSchema?: boolean;
|
|
6578
7235
|
}): Collection<T>;
|
|
7236
|
+
/**
|
|
7237
|
+
* Await all background persisted-schema writes triggered by
|
|
7238
|
+
* `collection({ persistJsonSchema: true })` calls on this vault.
|
|
7239
|
+
* Used in tests; production code does not need to call this.
|
|
7240
|
+
*/
|
|
7241
|
+
_drainPendingSchemaWrites(): Promise<void>;
|
|
6579
7242
|
/**
|
|
6580
7243
|
* Validate i18nText fields on a `put()`. Called by Collection just
|
|
6581
7244
|
* before the adapter write, after schema validation. Throws
|
|
@@ -6876,7 +7539,7 @@ declare class Vault {
|
|
|
6876
7539
|
* accessor `_getReadOnlyFacade()` (called from the tx amendment
|
|
6877
7540
|
* runner) stays synchronous.
|
|
6878
7541
|
*/
|
|
6879
|
-
_initGuards(handles: ReadonlyArray<
|
|
7542
|
+
_initGuards(handles: ReadonlyArray<GuardStrategyHandleAny>): Promise<void>;
|
|
6880
7543
|
/**
|
|
6881
7544
|
* @internal — Collection.put calls into this. Returns `null` for
|
|
6882
7545
|
* vaults that never registered any guard strategy. Callers MUST
|
|
@@ -7186,6 +7849,34 @@ declare class Vault {
|
|
|
7186
7849
|
private _decryptPeriodRecord;
|
|
7187
7850
|
/** List all collection names in this vault. */
|
|
7188
7851
|
collections(): Promise<string[]>;
|
|
7852
|
+
/**
|
|
7853
|
+
* Emit a structured introspection snapshot of this vault — vault name,
|
|
7854
|
+
* subsystem opt-in matrix, collections + their fields, materialized
|
|
7855
|
+
* views, overlay views, derivations. With `withStats: true`, walks
|
|
7856
|
+
* every collection's envelopes to compute record counts, byte totals,
|
|
7857
|
+
* and oldest/newest timestamps.
|
|
7858
|
+
*
|
|
7859
|
+
* Consumed by the `noydb describe` CLI to produce human-readable
|
|
7860
|
+
* audit YAML/JSON from a `.noydb` bundle.
|
|
7861
|
+
*
|
|
7862
|
+
* Field provenance:
|
|
7863
|
+
* - `persisted`: read from `_schemas/<col>` envelope (Route B opt-in)
|
|
7864
|
+
* - `live-validator`: derived in-process from a Zod schema attached
|
|
7865
|
+
* to the live `Collection`
|
|
7866
|
+
* - `sampled`: inferred from decrypted records (deferred to a follow-up)
|
|
7867
|
+
* - `unknown`: no schema info available
|
|
7868
|
+
*
|
|
7869
|
+
* @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
|
|
7870
|
+
*/
|
|
7871
|
+
dumpSchema(opts?: DumpSchemaOptions): Promise<VaultSchemaSnapshot>;
|
|
7872
|
+
/**
|
|
7873
|
+
* Internal accessor for {@link dumpVaultSchema}. Exposes the structural
|
|
7874
|
+
* state the walker needs (collection cache, registries, ref registry,
|
|
7875
|
+
* adapter) without widening the public Vault surface.
|
|
7876
|
+
*
|
|
7877
|
+
* @internal
|
|
7878
|
+
*/
|
|
7879
|
+
_introspectState(): VaultIntrospectState;
|
|
7189
7880
|
/**
|
|
7190
7881
|
* Return the stable opaque bundle handle for this vault,
|
|
7191
7882
|
* generating and persisting a fresh ULID on first call.
|
|
@@ -8241,8 +8932,20 @@ declare class Collection<T> {
|
|
|
8241
8932
|
staleMs?: number;
|
|
8242
8933
|
pollIntervalMs?: number;
|
|
8243
8934
|
}): PresenceHandle<P>;
|
|
8244
|
-
/**
|
|
8245
|
-
|
|
8935
|
+
/**
|
|
8936
|
+
* Create or update a record.
|
|
8937
|
+
*
|
|
8938
|
+
* @param id Record identifier.
|
|
8939
|
+
* @param record The record body (validated by the collection's schema
|
|
8940
|
+
* if one was attached at `vault.collection(...)` time).
|
|
8941
|
+
* @param options Optional metadata for audit + import workflows.
|
|
8942
|
+
* `reason` is stamped onto the resulting ledger entry
|
|
8943
|
+
* (see #1) so audit consumers can filter via
|
|
8944
|
+
* `entries.filter(e => e.reason?.startsWith('import:'))`.
|
|
8945
|
+
*/
|
|
8946
|
+
put(id: string, record: T, options?: {
|
|
8947
|
+
readonly reason?: string;
|
|
8948
|
+
}): Promise<void>;
|
|
8246
8949
|
/**
|
|
8247
8950
|
* Fire registered MV strategies whose dependency set includes this
|
|
8248
8951
|
* collection. Eager-mode MVs re-materialize inline via
|
|
@@ -8310,6 +9013,28 @@ declare class Collection<T> {
|
|
|
8310
9013
|
*/
|
|
8311
9014
|
_internalDelete(id: string, txCtx?: TxContext | null): Promise<void>;
|
|
8312
9015
|
private _doDelete;
|
|
9016
|
+
/**
|
|
9017
|
+
* Cascade deletes of array-shape derived rows when a source row is
|
|
9018
|
+
* deleted (#200). Reads each registered strategy's fanout sidecar
|
|
9019
|
+
* for this source id, deletes every listed derived row, then
|
|
9020
|
+
* deletes the sidecar itself.
|
|
9021
|
+
*
|
|
9022
|
+
* Record-shape derivations are skipped — see _doDelete's comment
|
|
9023
|
+
* for why the asymmetry is correct.
|
|
9024
|
+
*
|
|
9025
|
+
* @internal
|
|
9026
|
+
*/
|
|
9027
|
+
private dispatchArrayDerivationsOnDelete;
|
|
9028
|
+
/**
|
|
9029
|
+
* Mirror of {@link dispatchMaterializedViews} for the delete path
|
|
9030
|
+
* (#181). No record content is available (it's gone), so the
|
|
9031
|
+
* `_materializedFrom` skip used by the put-side dispatch doesn't
|
|
9032
|
+
* apply here — instead, the recursion guard is the `internal` gate
|
|
9033
|
+
* at the `_doDelete` call site above.
|
|
9034
|
+
*
|
|
9035
|
+
* @internal
|
|
9036
|
+
*/
|
|
9037
|
+
private dispatchMaterializedViewsOnDelete;
|
|
8313
9038
|
/**
|
|
8314
9039
|
* List all records in the collection.
|
|
8315
9040
|
*
|
|
@@ -9138,6 +9863,160 @@ interface SessionStrategy {
|
|
|
9138
9863
|
revokeAllSessions(): void;
|
|
9139
9864
|
}
|
|
9140
9865
|
|
|
9866
|
+
/**
|
|
9867
|
+
* Managed-passphrase mode — issue #14, rubber-hose-resistant vaults.
|
|
9868
|
+
*
|
|
9869
|
+
* A vault mode where the passphrase is machine-generated and never
|
|
9870
|
+
* exposed to the user, sealed under a developer-provided
|
|
9871
|
+
* {@link SealingKeyProvider} (macOS Keychain, Windows Credential
|
|
9872
|
+
* Manager, libsecret, AWS KMS, …). The user has no secret to give
|
|
9873
|
+
* up to coercion — they can't reveal what they don't know.
|
|
9874
|
+
*
|
|
9875
|
+
* ## Components in this file
|
|
9876
|
+
*
|
|
9877
|
+
* - {@link SealingKeyProvider} — the interface concrete providers
|
|
9878
|
+
* implement. Provider implementations live OUTSIDE hub (per-
|
|
9879
|
+
* platform packages).
|
|
9880
|
+
* - {@link MemorySealingKeyProvider} — in-memory test provider; uses
|
|
9881
|
+
* a deterministic per-instance "key" so two providers with
|
|
9882
|
+
* different ids cannot unseal each other's outputs.
|
|
9883
|
+
* - {@link loadSealedPassphrase} / {@link saveSealedPassphrase} —
|
|
9884
|
+
* plaintext envelope storage at `_meta/sealed-passphrase`.
|
|
9885
|
+
* Mirrors the `_meta/handle` and `_meta/public-envelope` AES-
|
|
9886
|
+
* GCM-bypassed patterns. The sealing layer (provider's job)
|
|
9887
|
+
* is the security boundary; hub doesn't have a key to encrypt
|
|
9888
|
+
* with at this layer — that's the whole point of the design.
|
|
9889
|
+
* - {@link resolveManagedSecret} — orchestrates the "generate +
|
|
9890
|
+
* seal + persist on first open; unseal on reopen" flow.
|
|
9891
|
+
* Returns the plaintext passphrase string that the rest of the
|
|
9892
|
+
* `createNoydb` keyring path consumes.
|
|
9893
|
+
*
|
|
9894
|
+
* Slice 1 of #14. Deferred to follow-ups:
|
|
9895
|
+
* - Block `rotate-passphrase` policy gate under managed mode.
|
|
9896
|
+
* - Mandatory strong-recovery enforcement (depends on #10).
|
|
9897
|
+
* - Recovery flow under managed mode (generates fresh sealed phrase).
|
|
9898
|
+
*
|
|
9899
|
+
* @see docs/subsystems/session-tiers.md → Managed-passphrase mode
|
|
9900
|
+
*
|
|
9901
|
+
* @module
|
|
9902
|
+
*/
|
|
9903
|
+
|
|
9904
|
+
/**
|
|
9905
|
+
* The contract concrete providers (per-platform key stores) implement
|
|
9906
|
+
* to seal and unseal a hub-generated random passphrase. The plaintext
|
|
9907
|
+
* passphrase NEVER leaves hub-controlled memory in unsealed form —
|
|
9908
|
+
* the provider receives the bytes, returns opaque sealed bytes, and
|
|
9909
|
+
* later reverses the operation. Hub treats the sealed bytes as
|
|
9910
|
+
* fully opaque.
|
|
9911
|
+
*
|
|
9912
|
+
* Implementations live OUTSIDE `@noy-db/hub` (separate packages
|
|
9913
|
+
* per the issue's "Concrete providers (live outside hub)" note):
|
|
9914
|
+
*
|
|
9915
|
+
* | Platform | Package (TBD) | Backing |
|
|
9916
|
+
* |---|---|---|
|
|
9917
|
+
* | macOS | `@noy-db/seal-macos-keychain` | Security.framework |
|
|
9918
|
+
* | Windows | `@noy-db/seal-wincred` | Credential Manager |
|
|
9919
|
+
* | Linux | `@noy-db/seal-libsecret` | libsecret / secret-service |
|
|
9920
|
+
* | Cloud / server | `@noy-db/seal-aws-kms` | AWS KMS Decrypt |
|
|
9921
|
+
*/
|
|
9922
|
+
interface SealingKeyProvider {
|
|
9923
|
+
/**
|
|
9924
|
+
* Non-sensitive identifier disclosed in the persisted envelope.
|
|
9925
|
+
* Surfaced to consumers via `loadSealedPassphrase().providerId` so
|
|
9926
|
+
* a vault opened with the wrong provider class can detect the
|
|
9927
|
+
* mismatch and surface a clear error. NOT secret — fine to log.
|
|
9928
|
+
*
|
|
9929
|
+
* Suggested format: `<family>:<scope>` — e.g. `macos-keychain:com.acme.app`,
|
|
9930
|
+
* `aws-kms:arn:aws:kms:us-east-1:123:key/abc`. The hub never
|
|
9931
|
+
* parses this; it's purely audit metadata.
|
|
9932
|
+
*/
|
|
9933
|
+
readonly id: string;
|
|
9934
|
+
/** Seal raw passphrase bytes. Output bytes are opaque to hub. */
|
|
9935
|
+
seal(passphrase: Uint8Array): Promise<Uint8Array>;
|
|
9936
|
+
/**
|
|
9937
|
+
* Reverse {@link seal}. MUST throw on tamper, wrong-provider, or
|
|
9938
|
+
* any other failure — hub treats a thrown error as "this provider
|
|
9939
|
+
* cannot unlock this vault" and surfaces it to the caller.
|
|
9940
|
+
*/
|
|
9941
|
+
unseal(sealed: Uint8Array): Promise<Uint8Array>;
|
|
9942
|
+
}
|
|
9943
|
+
/**
|
|
9944
|
+
* In-memory test provider. NOT secure — uses a deterministic
|
|
9945
|
+
* per-instance "key" (16-byte SHA-256 of `id`) XOR'd over the
|
|
9946
|
+
* passphrase plus a 4-byte provider-id fingerprint prefix. The XOR is
|
|
9947
|
+
* sufficient to make different `id` values produce mutually-unsealable
|
|
9948
|
+
* outputs (the contract tests for that), but offers ZERO real
|
|
9949
|
+
* confidentiality — never use outside tests.
|
|
9950
|
+
*
|
|
9951
|
+
* Replace with a real platform provider in production.
|
|
9952
|
+
*/
|
|
9953
|
+
declare class MemorySealingKeyProvider implements SealingKeyProvider {
|
|
9954
|
+
readonly id: string;
|
|
9955
|
+
private readonly fingerprint;
|
|
9956
|
+
private readonly keyBytes;
|
|
9957
|
+
constructor(opts: {
|
|
9958
|
+
id: string;
|
|
9959
|
+
});
|
|
9960
|
+
seal(passphrase: Uint8Array): Promise<Uint8Array>;
|
|
9961
|
+
unseal(sealed: Uint8Array): Promise<Uint8Array>;
|
|
9962
|
+
}
|
|
9963
|
+
/** Reserved id for the managed-passphrase envelope under `_meta`. */
|
|
9964
|
+
declare const SEALED_PASSPHRASE_RECORD_ID: "sealed-passphrase";
|
|
9965
|
+
/** Plaintext payload stored inside the `_meta/sealed-passphrase` envelope. */
|
|
9966
|
+
interface SealedPassphrase {
|
|
9967
|
+
readonly _noydb_sealed: 1;
|
|
9968
|
+
readonly providerId: string;
|
|
9969
|
+
/** Sealed bytes. Base64-encoded on the wire; decoded on load. */
|
|
9970
|
+
readonly sealed: Uint8Array;
|
|
9971
|
+
}
|
|
9972
|
+
/**
|
|
9973
|
+
* Wire-format envelope persisted at `_meta/sealed-passphrase` for
|
|
9974
|
+
* managed-mode vaults. The provider produces raw sealed bytes via
|
|
9975
|
+
* {@link SealingKeyProvider.seal}; this wrapper carries the dispatch
|
|
9976
|
+
* metadata hub needs to pick the right provider on the unseal path.
|
|
9977
|
+
*
|
|
9978
|
+
* Stability boundary: once shipped, the wire format only grows by
|
|
9979
|
+
* adding optional fields. See the at-* sealing dimension foundation
|
|
9980
|
+
* doc, §11.9.1.
|
|
9981
|
+
*
|
|
9982
|
+
* v1 shape (this release): `{ v: 1, _noydb_sealed: 1, pid, payload }`.
|
|
9983
|
+
*
|
|
9984
|
+
* Legacy shape (pre.14, pre.15): `{ _noydb_sealed: 1, providerId, sealed }`
|
|
9985
|
+
* — accepted on read for backwards compatibility; never produced on
|
|
9986
|
+
* write going forward.
|
|
9987
|
+
*/
|
|
9988
|
+
interface SealedEnvelope {
|
|
9989
|
+
/** Envelope schema version. v1 is the shape shipped in pre.16. */
|
|
9990
|
+
readonly v: 1;
|
|
9991
|
+
/** Magic marker for forensics + legacy-shape detection. */
|
|
9992
|
+
readonly _noydb_sealed: 1;
|
|
9993
|
+
/** Matches the producing provider's `.id`. Dispatch key on unseal. */
|
|
9994
|
+
readonly pid: string;
|
|
9995
|
+
/** Sealed bytes from the provider, base64-encoded on the wire. */
|
|
9996
|
+
readonly payload: string;
|
|
9997
|
+
}
|
|
9998
|
+
/**
|
|
9999
|
+
* Parse a `_meta/sealed-passphrase` `_data` JSON string into the
|
|
10000
|
+
* in-memory {@link SealedPassphrase} representation. Accepts both:
|
|
10001
|
+
*
|
|
10002
|
+
* 1. v1 wire format `{ v: 1, _noydb_sealed: 1, pid, payload }` —
|
|
10003
|
+
* the shape produced from pre.16 onward.
|
|
10004
|
+
* 2. Legacy wire format `{ _noydb_sealed: 1, providerId, sealed }` —
|
|
10005
|
+
* the shape produced in pre.14/pre.15. Read-only; never written
|
|
10006
|
+
* going forward.
|
|
10007
|
+
*
|
|
10008
|
+
* Returns `undefined` for any input that doesn't match either shape,
|
|
10009
|
+
* so callers can fall back to "no managed-mode envelope present."
|
|
10010
|
+
*
|
|
10011
|
+
* @internal — exported only for the migration safety-net test suite.
|
|
10012
|
+
*/
|
|
10013
|
+
declare function parseSealedEnvelope(raw: unknown): SealedPassphrase | undefined;
|
|
10014
|
+
declare function saveSealedPassphrase(store: NoydbStore, vault: string, payload: {
|
|
10015
|
+
readonly providerId: string;
|
|
10016
|
+
readonly sealed: Uint8Array;
|
|
10017
|
+
}): Promise<void>;
|
|
10018
|
+
declare function loadSealedPassphrase(store: NoydbStore, vault: string): Promise<SealedPassphrase | undefined>;
|
|
10019
|
+
|
|
9141
10020
|
/**
|
|
9142
10021
|
* Core types — the {@link NoydbStore} interface, envelope format, roles, and
|
|
9143
10022
|
* all configuration shapes consumed by {@link createNoydb}.
|
|
@@ -10656,7 +11535,7 @@ interface NoydbOptions {
|
|
|
10656
11535
|
* Multiple guards per collection are allowed; they are dispatched
|
|
10657
11536
|
* in registration order on `collection.put()`.
|
|
10658
11537
|
*/
|
|
10659
|
-
readonly guardStrategies?: ReadonlyArray<
|
|
11538
|
+
readonly guardStrategies?: ReadonlyArray<GuardStrategyHandleAny>;
|
|
10660
11539
|
/**
|
|
10661
11540
|
* Optional derivation strategies — source-to-output projections that
|
|
10662
11541
|
* fire on `collection.put()`. Each handle is the output of
|
|
@@ -10726,6 +11605,29 @@ interface NoydbOptions {
|
|
|
10726
11605
|
* subsequent sessions.
|
|
10727
11606
|
*/
|
|
10728
11607
|
readonly getKeyring?: (vault: string) => Promise<UnlockedKeyring>;
|
|
11608
|
+
/**
|
|
11609
|
+
* Passphrase mode (#14). Default `'standard'`.
|
|
11610
|
+
*
|
|
11611
|
+
* - `'standard'` — the legacy flow. `secret` supplies the
|
|
11612
|
+
* plaintext passphrase, the user knows it, and the policy gate
|
|
11613
|
+
* `rotate-passphrase` is enabled.
|
|
11614
|
+
* - `'managed'` — rubber-hose-resistant mode. Hub generates a
|
|
11615
|
+
* 256-bit random passphrase at first open and seals it under
|
|
11616
|
+
* the provided `sealingKey`. The user never sees or types the
|
|
11617
|
+
* passphrase, defeating the $5-wrench attack. Mutually
|
|
11618
|
+
* exclusive with `secret` and `getKeyring`.
|
|
11619
|
+
*
|
|
11620
|
+
* @see docs/subsystems/session-tiers.md → Managed-passphrase mode
|
|
11621
|
+
*/
|
|
11622
|
+
readonly passphraseMode?: 'standard' | 'managed';
|
|
11623
|
+
/**
|
|
11624
|
+
* Provider that seals/unseals the auto-generated managed-mode
|
|
11625
|
+
* passphrase. Required when `passphraseMode === 'managed'`; ignored
|
|
11626
|
+
* otherwise. Implementations live in per-platform packages
|
|
11627
|
+
* (`@noy-db/seal-macos-keychain`, `@noy-db/seal-wincred`,
|
|
11628
|
+
* `@noy-db/seal-libsecret`, `@noy-db/seal-aws-kms`, …).
|
|
11629
|
+
*/
|
|
11630
|
+
readonly sealingKey?: SealingKeyProvider;
|
|
10729
11631
|
/** Auth method. Default: 'passphrase'. */
|
|
10730
11632
|
readonly auth?: 'passphrase' | 'biometric';
|
|
10731
11633
|
/** Enable encryption. Default: true. */
|
|
@@ -10929,4 +11831,4 @@ interface DeleteManyResult {
|
|
|
10929
11831
|
}>;
|
|
10930
11832
|
}
|
|
10931
11833
|
|
|
10932
|
-
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, applyPatch 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 DerivedFromMeta as aA, type OutputSpec as aB, type MaterializedViewStrategy as aC, type MaterializedViewStrategyHandle as aD, type OverlayedViewStrategy as aE, Collection as aF, OverlayedViewRegistry as aG, type OverlayedViewStrategyHandle as aH, type SyncStrategy as aI, type Role as aJ, type UnlockedKeyring as aK, type HistoryStrategy as aL, type NoydbStore as aM, type HistoryOptions as aN, type EncryptedEnvelope as aO, type PruneOptions as aP, type AppendInput as aQ, type ChangeType as aR, CollectionInstant as aS, type DiffEntry as aT, type JsonPatch as aU, type JsonPatchOp as aV, type LedgerEntry as aW, LedgerStore as aX, type VaultEngine as aY, VaultInstant as aZ, type VerifyResult 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 GuardStrategy as ah, type GuardChange as ai, type GuardContext as aj, GuardRegistry as ak, type GuardStrategyHandle as al, ReadOnlyVaultFacade as am, type ShadowStrategy as an, CollectionFrame as ao, VaultFrame as ap, type TxStrategy as aq, type AmendmentTxOptions as ar, TxCollection as as, TxContext as at, TxVault as au, runTransaction as av, type DerivationStrategy as aw, type DerivationContext as ax, DerivationRegistry as ay, type DerivationStrategyHandle as az, type DictKeyDescriptor as b, type IssueMagicLinkGrantOptions as b$, canonicalJson as b0, computePatch as b1, diff as b2, formatDiff as b3, hashEntry as b4, paddedIndex as b5, parseIndex as b6, sha256Hex as b7, type MVQueryContext as b8, type RegisteredMV as b9, DEFAULT_PUBLIC_ENVELOPE_SCHEMA as bA, DELEGATIONS_COLLECTION as bB, type DeepPartial as bC, type DeepPartialOrNull as bD, type DelegationToken as bE, type DeleteManyResult as bF, type DirtyEntry as bG, ELEVATION_AUDIT_COLLECTION as bH, ElevatedHandle as bI, type EnrollAuthenticatorOptions as bJ, type EnrollAuthenticatorWrappingDEKsOptions as bK, type EnrollAuthenticatorWrappingKEKOptions as bL, type ExportCapability as bM, type ExportChunk as bN, type ExportFormat as bO, type ExportStreamOptions as bP, type FactorKind as bQ, type FactorProofBundle as bR, type FactorRequirement as bS, type GhostRecord as bT, type GrantOptions as bU, type HistoryConfig as bV, type HistoryEntry as bW, INDEXED_STORE_POLICY as bX, type ImportCapability as bY, type InferOutput as bZ, type IssueDelegationOptions as b_, MaterializedViewRegistry as ba, type MaterializedFromMeta as bb, type MaterializedViewOutput as bc, type UserEnvelope as bd, type PublicEnvelope as be, type GateName as bf, type GatePolicy as bg, type VaultPolicy as bh, type ActiveTier as bi, type FactorProof as bj, type DirectoryConfig as bk, type UserVisibility as bl, Vault as bm, type AccessibleVault as bn, BUNDLE_STORE_POLICY as bo, type BuiltInGateName as bp, type BundleRecipient as bq, type CacheOptions as br, type CacheStats as bs, type ChangeEvent as bt, type CollectionChangeEvent as bu, type CollectionConflictResolver as bv, type Conflict as bw, type ConflictPolicy as bx, type ConflictStrategy as by, type CrossTierAccessEvent as bz, DictionaryHandle as c, type SetPublicEnvelopeInput as c$, type KeyringAuthenticator as c0, type KeyringAuthenticatorWrappingDEKs as c1, type KeyringAuthenticatorWrappingKEK as c2, type KeyringFile as c3, type ListAccessibleVaultsOptions as c4, type ListPageResult as c5, type ListUsersOptions as c6, type LiveUserEnvelope as c7, type LocaleReadOptions as c8, Lru as c9, type PublicEnvelopeField as cA, type PublicEnvelopeSchema as cB, type PublicEnvelopeText as cC, type PullMode as cD, type PullOptions as cE, type PullPolicy as cF, type PullResult as cG, type PushMode as cH, type PushOptions as cI, type PushPolicy as cJ, type PushResult as cK, type PutManyItemOptions as cL, type PutManyOptions as cM, type PutManyResult as cN, type QueryAcrossOptions as cO, type QueryAcrossResult as cP, type QuickUnlockState as cQ, QuickUnlockStore as cR, type ReAuthOperation as cS, type RecoverPassphraseInput as cT, type RecoverPassphraseResult as cU, type RecoverUserOptions as cV, type RecoveryProof as cW, type ResolvedPublicEnvelopeSchema as cX, type RevokeOptions as cY, type RotatePassphraseInput as cZ, type SessionPolicy as c_, type LruOptions as ca, type LruStats as cb, MAGIC_LINK_CONTENT_INFO_PREFIX as cc, MAGIC_LINK_GRANTS_COLLECTION as cd, MAGIC_LINK_KEK_INFO_PREFIX as ce, type MagicLinkGrantPayload as cf, type MagicLinkGrantRecord as cg, NOYDB_BACKUP_VERSION as ch, NOYDB_FORMAT_VERSION as ci, NOYDB_KEYRING_VERSION as cj, NOYDB_SYNC_VERSION as ck, Noydb as cl, type NoydbBundleStore as cm, type NoydbEventMap as cn, type NoydbOptions as co, PUBLIC_ENVELOPE_FIELDS as cp, type PaperRecoveryDoc as cq, type PaperRecoveryEntry as cr, type PassphrasePolicy as cs, type PassphraseValidationResult as ct, type Permission as cu, type Permissions as cv, type PlaintextTranslatorContext as cw, type PlaintextTranslatorFn as cx, PresenceHandle as cy, type PresencePeer as cz, type DictionaryOptions as d, magicLinkGrantRecordId as d$, type SlotRewrapCeremony as d0, type SlotRewrapContext as d1, type StandardSchemaV1 as d2, type StandardSchemaV1Issue as d3, type StandardSchemaV1SyncResult as d4, type StoreAuth as d5, type StoreAuthKind as d6, type StoreCapabilities as d7, SyncEngine as d8, type SyncMetadata as d9, WeakPassphraseError as dA, type WeakPassphraseReason as dB, type WrappedDeksBlob as dC, assertStrongPassphrase as dD, buildRecipientKeyringFile as dE, burnPaperRecoveryEntry as dF, createNoydb as dG, createStore as dH, deriveMagicLinkContentKey as dI, enrollAuthenticator as dJ, estimateEntropy as dK, evaluateExportCapability as dL, evaluateImportCapability as dM, findAuthenticator as dN, hasExportCapability as dO, hasImportCapability as dP, hasRecoveryEnrolled as dQ, isMagicLinkGrantExpired as dR, isPublicEnvelope as dS, issueDelegation as dT, recoverPassphrase as dU, rotatePassphrase as dV, listMagicLinkGrants as dW, listUsers as dX, listUsersWithEnvelopes as dY, loadActiveDelegations as dZ, loadPaperRecoveryEntries as d_, type SyncPolicy as da, SyncScheduler as db, type SyncSchedulerStatus as dc, type SyncStatus as dd, type SyncTarget as de, type SyncTargetRole as df, SyncTransaction as dg, type SyncTransactionResult as dh, type TierMode as di, type TranslatorAuditEntry as dj, type TxOp as dk, USER_ENVELOPE_COLLECTION as dl, USER_ENVELOPE_MAX_BYTES as dm, type Unsubscribe as dn, type UpdateAuthenticatorOptions as dp, type UpdateUserOptions as dq, UserApi as dr, type UserEnvelopeCheckGate as ds, UserEnvelopeOversizedError as dt, type UserEnvelopePresented as du, type UserInfo as dv, type VaultBackup as dw, type VaultPolicyOnDisk as dx, type VaultSnapshot as dy, type WarningRules as dz, type I18nTextDescriptor as e, mintPaperRecoveryEntry as e0, mintWrappedDeksBlob as e1, readMagicLinkGrantRecord as e2, recoverUser as e3, removeAuthenticator as e4, resolveSchema as e5, revokeDelegation as e6, revokeMagicLinkGrant as e7, savePaperRecoveryEntries as e8, unwrapDeksFromBlob as e9, unwrapDeksFromPaperEntry as ea, unwrapMagicLinkGrant as eb, validatePassphrase as ec, validatePublicEnvelopeInput as ed, validateSchemaInput as ee, validateSchemaOutput as ef, writeMagicLinkGrant as eg, changeSecret as eh, createOwnerKeyring as ei, ensureCollectionDEK as ej, grant as ek, loadKeyring as el, persistKeyring as em, revoke as en, updateAuthenticator as eo, updateKeyringIdentity as ep, 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 };
|
|
11834
|
+
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, VaultInstant 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 DerivationStrategyHandle as aA, type DerivedFromMeta as aB, type OutputSpec as aC, type RecordOutputSpec as aD, type MaterializedViewStrategy as aE, type MaterializedViewStrategyHandle as aF, type OverlayedViewStrategy as aG, Collection as aH, OverlayedViewRegistry as aI, type OverlayedViewStrategyHandle as aJ, type SyncStrategy as aK, type Role as aL, type UnlockedKeyring as aM, type HistoryStrategy as aN, type NoydbStore as aO, type HistoryOptions as aP, type EncryptedEnvelope as aQ, type PruneOptions as aR, type AppendInput as aS, type ChangeType as aT, CollectionInstant as aU, type DiffEntry as aV, type JsonPatch as aW, type JsonPatchOp as aX, type LedgerEntry as aY, LedgerStore as aZ, type VaultEngine 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 GuardStrategy as ah, type GuardChange as ai, type GuardContext as aj, GuardRegistry as ak, type GuardStrategyHandle as al, ReadOnlyVaultFacade as am, type ShadowStrategy as an, CollectionFrame as ao, VaultFrame as ap, type TxStrategy as aq, type AmendmentTxOptions as ar, TxCollection as as, TxContext as at, TxVault as au, runTransaction as av, type DerivationStrategy as aw, type DerivationContext as ax, type ArrayOutputSpec as ay, DerivationRegistry as az, type DictKeyDescriptor as b, type FactorRequirement as b$, type VerifyResult as b0, applyPatch as b1, canonicalJson as b2, computePatch as b3, diff as b4, formatDiff as b5, hashEntry as b6, paddedIndex as b7, parseIndex as b8, sha256Hex as b9, type CollectionDescriptor as bA, type CollectionStats as bB, type Conflict as bC, type ConflictPolicy as bD, type ConflictStrategy as bE, type CrossTierAccessEvent as bF, DEFAULT_PUBLIC_ENVELOPE_SCHEMA as bG, DELEGATIONS_COLLECTION as bH, type DeepPartial as bI, type DeepPartialOrNull as bJ, type DelegationToken as bK, type DeleteManyResult as bL, type DerivationDescriptor as bM, type DirtyEntry as bN, type DumpSchemaOptions as bO, ELEVATION_AUDIT_COLLECTION as bP, ElevatedHandle as bQ, type EnrollAuthenticatorOptions as bR, type EnrollAuthenticatorWrappingDEKsOptions as bS, type EnrollAuthenticatorWrappingKEKOptions as bT, type EnrollRecoveryResult as bU, type ExportCapability as bV, type ExportChunk as bW, type ExportFormat as bX, type ExportStreamOptions as bY, type FactorKind as bZ, type FactorProofBundle as b_, type MVQueryContext as ba, type RegisteredMV as bb, MaterializedViewRegistry as bc, type MaterializedFromMeta as bd, type MaterializedViewOutput as be, type UnionSource as bf, type UserEnvelope as bg, type PublicEnvelope as bh, type GateName as bi, type GatePolicy as bj, type VaultPolicy as bk, type ActiveTier as bl, type FactorProof as bm, type PersistedSchemaEnvelope as bn, type DirectoryConfig as bo, type UserVisibility as bp, Vault as bq, type AccessibleVault as br, BUNDLE_STORE_POLICY as bs, type BuiltInGateName as bt, type BundleRecipient as bu, type CacheOptions as bv, type CacheStats as bw, type ChangeEvent as bx, type CollectionChangeEvent as by, type CollectionConflictResolver as bz, DictionaryHandle as c, type PutManyItemOptions as c$, type FieldDescriptor as c0, type FieldSource as c1, type GhostRecord as c2, type GrantOptions as c3, type HistoryConfig as c4, type HistoryEntry as c5, INDEXED_STORE_POLICY as c6, type ImportCapability as c7, type InferOutput as c8, type InternalCollectionStats as c9, type NoydbBundleStore as cA, type NoydbEventMap as cB, type NoydbOptions as cC, type OverlayViewDescriptor as cD, PUBLIC_ENVELOPE_FIELDS as cE, type PaperRecoveryDoc as cF, type PaperRecoveryEntry as cG, type PassphrasePolicy as cH, type PassphraseValidationResult as cI, type Permission as cJ, type Permissions as cK, type PersistedSchemaKind as cL, type PlaintextTranslatorContext as cM, type PlaintextTranslatorFn as cN, PresenceHandle as cO, type PresencePeer as cP, type PublicEnvelopeField as cQ, type PublicEnvelopeSchema as cR, type PublicEnvelopeText as cS, type PullMode as cT, type PullOptions as cU, type PullPolicy as cV, type PullResult as cW, type PushMode as cX, type PushOptions as cY, type PushPolicy as cZ, type PushResult as c_, type IssueDelegationOptions as ca, type IssueMagicLinkGrantOptions as cb, type KeyringAuthenticator as cc, type KeyringAuthenticatorWrappingDEKs as cd, type KeyringAuthenticatorWrappingKEK as ce, type KeyringFile as cf, type ListAccessibleVaultsOptions as cg, type ListPageResult as ch, type ListUsersOptions as ci, type LiveUserEnvelope as cj, type LocaleReadOptions as ck, Lru as cl, type LruOptions as cm, type LruStats as cn, MAGIC_LINK_CONTENT_INFO_PREFIX as co, MAGIC_LINK_GRANTS_COLLECTION as cp, MAGIC_LINK_KEK_INFO_PREFIX as cq, type MagicLinkGrantPayload as cr, type MagicLinkGrantRecord as cs, type MaterializedViewDescriptor as ct, MemorySealingKeyProvider as cu, NOYDB_BACKUP_VERSION as cv, NOYDB_FORMAT_VERSION as cw, NOYDB_KEYRING_VERSION as cx, NOYDB_SYNC_VERSION as cy, Noydb as cz, type DictionaryOptions as d, type WrappedDeksBlob as d$, type PutManyOptions as d0, type PutManyResult as d1, type QueryAcrossOptions as d2, type QueryAcrossResult as d3, type QuickUnlockState as d4, QuickUnlockStore as d5, type ReAuthOperation as d6, type RecoverPassphraseInput as d7, type RecoverPassphraseResult as d8, type RecoverUserOptions as d9, SyncScheduler as dA, type SyncSchedulerStatus as dB, type SyncStatus as dC, type SyncTarget as dD, type SyncTargetRole as dE, SyncTransaction as dF, type SyncTransactionResult as dG, type TierMode as dH, type TranslatorAuditEntry as dI, type TxOp as dJ, USER_ENVELOPE_COLLECTION as dK, USER_ENVELOPE_MAX_BYTES as dL, type Unsubscribe as dM, type UpdateAuthenticatorOptions as dN, type UpdateUserOptions as dO, UserApi as dP, type UserEnvelopeCheckGate as dQ, UserEnvelopeOversizedError as dR, type UserEnvelopePresented as dS, type UserInfo as dT, type VaultBackup as dU, type VaultPolicyOnDisk as dV, type VaultSchemaSnapshot as dW, type VaultSnapshot as dX, type WarningRules as dY, WeakPassphraseError as dZ, type WeakPassphraseReason as d_, type RecoveryProof as da, type ResolvedPublicEnvelopeSchema as db, type RevokeOptions as dc, type RotatePassphraseInput as dd, type RotateRecoveryOptions as de, type RotateRecoveryResult as df, SEALED_PASSPHRASE_RECORD_ID as dg, type SealedEnvelope as dh, type SealedPassphrase as di, type SealingKeyProvider as dj, type SessionPolicy as dk, type SetPublicEnvelopeInput as dl, type ShamirRecoveryDoc as dm, type ShamirRecoveryEntry as dn, type SlotRewrapCeremony as dp, type SlotRewrapContext as dq, type StandardSchemaV1 as dr, type StandardSchemaV1Issue as ds, type StandardSchemaV1SyncResult as dt, type StoreAuth as du, type StoreAuthKind as dv, type StoreCapabilities as dw, SyncEngine as dx, type SyncMetadata as dy, type SyncPolicy as dz, type I18nTextDescriptor as e, assertStrongPassphrase as e0, buildRecipientKeyringFile as e1, burnPaperRecoveryEntry as e2, createNoydb as e3, createStore as e4, deriveMagicLinkContentKey as e5, enrollAuthenticator as e6, estimateEntropy as e7, evaluateExportCapability as e8, evaluateImportCapability as e9, revokeMagicLinkGrant as eA, savePaperRecoveryEntries as eB, saveSealedPassphrase as eC, saveShamirRecoveryEntries as eD, unwrapDeksFromBlob as eE, unwrapDeksFromPaperEntry as eF, unwrapDeksFromShamirEntry as eG, unwrapMagicLinkGrant as eH, validatePassphrase as eI, validatePublicEnvelopeInput as eJ, validateSchemaInput as eK, validateSchemaOutput as eL, writeMagicLinkGrant as eM, changeSecret as eN, createOwnerKeyring as eO, ensureCollectionDEK as eP, grant as eQ, loadKeyring as eR, persistKeyring as eS, revoke as eT, updateAuthenticator as eU, updateKeyringIdentity as eV, findAuthenticator as ea, hasExportCapability as eb, hasImportCapability as ec, hasRecoveryEnrolled as ed, isMagicLinkGrantExpired as ee, isPublicEnvelope as ef, issueDelegation as eg, recoverPassphrase as eh, rotatePassphrase as ei, listMagicLinkGrants as ej, listUsers as ek, listUsersWithEnvelopes as el, loadActiveDelegations as em, loadPaperRecoveryEntries as en, loadSealedPassphrase as eo, loadShamirRecoveryEntries as ep, magicLinkGrantRecordId as eq, mintPaperRecoveryEntry as er, mintShamirRecoveryEntry as es, mintWrappedDeksBlob as et, parseSealedEnvelope as eu, readMagicLinkGrantRecord as ev, recoverUser as ew, removeAuthenticator as ex, resolveSchema as ey, revokeDelegation as ez, 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 };
|