[{"data":1,"prerenderedAt":3859},["ShallowReactive",2],{"navigation":3,"\u002Fcore\u002Fnoydb\u002Fenclave":927},[4,40,114,446,474,498,596,903],{"title":5,"path":6,"stem":7,"children":8},"Architecture","\u002Farchitecture","architecture",[9,14,28,32,36],{"title":10,"path":6,"stem":11,"access":12,"icon":13},"Overview","architecture\u002Findex","public","i-lucide-network",{"title":10,"path":15,"stem":16,"children":17,"access":12,"icon":19},"\u002Farchitecture\u002Fkernel","architecture\u002F1.kernel\u002Findex",[18,20,24],{"title":10,"path":15,"stem":16,"access":12,"icon":19},"i-lucide-box",{"title":21,"path":22,"stem":23,"access":12},"Enclave","\u002Farchitecture\u002Fkernel\u002Fenclave","architecture\u002F1.kernel\u002Fenclave",{"title":25,"path":26,"stem":27,"access":12},"Forking the enclave","\u002Farchitecture\u002Fkernel\u002Fforking-the-enclave","architecture\u002F1.kernel\u002Fforking-the-enclave",{"title":29,"path":30,"stem":31,"access":12},"Ports","\u002Farchitecture\u002Fports","architecture\u002F2.ports",{"title":33,"path":34,"stem":35,"access":12},"Service layers","\u002Farchitecture\u002Fservice-layers","architecture\u002F3.service-layers",{"title":37,"path":38,"stem":39,"access":12},"Families","\u002Farchitecture\u002Ffamilies","architecture\u002F4.families",{"title":41,"path":42,"stem":43,"children":44},"Core","\u002Fcore","core",[45,47,50,53,56,88,97],{"title":10,"path":42,"stem":46,"access":12,"icon":19},"core\u002Findex",{"title":10,"path":48,"stem":49,"access":12},"\u002Fcore\u002F01-overview","core\u002F01-overview",{"title":10,"path":51,"stem":52,"access":12},"\u002Fcore\u002F05-stores","core\u002F05-stores",{"title":10,"path":54,"stem":55,"access":12},"\u002Fcore\u002F06-permissions-and-keyring","core\u002F06-permissions-and-keyring",{"title":10,"path":57,"stem":58,"children":59,"access":12},"\u002Fcore\u002Fnoydb","core\u002F2.noydb\u002Findex",[60,61,65,68,72,76,80,84],{"title":10,"path":57,"stem":58,"access":12},{"title":62,"path":63,"stem":64,"access":12},"Noydb","\u002Fcore\u002Fnoydb\u002Fmethods","core\u002F2.noydb\u002F1.methods",{"title":21,"path":66,"stem":67,"access":12},"\u002Fcore\u002Fnoydb\u002Fenclave","core\u002F2.noydb\u002F2.enclave",{"title":69,"path":70,"stem":71,"access":12},"Secret & keyring","\u002Fcore\u002Fnoydb\u002Fkeyring","core\u002F2.noydb\u002F3.keyring",{"title":73,"path":74,"stem":75,"access":12},"Authentication","\u002Fcore\u002Fnoydb\u002Fauthentication","core\u002F2.noydb\u002F4.authentication",{"title":77,"path":78,"stem":79,"access":12},"Auth recovery","\u002Fcore\u002Fnoydb\u002Frecovery","core\u002F2.noydb\u002F5.recovery",{"title":81,"path":82,"stem":83,"access":12},"Configuration","\u002Fcore\u002Fnoydb\u002Fconfiguration","core\u002F2.noydb\u002F6.configuration",{"title":85,"path":86,"stem":87,"access":12},"Strategies","\u002Fcore\u002Fnoydb\u002Fstrategies","core\u002F2.noydb\u002F7.strategies",{"title":10,"path":89,"stem":90,"children":91,"access":12},"\u002Fcore\u002Fvault","core\u002F3.vault\u002Findex",[92,93],{"title":10,"path":89,"stem":90,"access":12},{"title":94,"path":95,"stem":96,"access":12},"Vault","\u002Fcore\u002Fvault\u002Fmethods","core\u002F3.vault\u002F1.methods",{"title":10,"path":98,"stem":99,"children":100,"access":12},"\u002Fcore\u002Fcollection","core\u002F4.collection\u002Findex",[101,102,106,110],{"title":10,"path":98,"stem":99,"access":12},{"title":103,"path":104,"stem":105,"access":12},"Collection","\u002Fcore\u002Fcollection\u002Fmethods","core\u002F4.collection\u002F1.methods",{"title":107,"path":108,"stem":109,"access":12},"Querying","\u002Fcore\u002Fcollection\u002Fquerying","core\u002F4.collection\u002F2.querying",{"title":111,"path":112,"stem":113,"access":12},"Schema","\u002Fcore\u002Fcollection\u002Fschema","core\u002F4.collection\u002F3.schema",{"title":37,"path":115,"stem":116,"children":117},"\u002Ffamilies","families",[118,121,168,194,208,212,216,294,340],{"title":10,"path":115,"stem":119,"access":12,"icon":120},"families\u002Findex","i-lucide-plug",{"title":122,"path":123,"stem":124,"children":125,"access":12,"icon":127},"as-Exports","\u002Ffamilies\u002Fas","families\u002Fas\u002Findex",[126,128,132,136,140,144,148,152,156,160,164],{"title":122,"path":123,"stem":124,"access":12,"icon":127},"i-lucide-book-open",{"title":129,"path":130,"stem":131,"access":12},"aws-s3","\u002Ffamilies\u002Fas\u002Faws-s3","families\u002Fas\u002Faws-s3",{"title":133,"path":134,"stem":135,"access":12},"blob","\u002Ffamilies\u002Fas\u002Fblob","families\u002Fas\u002Fblob",{"title":137,"path":138,"stem":139,"access":12},"csv","\u002Ffamilies\u002Fas\u002Fcsv","families\u002Fas\u002Fcsv",{"title":141,"path":142,"stem":143,"access":12},"json","\u002Ffamilies\u002Fas\u002Fjson","families\u002Fas\u002Fjson",{"title":145,"path":146,"stem":147,"access":12},"ndjson","\u002Ffamilies\u002Fas\u002Fndjson","families\u002Fas\u002Fndjson",{"title":149,"path":150,"stem":151,"access":12},"noydb","\u002Ffamilies\u002Fas\u002Fnoydb","families\u002Fas\u002Fnoydb",{"title":153,"path":154,"stem":155,"access":12},"sql","\u002Ffamilies\u002Fas\u002Fsql","families\u002Fas\u002Fsql",{"title":157,"path":158,"stem":159,"access":12},"xlsx","\u002Ffamilies\u002Fas\u002Fxlsx","families\u002Fas\u002Fxlsx",{"title":161,"path":162,"stem":163,"access":12},"xml","\u002Ffamilies\u002Fas\u002Fxml","families\u002Fas\u002Fxml",{"title":165,"path":166,"stem":167,"access":12},"zip","\u002Ffamilies\u002Fas\u002Fzip","families\u002Fas\u002Fzip",{"title":169,"path":170,"stem":171,"children":172,"access":12,"icon":127},"at-Seals","\u002Ffamilies\u002Fat","families\u002Fat\u002Findex",[173,174,178,182,186,190],{"title":169,"path":170,"stem":171,"access":12,"icon":127},{"title":175,"path":176,"stem":177,"access":12},"aws-kms","\u002Ffamilies\u002Fat\u002Faws-kms","families\u002Fat\u002Faws-kms",{"title":179,"path":180,"stem":181,"access":12},"azure-keyvault","\u002Ffamilies\u002Fat\u002Fazure-keyvault","families\u002Fat\u002Fazure-keyvault",{"title":183,"path":184,"stem":185,"access":12},"env","\u002Ffamilies\u002Fat\u002Fenv","families\u002Fat\u002Fenv",{"title":187,"path":188,"stem":189,"access":12},"gcp-kms","\u002Ffamilies\u002Fat\u002Fgcp-kms","families\u002Fat\u002Fgcp-kms",{"title":191,"path":192,"stem":193,"access":12},"macos-keychain","\u002Ffamilies\u002Fat\u002Fmacos-keychain","families\u002Fat\u002Fmacos-keychain",{"title":195,"path":196,"stem":197,"children":198,"access":12,"icon":127},"by-Sessions","\u002Ffamilies\u002Fby","families\u002Fby\u002Findex",[199,200,204],{"title":195,"path":196,"stem":197,"access":12,"icon":127},{"title":201,"path":202,"stem":203,"access":12},"peer","\u002Ffamilies\u002Fby\u002Fpeer","families\u002Fby\u002Fpeer",{"title":205,"path":206,"stem":207,"access":12},"tabs","\u002Ffamilies\u002Fby\u002Ftabs","families\u002Fby\u002Ftabs",{"title":209,"path":210,"stem":211,"access":12},"Classifying a package","\u002Ffamilies\u002Fclassification","families\u002Fclassification",{"title":213,"path":214,"stem":215,"access":12},"Command-line tools","\u002Ffamilies\u002Fcli","families\u002Fcli",{"title":217,"path":218,"stem":219,"children":220,"access":12,"icon":127},"in-Frameworks","\u002Ffamilies\u002Fin","families\u002Fin\u002Findex",[221,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290],{"title":217,"path":218,"stem":219,"access":12,"icon":127},{"title":223,"path":224,"stem":225,"access":12},"ai","\u002Ffamilies\u002Fin\u002Fai","families\u002Fin\u002Fai",{"title":227,"path":228,"stem":229,"access":12},"devtools","\u002Ffamilies\u002Fin\u002Fdevtools","families\u002Fin\u002Fdevtools",{"title":231,"path":232,"stem":233,"access":12},"devtools-tui","\u002Ffamilies\u002Fin\u002Fdevtools-tui","families\u002Fin\u002Fdevtools-tui",{"title":235,"path":236,"stem":237,"access":12},"liff","\u002Ffamilies\u002Fin\u002Fliff","families\u002Fin\u002Fliff",{"title":239,"path":240,"stem":241,"access":12},"nextjs","\u002Ffamilies\u002Fin\u002Fnextjs","families\u002Fin\u002Fnextjs",{"title":243,"path":244,"stem":245,"access":12},"nuxt","\u002Ffamilies\u002Fin\u002Fnuxt","families\u002Fin\u002Fnuxt",{"title":247,"path":248,"stem":249,"access":12},"pinia","\u002Ffamilies\u002Fin\u002Fpinia","families\u002Fin\u002Fpinia",{"title":251,"path":252,"stem":253,"access":12},"pwa","\u002Ffamilies\u002Fin\u002Fpwa","families\u002Fin\u002Fpwa",{"title":255,"path":256,"stem":257,"access":12},"react","\u002Ffamilies\u002Fin\u002Freact","families\u002Fin\u002Freact",{"title":259,"path":260,"stem":261,"access":12},"relay","\u002Ffamilies\u002Fin\u002Frelay","families\u002Fin\u002Frelay",{"title":263,"path":264,"stem":265,"access":12},"rest","\u002Ffamilies\u002Fin\u002Frest","families\u002Fin\u002Frest",{"title":267,"path":268,"stem":269,"access":12},"solid","\u002Ffamilies\u002Fin\u002Fsolid","families\u002Fin\u002Fsolid",{"title":271,"path":272,"stem":273,"access":12},"svelte","\u002Ffamilies\u002Fin\u002Fsvelte","families\u002Fin\u002Fsvelte",{"title":275,"path":276,"stem":277,"access":12},"tanstack-query","\u002Ffamilies\u002Fin\u002Ftanstack-query","families\u002Fin\u002Ftanstack-query",{"title":279,"path":280,"stem":281,"access":12},"tanstack-table","\u002Ffamilies\u002Fin\u002Ftanstack-table","families\u002Fin\u002Ftanstack-table",{"title":283,"path":284,"stem":285,"access":12},"vue","\u002Ffamilies\u002Fin\u002Fvue","families\u002Fin\u002Fvue",{"title":287,"path":288,"stem":289,"access":12},"yjs","\u002Ffamilies\u002Fin\u002Fyjs","families\u002Fin\u002Fyjs",{"title":291,"path":292,"stem":293,"access":12},"zustand","\u002Ffamilies\u002Fin\u002Fzustand","families\u002Fin\u002Fzustand",{"title":295,"path":296,"stem":297,"children":298,"access":12,"icon":127},"on-Auth","\u002Ffamilies\u002Fon","families\u002Fon\u002Findex",[299,300,304,308,312,316,320,324,328,332,336],{"title":295,"path":296,"stem":297,"access":12,"icon":127},{"title":301,"path":302,"stem":303,"access":12},"email-otp","\u002Ffamilies\u002Fon\u002Femail-otp","families\u002Fon\u002Femail-otp",{"title":305,"path":306,"stem":307,"access":12},"magic-link","\u002Ffamilies\u002Fon\u002Fmagic-link","families\u002Fon\u002Fmagic-link",{"title":309,"path":310,"stem":311,"access":12},"oidc","\u002Ffamilies\u002Fon\u002Foidc","families\u002Fon\u002Foidc",{"title":313,"path":314,"stem":315,"access":12},"password","\u002Ffamilies\u002Fon\u002Fpassword","families\u002Fon\u002Fpassword",{"title":317,"path":318,"stem":319,"access":12},"pin","\u002Ffamilies\u002Fon\u002Fpin","families\u002Fon\u002Fpin",{"title":321,"path":322,"stem":323,"access":12},"recovery","\u002Ffamilies\u002Fon\u002Frecovery","families\u002Fon\u002Frecovery",{"title":325,"path":326,"stem":327,"access":12},"shamir","\u002Ffamilies\u002Fon\u002Fshamir","families\u002Fon\u002Fshamir",{"title":329,"path":330,"stem":331,"access":12},"threat","\u002Ffamilies\u002Fon\u002Fthreat","families\u002Fon\u002Fthreat",{"title":333,"path":334,"stem":335,"access":12},"totp","\u002Ffamilies\u002Fon\u002Ftotp","families\u002Fon\u002Ftotp",{"title":337,"path":338,"stem":339,"access":12},"webauthn","\u002Ffamilies\u002Fon\u002Fwebauthn","families\u002Fon\u002Fwebauthn",{"title":341,"path":342,"stem":343,"children":344,"access":12,"icon":127},"to-Stores","\u002Ffamilies\u002Fto","families\u002Fto\u002Findex",[345,346,350,353,357,361,365,370,374,378,382,386,390,394,398,402,406,410,414,417,421,425,429,434,438,442],{"title":341,"path":342,"stem":343,"access":12,"icon":127},{"title":347,"path":348,"stem":349,"access":12},"aws-dynamo","\u002Ffamilies\u002Fto\u002Faws-dynamo","families\u002Fto\u002Faws-dynamo",{"title":129,"path":351,"stem":352,"access":12},"\u002Ffamilies\u002Fto\u002Faws-s3","families\u002Fto\u002Faws-s3",{"title":354,"path":355,"stem":356,"access":12},"browser-fs","\u002Ffamilies\u002Fto\u002Fbrowser-fs","families\u002Fto\u002Fbrowser-fs",{"title":358,"path":359,"stem":360,"access":12},"browser-idb","\u002Ffamilies\u002Fto\u002Fbrowser-idb","families\u002Fto\u002Fbrowser-idb",{"title":362,"path":363,"stem":364,"access":12},"browser-local","\u002Ffamilies\u002Fto\u002Fbrowser-local","families\u002Fto\u002Fbrowser-local",{"title":366,"path":367,"stem":368,"access":12,"icon":369},"Choosing a store","\u002Ffamilies\u002Fto\u002Fchoosing-a-store","families\u002Fto\u002Fchoosing-a-store","i-lucide-split",{"title":371,"path":372,"stem":373,"access":12},"cloudflare-d1","\u002Ffamilies\u002Fto\u002Fcloudflare-d1","families\u002Fto\u002Fcloudflare-d1",{"title":375,"path":376,"stem":377,"access":12},"cloudflare-r2","\u002Ffamilies\u002Fto\u002Fcloudflare-r2","families\u002Fto\u002Fcloudflare-r2",{"title":379,"path":380,"stem":381,"access":12},"drive","\u002Ffamilies\u002Fto\u002Fdrive","families\u002Fto\u002Fdrive",{"title":383,"path":384,"stem":385,"access":12},"file","\u002Ffamilies\u002Fto\u002Ffile","families\u002Fto\u002Ffile",{"title":387,"path":388,"stem":389,"access":12},"icloud","\u002Ffamilies\u002Fto\u002Ficloud","families\u002Fto\u002Ficloud",{"title":391,"path":392,"stem":393,"access":12},"memory","\u002Ffamilies\u002Fto\u002Fmemory","families\u002Fto\u002Fmemory",{"title":395,"path":396,"stem":397,"access":12},"meter","\u002Ffamilies\u002Fto\u002Fmeter","families\u002Fto\u002Fmeter",{"title":399,"path":400,"stem":401,"access":12},"mysql","\u002Ffamilies\u002Fto\u002Fmysql","families\u002Fto\u002Fmysql",{"title":403,"path":404,"stem":405,"access":12},"nfs","\u002Ffamilies\u002Fto\u002Fnfs","families\u002Fto\u002Fnfs",{"title":407,"path":408,"stem":409,"access":12},"postgres","\u002Ffamilies\u002Fto\u002Fpostgres","families\u002Fto\u002Fpostgres",{"title":411,"path":412,"stem":413,"access":12},"probe","\u002Ffamilies\u002Fto\u002Fprobe","families\u002Fto\u002Fprobe",{"title":263,"path":415,"stem":416,"access":12},"\u002Ffamilies\u002Fto\u002Frest","families\u002Fto\u002Frest",{"title":418,"path":419,"stem":420,"access":12},"smb","\u002Ffamilies\u002Fto\u002Fsmb","families\u002Fto\u002Fsmb",{"title":422,"path":423,"stem":424,"access":12},"sqlite","\u002Ffamilies\u002Fto\u002Fsqlite","families\u002Fto\u002Fsqlite",{"title":426,"path":427,"stem":428,"access":12},"ssh","\u002Ffamilies\u002Fto\u002Fssh","families\u002Fto\u002Fssh",{"title":430,"path":431,"stem":432,"access":12,"icon":433},"Store-locator descriptors","\u002Ffamilies\u002Fto\u002Fstore-locator","families\u002Fto\u002Fstore-locator","i-lucide-map-pin",{"title":435,"path":436,"stem":437,"access":12},"supabase","\u002Ffamilies\u002Fto\u002Fsupabase","families\u002Fto\u002Fsupabase",{"title":439,"path":440,"stem":441,"access":12},"turso","\u002Ffamilies\u002Fto\u002Fturso","families\u002Fto\u002Fturso",{"title":443,"path":444,"stem":445,"access":12},"webdav","\u002Ffamilies\u002Fto\u002Fwebdav","families\u002Fto\u002Fwebdav",{"title":447,"path":448,"stem":449,"children":450},"Faq","\u002Ffaq","faq",[451,454,458,462,466,470],{"title":10,"path":448,"stem":452,"access":12,"icon":453},"faq\u002Findex","i-lucide-circle-help",{"title":455,"path":456,"stem":457,"access":12},"Where can noy-db run?","\u002Ffaq\u002Fwhere-can-noy-db-run","faq\u002F1.where-can-noy-db-run",{"title":459,"path":460,"stem":461,"access":12},"Native mobile & PWA","\u002Ffaq\u002Fmobile-and-pwa","faq\u002F2.mobile-and-pwa",{"title":463,"path":464,"stem":465,"access":12},"Threat model","\u002Ffaq\u002Fthreat-model","faq\u002F3.threat-model",{"title":467,"path":468,"stem":469,"access":12},"Community & ecosystem","\u002Ffaq\u002Fcommunity-and-ecosystem","faq\u002F4.community-and-ecosystem",{"title":471,"path":472,"stem":473,"access":12},"Licensing","\u002Ffaq\u002Flicensing","faq\u002F5.licensing",{"title":475,"path":476,"stem":477,"children":478},"Glossary","\u002Fglossary","glossary",[479,482,486,490,494],{"title":10,"path":476,"stem":480,"access":12,"icon":481},"glossary\u002Findex","i-lucide-book-a",{"title":483,"path":484,"stem":485,"access":12},"Core vocabulary","\u002Fglossary\u002Fcore-vocabulary","glossary\u002Fcore-vocabulary",{"title":487,"path":488,"stem":489,"access":12},"Deletion vocabulary","\u002Fglossary\u002Fdeletion","glossary\u002Fdeletion",{"title":491,"path":492,"stem":493,"access":12},"Satellite collection vocabulary","\u002Fglossary\u002Fsatellite-collections","glossary\u002Fsatellite-collections",{"title":495,"path":496,"stem":497,"access":12},"Schema migration vocabulary","\u002Fglossary\u002Fschema-migration","glossary\u002Fschema-migration",{"title":499,"path":500,"stem":501,"children":502},"Recipes","\u002Frecipes","recipes",[503,506,510,514,518,522,526,530,534,538,542,546,550,554,558,562,567,571,575,580,584,588,592],{"title":10,"path":500,"stem":504,"access":12,"icon":505},"recipes\u002Findex","i-lucide-play",{"title":507,"path":508,"stem":509,"access":12},"Accounting app","\u002Frecipes\u002Faccounting-app","recipes\u002Faccounting-app",{"title":511,"path":512,"stem":513,"access":12},"Analytics app","\u002Frecipes\u002Fanalytics-app","recipes\u002Fanalytics-app",{"title":515,"path":516,"stem":517,"access":12},"Attestation verifier","\u002Frecipes\u002Fattestation-verifier","recipes\u002Fattestation-verifier",{"title":519,"path":520,"stem":521,"access":12},"AWS-KMS attestation","\u002Frecipes\u002Faws-kms-pdf-attestation","recipes\u002Faws-kms-pdf-attestation",{"title":523,"path":524,"stem":525,"access":12},"Browser durability","\u002Frecipes\u002Fbrowser-durability","recipes\u002Fbrowser-durability",{"title":527,"path":528,"stem":529,"access":12},"Production cloud store","\u002Frecipes\u002Fcloud-store","recipes\u002Fcloud-store",{"title":531,"path":532,"stem":533,"access":12},"Compose your own setup","\u002Frecipes\u002Fcompose-your-own","recipes\u002Fcompose-your-own",{"title":535,"path":536,"stem":537,"access":12},"Confidential HR records","\u002Frecipes\u002Fconfidential-hr","recipes\u002Fconfidential-hr",{"title":539,"path":540,"stem":541,"access":12},"Composing an echo secret","\u002Frecipes\u002Fecho-secret-enrollment","recipes\u002Fecho-secret-enrollment",{"title":543,"path":544,"stem":545,"access":12},"Email archive","\u002Frecipes\u002Femail-archive","recipes\u002Femail-archive",{"title":547,"path":548,"stem":549,"access":12},"Email archive — threads & revisions","\u002Frecipes\u002Femail-archive-threads-revisions","recipes\u002Femail-archive-threads-revisions",{"title":551,"path":552,"stem":553,"access":12},"Export & portability","\u002Frecipes\u002Fexport-portability","recipes\u002Fexport-portability",{"title":555,"path":556,"stem":557,"access":12},"Passwordless OIDC (AWS Cognito)","\u002Frecipes\u002Fpasswordless-oidc","recipes\u002Fpasswordless-oidc",{"title":559,"path":560,"stem":561,"access":12},"Personal notebook","\u002Frecipes\u002Fpersonal-notebook","recipes\u002Fpersonal-notebook",{"title":563,"path":564,"stem":565,"access":12,"icon":566},"Playgrounds","\u002Frecipes\u002Fplaygrounds","recipes\u002Fplaygrounds","i-lucide-gamepad-2",{"title":568,"path":569,"stem":570,"access":12},"React invoice app","\u002Frecipes\u002Freact-invoices","recipes\u002Freact-invoices",{"title":572,"path":573,"stem":574,"access":12},"Collaborative app","\u002Frecipes\u002Frealtime-crdt-app","recipes\u002Frealtime-crdt-app",{"title":576,"path":577,"stem":578,"access":12,"icon":579},"Run the showcases","\u002Frecipes\u002Frun-the-showcases","recipes\u002Frun-the-showcases","i-lucide-flask-conical",{"title":581,"path":582,"stem":583,"access":12},"Search & RAG","\u002Frecipes\u002Fsearch-rag","recipes\u002Fsearch-rag",{"title":585,"path":586,"stem":587,"access":12},"Team vault topology","\u002Frecipes\u002Fteam-vault-topology","recipes\u002Fteam-vault-topology",{"title":589,"path":590,"stem":591,"access":12},"Unlock ceremonies","\u002Frecipes\u002Funlock-ceremonies","recipes\u002Funlock-ceremonies",{"title":593,"path":594,"stem":595,"access":12},"User preferences","\u002Frecipes\u002Fuser-preferences","recipes\u002Fuser-preferences",{"title":597,"path":598,"stem":599,"children":600},"Services","\u002Fservices","services",[601,604,608,612,616,620,624,628,632,636,640,644,648,652,656,660,664,668,672,676,680,684,688,692,696,700,704,710,714,718,722,726,730,734,738,742,746,750,755,759,763,767,771,775,779,783,787,791,795,799,803,807,811,815,819,823,827,831,835,839,843,847,851,855,859,863,867,871,875,879,883,887,891,895,899],{"title":10,"path":598,"stem":602,"access":12,"icon":603},"services\u002Findex","i-lucide-layers",{"title":605,"path":606,"stem":607,"access":12},"archive","\u002Fservices\u002Farchive","services\u002Farchive",{"title":609,"path":610,"stem":611,"access":12},"attestation","\u002Fservices\u002Fattestation","services\u002Fattestation",{"title":613,"path":614,"stem":615,"access":12},"auth-introspection","\u002Fservices\u002Fauth-introspection","services\u002Fauth-introspection",{"title":617,"path":618,"stem":619,"access":12},"auth-landscape","\u002Fservices\u002Fauth-landscape","services\u002Fauth-landscape",{"title":621,"path":622,"stem":623,"access":12},"blobs","\u002Fservices\u002Fblobs","services\u002Fblobs",{"title":625,"path":626,"stem":627,"access":12},"broker","\u002Fservices\u002Fbroker","services\u002Fbroker",{"title":629,"path":630,"stem":631,"access":12},"bundle","\u002Fservices\u002Fbundle","services\u002Fbundle",{"title":633,"path":634,"stem":635,"access":12},"classified","\u002Fservices\u002Fclassified","services\u002Fclassified",{"title":637,"path":638,"stem":639,"access":12},"computed","\u002Fservices\u002Fcomputed","services\u002Fcomputed",{"title":641,"path":642,"stem":643,"access":12},"consent","\u002Fservices\u002Fconsent","services\u002Fconsent",{"title":645,"path":646,"stem":647,"access":12},"cover","\u002Fservices\u002Fcover","services\u002Fcover",{"title":649,"path":650,"stem":651,"access":12},"coverage","\u002Fservices\u002Fcoverage","services\u002Fcoverage",{"title":653,"path":654,"stem":655,"access":12},"crdt","\u002Fservices\u002Fcrdt","services\u002Fcrdt",{"title":657,"path":658,"stem":659,"access":12},"cross-join","\u002Fservices\u002Fcross-join","services\u002Fcross-join",{"title":661,"path":662,"stem":663,"access":12},"custody","\u002Fservices\u002Fcustody","services\u002Fcustody",{"title":665,"path":666,"stem":667,"access":12},"derivations","\u002Fservices\u002Fderivations","services\u002Fderivations",{"title":669,"path":670,"stem":671,"access":12},"directory","\u002Fservices\u002Fdirectory","services\u002Fdirectory",{"title":673,"path":674,"stem":675,"access":12},"search — AI","\u002Fservices\u002Fembeddings","services\u002Fembeddings",{"title":677,"path":678,"stem":679,"access":12},"Field metadata","\u002Fservices\u002Ffield-metadata","services\u002Ffield-metadata",{"title":681,"path":682,"stem":683,"access":12},"Foreign refs","\u002Fservices\u002Fforeign-refs","services\u002Fforeign-refs",{"title":685,"path":686,"stem":687,"access":12},"forget","\u002Fservices\u002Fforget","services\u002Fforget",{"title":689,"path":690,"stem":691,"access":12},"governance","\u002Fservices\u002Fgovernance","services\u002Fgovernance",{"title":693,"path":694,"stem":695,"access":12},"guards","\u002Fservices\u002Fguards","services\u002Fguards",{"title":697,"path":698,"stem":699,"access":12},"history","\u002Fservices\u002Fhistory","services\u002Fhistory",{"title":701,"path":702,"stem":703,"access":12},"i18n","\u002Fservices\u002Fi18n","services\u002Fi18n",{"title":705,"path":706,"stem":707,"children":708,"access":12},"indexing","\u002Fservices\u002Findexing","services\u002Findexing",[709],{"title":705,"path":706,"stem":707,"access":12},{"title":711,"path":712,"stem":713,"access":12},"introspection","\u002Fservices\u002Fintrospection","services\u002Fintrospection",{"title":715,"path":716,"stem":717,"access":12},"joins","\u002Fservices\u002Fjoins","services\u002Fjoins",{"title":719,"path":720,"stem":721,"access":12},"lazy","\u002Fservices\u002Flazy","services\u002Flazy",{"title":723,"path":724,"stem":725,"access":12},"links","\u002Fservices\u002Flinks","services\u002Flinks",{"title":727,"path":728,"stem":729,"access":12},"live","\u002Fservices\u002Flive","services\u002Flive",{"title":731,"path":732,"stem":733,"access":12},"lookup","\u002Fservices\u002Flookup","services\u002Flookup",{"title":735,"path":736,"stem":737,"access":12},"manifest","\u002Fservices\u002Fmanifest","services\u002Fmanifest",{"title":739,"path":740,"stem":741,"access":12},"materialized-views","\u002Fservices\u002Fmaterialized-views","services\u002Fmaterialized-views",{"title":743,"path":744,"stem":745,"access":12},"Metadata ladder","\u002Fservices\u002Fmetadata-ladder","services\u002Fmetadata-ladder",{"title":747,"path":748,"stem":749,"access":12},"Metadata riders","\u002Fservices\u002Fmetadata-riders","services\u002Fmetadata-riders",{"title":751,"path":752,"stem":753,"access":12,"badge":754},"metrics","\u002Fservices\u002Fmetrics","services\u002Fmetrics","Planned",{"title":756,"path":757,"stem":758,"access":12,"badge":754},"migrations","\u002Fservices\u002Fmigrations","services\u002Fmigrations",{"title":760,"path":761,"stem":762,"access":12},"money","\u002Fservices\u002Fmoney","services\u002Fmoney",{"title":764,"path":765,"stem":766,"access":12},"numbering","\u002Fservices\u002Fnumbering","services\u002Fnumbering",{"title":768,"path":769,"stem":770,"access":12},"overlay-views","\u002Fservices\u002Foverlay-views","services\u002Foverlay-views",{"title":772,"path":773,"stem":774,"access":12,"badge":754},"partitioning","\u002Fservices\u002Fpartitioning","services\u002Fpartitioning",{"title":776,"path":777,"stem":778,"access":12},"periods","\u002Fservices\u002Fperiods","services\u002Fperiods",{"title":780,"path":781,"stem":782,"access":12},"persisted-schemas","\u002Fservices\u002Fpersisted-schemas","services\u002Fpersisted-schemas",{"title":784,"path":785,"stem":786,"access":12},"plaintext-bypass","\u002Fservices\u002Fplaintext-bypass","services\u002Fplaintext-bypass",{"title":788,"path":789,"stem":790,"access":12},"pod-redirect","\u002Fservices\u002Fpod-redirect","services\u002Fpod-redirect",{"title":792,"path":793,"stem":794,"access":12},"pod-signature","\u002Fservices\u002Fpod-signature","services\u002Fpod-signature",{"title":796,"path":797,"stem":798,"access":12},"policy","\u002Fservices\u002Fpolicy","services\u002Fpolicy",{"title":800,"path":801,"stem":802,"access":12},"portability","\u002Fservices\u002Fportability","services\u002Fportability",{"title":804,"path":805,"stem":806,"access":12},"reduce","\u002Fservices\u002Freduce","services\u002Freduce",{"title":808,"path":809,"stem":810,"access":12},"routing","\u002Fservices\u002Frouting","services\u002Frouting",{"title":812,"path":813,"stem":814,"access":12},"satellites","\u002Fservices\u002Fsatellites","services\u002Fsatellites",{"title":816,"path":817,"stem":818,"access":12},"schema-identifiers","\u002Fservices\u002Fschema-identifiers","services\u002Fschema-identifiers",{"title":820,"path":821,"stem":822,"access":12},"schema-update","\u002Fservices\u002Fschema-update","services\u002Fschema-update",{"title":824,"path":825,"stem":826,"access":12},"sealed-record","\u002Fservices\u002Fsealed-record","services\u002Fsealed-record",{"title":828,"path":829,"stem":830,"access":12},"sealing provider id","\u002Fservices\u002Fsealing-pid-stability","services\u002Fsealing-pid-stability",{"title":832,"path":833,"stem":834,"access":12},"search — full-text","\u002Fservices\u002Fsearch","services\u002Fsearch",{"title":836,"path":837,"stem":838,"access":12},"sequence","\u002Fservices\u002Fsequence","services\u002Fsequence",{"title":840,"path":841,"stem":842,"access":12},"session","\u002Fservices\u002Fsession","services\u002Fsession",{"title":844,"path":845,"stem":846,"access":12},"session-tiers","\u002Fservices\u002Fsession-tiers","services\u002Fsession-tiers",{"title":848,"path":849,"stem":850,"access":12},"shadow","\u002Fservices\u002Fshadow","services\u002Fshadow",{"title":852,"path":853,"stem":854,"access":12},"share-link","\u002Fservices\u002Fshare-link","services\u002Fshare-link",{"title":856,"path":857,"stem":858,"access":12},"snapshots","\u002Fservices\u002Fsnapshots","services\u002Fsnapshots",{"title":860,"path":861,"stem":862,"access":12},"store capabilities","\u002Fservices\u002Fstorage-capability-matrix","services\u002Fstorage-capability-matrix",{"title":864,"path":865,"stem":866,"access":12},"sync","\u002Fservices\u002Fsync","services\u002Fsync",{"title":868,"path":869,"stem":870,"access":12},"team","\u002Fservices\u002Fteam","services\u002Fteam",{"title":872,"path":873,"stem":874,"access":12},"tiers","\u002Fservices\u002Ftiers","services\u002Ftiers",{"title":876,"path":877,"stem":878,"access":12},"transactions","\u002Fservices\u002Ftransactions","services\u002Ftransactions",{"title":880,"path":881,"stem":882,"access":12},"partitions","\u002Fservices\u002Ftransferable-partitions","services\u002Ftransferable-partitions",{"title":884,"path":885,"stem":886,"access":12},"user-envelope","\u002Fservices\u002Fuser-envelope","services\u002Fuser-envelope",{"title":888,"path":889,"stem":890,"access":12,"badge":754},"validation","\u002Fservices\u002Fvalidation","services\u002Fvalidation",{"title":892,"path":893,"stem":894,"access":12},"vault-head","\u002Fservices\u002Fvault-head","services\u002Fvault-head",{"title":896,"path":897,"stem":898,"access":12},"via","\u002Fservices\u002Fvia","services\u002Fvia",{"title":900,"path":901,"stem":902,"access":12},"withdrawal","\u002Fservices\u002Fwithdrawal","services\u002Fwithdrawal",{"title":904,"path":905,"stem":906,"children":907},"Start","\u002Fstart","start",[908,911,915,919,923],{"title":10,"path":905,"stem":909,"access":12,"icon":910},"start\u002Findex","i-lucide-flag",{"title":912,"path":913,"stem":914,"access":12},"Install","\u002Fstart\u002Finstall","start\u002F1.install",{"title":916,"path":917,"stem":918,"access":12},"Your first vault","\u002Fstart\u002Ffirst-vault","start\u002F2.first-vault",{"title":920,"path":921,"stem":922,"access":12},"Your first service","\u002Fstart\u002Ffirst-service","start\u002F3.first-service",{"title":924,"path":925,"stem":926,"access":12},"See the ciphertext","\u002Fstart\u002Fsee-the-ciphertext","start\u002F4.see-the-ciphertext",{"id":928,"title":21,"access":12,"apiToc":929,"body":930,"category":3851,"description":3852,"extension":3853,"meta":3854,"navigation":3851,"nest":936,"path":66,"seo":3855,"sinceVersion":3851,"status":3856,"stem":67,"subtitle":3851,"tier":3857,"tocExternal":3851,"__hash__":3858},"docs\u002Fcore\u002F2.noydb\u002F2.enclave.md",false,{"type":931,"value":932,"toc":3820},"minimark",[933,937,952,979,988,993,1028,1031,1039,1071,1098,1116,1122,1172,1183,1245,1249,1264,1271,1274,1374,1377,1400,1404,1408,1421,1424,1477,1497,1501,1504,1603,1606,1687,1690,1757,1759,1764,1886,1896,1900,1922,1970,1973,2007,2030,2054,2057,2070,2181,2301,2312,2320,2350,2353,2388,2395,2399,2406,2763,2789,2793,2796,3026,3030,3033,3173,3177,3180,3187,3196,3202,3216,3383,3390,3428,3439,3545,3548,3575,3581,3585,3588,3757,3775,3779,3816],[934,935,21],"h1",{"id":936},"enclave",[938,939,940],"blockquote",{},[941,942,943,947,948],"p",{},[944,945,946],"strong",{},"Always-on. The non-negotiable trust boundary.","\nSource of truth: ",[949,950,951],"code",{},"packages\u002Fhub\u002Fsrc\u002Fcapsule\u002Fenclave-aes\u002Fcrypto.ts",[941,953,954,955,957,958,961,962,966,967,970,971,974,975,978],{},"An ",[944,956,936],{}," — the term Apple and others use for a restricted, trusted area of a system where privacy and security are structurally ensured — is a place where secrets may exist because nothing outside can reach in. noy-db has one, in software: the region inside ",[949,959,960],{},"@noy-db\u002Fhub"," where keys and plaintext exist ",[963,964,965],"em",{},"at all",". noy-db encrypts every record ",[944,968,969],{},"inside the client library, before it reaches any storage backend"," — the store (a file, a browser database, a cloud bucket) only ever sees ciphertext. The secret-derived KEK, every unwrapped DEK and CEK, and the cleartext of your records are materialized ",[963,972,973],{},"only"," in the hub's process memory, and only while a session is unlocked — ",[949,976,977],{},"db.close()"," scrubs them. The code that does this lives in a self-contained folder inside the hub's kernel that owns the keys, the crypto functions, and the encrypted data format.",[941,980,981,982,987],{},"This page walks the enclave from the outside in: the boundary and its two designed openings, the primitives, how a record is actually encrypted, the three extension layers (users, sealing, per-record keys), the envelope-slot reference and the key-rotation map, the invariants — and, at the very bottom, the dev-only ",[983,984,986],"a",{"href":985},"#plaintext-modes","plaintext modes"," that switch the enclave off for local inspection.",[989,990,992],"h2",{"id":991},"the-enclave","The enclave",[941,994,995,996,999,1000,1003,1004,1007,1008,1011,1012,1015,1016,1019,1020,1023,1024,1027],{},"The far side of the boundary is everything the hub hands data to. The ",[944,997,998],{},"store"," receives only the ciphertext envelope; it never sees plaintext, so it can never run your query — the query DSL lives inside the hub and runs ",[963,1001,1002],{},"after"," decryption. The same holds for every bridge package the family ships: the ",[949,1005,1006],{},"to-*"," storage destinations, the ",[949,1009,1010],{},"in-*"," framework bindings, the ",[949,1013,1014],{},"on-*"," unlock methods, the ",[949,1017,1018],{},"as-*"," exporters, and the ",[949,1021,1022],{},"by-*"," session-share transports ",[944,1025,1026],{},"never see plaintext"," — the encryption happens in the core before data reaches any of them. Encrypt-before-store is not a policy the store cooperates with; it is structural, and the store stays a dumb, untrusted ciphertext shelf.",[941,1029,1030],{},"Everything is encrypted, then. But a vault nothing could ever leave would be a safe, not a database — so the boundary has exactly two designed openings, and both are deliberate.",[1032,1033,1035,1038],"h3",{"id":1034},"at-delegated-decryption",[949,1036,1037],{},"at-*"," — delegated decryption",[941,1040,1041,1042,1044,1045,1049,1050,1049,1054,1049,1058,1049,1062,1066,1067,1070],{},"Sometimes the party that needs to read is not a human with a secret but a machine: a server-side job, a scheduled function, a serverless handler that must process a user's data while the user is asleep. The ",[949,1043,1037],{}," sealing-key hosts (",[983,1046,1048],{"href":1047},"..\u002F..\u002Ffamilies\u002Fat\u002Fenv","at-env",", ",[983,1051,1053],{"href":1052},"..\u002F..\u002Ffamilies\u002Fat\u002Faws-kms","at-aws-kms",[983,1055,1057],{"href":1056},"..\u002F..\u002Ffamilies\u002Fat\u002Fgcp-kms","at-gcp-kms",[983,1059,1061],{"href":1060},"..\u002F..\u002Ffamilies\u002Fat\u002Fazure-keyvault","at-azure-keyvault",[983,1063,1065],{"href":1064},"..\u002F..\u002Ffamilies\u002Fat\u002Fmacos-keychain","at-macos-keychain",") exist for exactly this case: a host ",[944,1068,1069],{},"you"," control holds a sealing key, and that key unseals what was explicitly sealed to it — with no human present to type a secret.",[941,1072,1073,1074,1077,1078,1081,1082,1085,1086,1077,1089,1092,1093,1097],{},"Be precise about what is unsealed, because there are two grants with very different scopes. A ",[944,1075,1076],{},"vault-scoped"," grant (",[949,1079,1080],{},"secretMode: 'managed'"," + ",[949,1083,1084],{},"sealingKey",") seals a machine-generated vault secret to the host, so the host can open — in full — exactly the vaults sealed under its key, and nothing else. A ",[944,1087,1088],{},"record-scoped",[983,1090,824],{"href":1091},"..\u002F..\u002Fservices\u002Fsealed-record",") seals a single record's per-record key to the host, which can then decrypt exactly that one record, until an expiry, and nothing more. The mechanics of both live in ",[983,1094,1096],{"href":1095},"#the-sealing-key","The sealing key"," below.",[941,1099,1100,1101,1104,1105,1107,1108,1111,1112,1115],{},"Either way, this is the family's ",[944,1102,1103],{},"single non-zero-knowledge seam"," — an ",[949,1106,1037],{}," host ",[963,1109,1110],{},"can"," decrypt what it unseals, running on infrastructure you own, by design. The safeguard is ",[963,1113,1114],{},"scope",", not secrecy.",[1032,1117,1119,1121],{"id":1118},"as-the-designed-output-channel",[949,1120,1018],{}," — the designed output channel",[941,1123,1124,1125,1128,1129,1135,1136,1138,1139,1143,1144,1147,1148,1150,1151,1154,1155,1158,1159,1162,1163,1167,1168,1171],{},"Data also flows ",[963,1126,1127],{},"out"," — through the ",[983,1130,1132,1134],{"href":1131},"..\u002F..\u002Ffamilies\u002Fas\u002F",[949,1133,1018],{}," exporters",", the deliberate, user-invoked exit. Every ",[949,1137,1018],{}," artefact sits in one of two tiers, and both pass a capability check on the caller's ",[983,1140,1142],{"href":1141},".\u002Fkeyring","keyring",". The ",[944,1145,1146],{},"plaintext tier"," (CSV, XLSX, JSON, NDJSON, XML, SQL, blob, ZIP) runs ",[963,1149,1002],{}," the hub decrypts and necessarily produces plaintext artefacts — that is the point of an export: an explicit act by a keyholder inside the enclave, gated by the keyring's ",[949,1152,1153],{},"exportCapability.plaintext"," grant (a per-format allow-list), not a leak. The ",[944,1156,1157],{},"bundle tier"," — the ",[949,1160,1161],{},".noydb"," container (",[983,1164,1166],{"href":1165},"..\u002F..\u002Ffamilies\u002Fas\u002Fnoydb","as-noydb",") — never leaves ciphertext: record bodies stay encrypted under the vault's own DEKs end-to-end, and recipient access travels as rebuilt keyring slots that wrap the DEK set under a key derived from the recipient's secret (PBKDF2-SHA256, 600,000 iterations), gated by the keyring's ",[949,1169,1170],{},"exportCapability.bundle"," grant.",[941,1173,1174,1175,1177,1178,1182],{},"The enclave is also the one part of the kernel that is swappable: a sister project can replace the crypto interior wholesale by implementing the frozen enclave contract — the envelope-in \u002F plaintext-out surface, its refusal semantics, and the wire protocol between the kernel and its crypto core are specified in ",[983,1176,25],{"href":26},", and the architecture of the interior itself in ",[983,1179,1181],{"href":1180},"..\u002F..\u002Farchitecture\u002Fkernel\u002Fenclave","Enclave (architecture)",". Everything on this page describes the enclave noy-db ships by default.",[1184,1185,1188,1194,1238],"callout",{"color":1186,"icon":1187},"neutral","i-lucide-eye",[941,1189,1190,1193],{},[944,1191,1192],{},"What the store still learns."," Ciphertext is not invisibility. An observer with store access still sees:",[1195,1196,1197,1209,1220,1227],"ul",{},[1198,1199,1200,1201,1204,1205,1208],"li",{},"the plaintext envelope metadata — ",[949,1202,1203],{},"_v"," (version counter) and ",[949,1206,1207],{},"_ts"," (timestamp) — which the sync engine needs without keys;",[1198,1210,1211,1212,1215,1216,1219],{},"record counts, ids, sizes, and write timing — ",[963,1213,1214],{},"that"," you write and roughly how much, never ",[963,1217,1218],{},"what",";",[1198,1221,1222,1223,1226],{},"with opt-in deterministic fields, the ",[949,1224,1225],{},"_det"," slots' equality classes — which records share a value, acknowledged per collection;",[1198,1228,1229,1230,1233,1234,1237],{},"with opt-in classified ",[949,1231,1232],{},"equatable"," fields, the ",[949,1235,1236],{},"_bidx"," tags — the same equality leak, behind its own acknowledgement gate.",[941,1239,1240,1241,1244],{},"The full walk by attacker position is the ",[983,1242,1243],{"href":464},"threat model",".",[989,1246,1248],{"id":1247},"zero-crypto-dependencies","Zero crypto dependencies",[941,1250,1251,1252,1255,1256,1259,1260,1263],{},"All cryptography uses the Web Crypto API — every operation goes through ",[949,1253,1254],{},"globalThis.crypto.subtle",", and random material comes from ",[949,1257,1258],{},"crypto.getRandomValues",". No ",[949,1261,1262],{},"npm"," crypto packages are or ever will be installed.",[941,1265,1266,1267,1270],{},"That is a security feature, not a footnote. Cryptographic primitives are the worst possible place for a supply-chain compromise, and the way to shrink that attack surface is to have ",[944,1268,1269],{},"zero third-party crypto code",": nothing to audit beyond the runtime itself, no transitive crypto dependency to pin, patch, or watch for CVEs. The primitives are implemented and maintained by the runtime vendor — the same code path the platform itself trusts — and are hardware-accelerated where the platform provides it. It also forces discipline: the Web Crypto API only offers standard, reviewed constructions, so there is no homegrown cipher anywhere in noy-db.",[941,1272,1273],{},"The full primitive set the enclave uses:",[1275,1276,1277,1293],"table",{},[1278,1279,1280],"thead",{},[1281,1282,1283,1287,1290],"tr",{},[1284,1285,1286],"th",{},"Primitive",[1284,1288,1289],{},"Parameters",[1284,1291,1292],{},"Used for",[1294,1295,1296,1308,1319,1330,1341,1352,1363],"tbody",{},[1281,1297,1298,1302,1305],{},[1299,1300,1301],"td",{},"PBKDF2-SHA256",[1299,1303,1304],{},"600,000 iterations, 32-byte salt",[1299,1306,1307],{},"secret → KEK derivation",[1281,1309,1310,1313,1316],{},[1299,1311,1312],{},"AES-KW (RFC 3394)",[1299,1314,1315],{},"256-bit keys",[1299,1317,1318],{},"wrapping DEKs under the KEK (and CEKs under an HKDF-derived wrap key)",[1281,1320,1321,1324,1327],{},[1299,1322,1323],{},"AES-256-GCM",[1299,1325,1326],{},"fresh random 12-byte IV per operation",[1299,1328,1329],{},"record bodies, binary blob chunks",[1281,1331,1332,1335,1338],{},[1299,1333,1334],{},"HKDF-SHA256",[1299,1336,1337],{},"domain-separated salt + info per channel",[1299,1339,1340],{},"deriving subkeys from a DEK: the CEK wrap key, presence key, sealed-field keys, deterministic-index key",[1281,1342,1343,1346,1349],{},[1299,1344,1345],{},"HMAC-SHA256",[1299,1347,1348],{},"keyed by a DEK",[1299,1350,1351],{},"blob eTags, presence integrity",[1281,1353,1354,1357,1360],{},[1299,1355,1356],{},"SHA-256",[1299,1358,1359],{},"—",[1299,1361,1362],{},"content hashes for ledger and bundle integrity",[1281,1364,1365,1369,1371],{},[1299,1366,1367],{},[949,1368,1258],{},[1299,1370,1359],{},[1299,1372,1373],{},"IVs, salts, minted keys and secrets",[941,1375,1376],{},"Available in:",[1195,1378,1379,1382,1385,1388,1391,1394,1397],{},[1198,1380,1381],{},"Node.js 18+",[1198,1383,1384],{},"Bun",[1198,1386,1387],{},"Deno",[1198,1389,1390],{},"Modern browsers",[1198,1392,1393],{},"Cloudflare Workers",[1198,1395,1396],{},"Electron \u002F NW.js",[1198,1398,1399],{},"Mobile WebViews",[989,1401,1403],{"id":1402},"how-a-record-is-encrypted","How a record is encrypted",[1032,1405,1407],{"id":1406},"first-the-ideas-in-plain-words","First, the ideas — in plain words",[941,1409,1410,1411,1414,1415,1244],{},"noy-db is built on ",[944,1412,1413],{},"zero trust"," — the idea that you never assume anyone, even your own server, is safe to show secrets to. The term was popularized around 2010 by John Kindervag at Forrester Research, building on earlier \"de-perimeterization\" work — see ",[983,1416,1420],{"href":1417,"rel":1418},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FZero_trust_architecture",[1419],"nofollow","Zero trust architecture",[941,1422,1423],{},"The rest of this page uses a small cast of characters. Each one, in plain words:",[1195,1425,1426,1433,1440,1450,1459,1465,1471],{},[1198,1427,1428,1429,1432],{},"A ",[944,1430,1431],{},"key"," is a big secret number that scrambles a box shut — and unscrambles it again.",[1198,1434,1435,1436,1439],{},"The ",[944,1437,1438],{},"DEK"," (data-encryption key) is the key that locks your actual documents — one per drawer (a collection).",[1198,1441,1435,1442,1445,1446,1449],{},[944,1443,1444],{},"KEK"," (key-encryption key) is a key whose only job is to lock ",[963,1447,1448],{},"other keys",". It is rebuilt from your secret secret every time you unlock, and it is never written down anywhere.",[1198,1451,1435,1452,1454,1455,1458],{},[944,1453,1142],{}," is the little box of locked-up keys that ",[963,1456,1457],{},"is"," safe to store — because without the KEK it is just noise.",[1198,1460,1435,1461,1464],{},[944,1462,1463],{},"IV"," is a fresh random sprinkle added to every scramble, so the same document never scrambles the same way twice.",[1198,1466,1435,1467,1470],{},[944,1468,1469],{},"envelope"," is the sealed package the storage actually receives — the scrambled document plus its sprinkle, nothing readable.",[1198,1472,1428,1473,1476],{},[944,1474,1475],{},"CEK"," (content-encryption key) is an optional extra: every single document gets its own tiny key, so one document can be destroyed — or lent out — on its own.",[941,1478,1479,1480,1483,1484,1487,1488,1491,1492,1496],{},"One honest note before the details: everything above is ",[944,1481,1482],{},"symmetric"," encryption — the same key locks and unlocks. The other kind, ",[944,1485,1486],{},"asymmetric",", is a two-part lock: anyone can snap it shut with the public part, but only the private part opens it. noy-db uses asymmetric crypto only in special places — ",[983,1489,1490],{"href":1095},"handing one record's key to a machine"," and ",[983,1493,1495],{"href":1494},"#encryption-elsewhere-in-the-family","signing attestations"," — the record path below is symmetric throughout.",[1032,1498,1500],{"id":1499},"the-chain-precisely","The chain, precisely",[941,1502,1503],{},"This is the basic, single-secret flow — one user, one secret, no per-record keys. (The extensions — more users, a sealing key, per-record keys — each add one layer on top and are covered in the next three sections.)",[1505,1506,1508],"div",{"style":1507},"border:1px solid var(--ui-border); border-radius:0.75rem; background:var(--ui-bg-elevated); padding:1.25rem 1rem; margin:1.5rem 0; overflow-x:auto;",[1505,1509,1511,1522,1525,1529,1531,1535,1553,1556,1562,1564,1566,1577,1579,1582,1584,1586],{"style":1510},"display:flex; flex-direction:column; align-items:center; min-width:21rem; text-align:center; line-height:1.35;",[1505,1512,1514,1518],{"style":1513},"border:1px solid var(--ui-border); border-radius:0.5rem; background:var(--ui-bg); padding:0.5rem 1.5rem;",[1505,1515,1517],{"style":1516},"font-weight:600; color:var(--ui-text-highlighted);","Secret",[1505,1519,1521],{"style":1520},"font-size:0.75rem; color:var(--ui-text-muted);","the secret — supplied at unlock, never stored",[1505,1523],{"style":1524},"width:1px; height:0.5rem; background:var(--ui-border);",[1505,1526,1528],{"style":1527},"font-size:0.75rem; color:var(--ui-text-muted); border:1px dashed var(--ui-border); border-radius:999px; padding:0.15rem 0.9rem; margin:0.25rem 0;","PBKDF2-SHA256 · 600,000 iterations · 32-byte salt from the keyring",[1505,1530],{"style":1524},[1505,1532,1534],{"style":1533},"color:var(--ui-text-muted); line-height:1; font-size:0.7rem;","▼",[1505,1536,1538,1546],{"style":1537},"border:1px solid var(--ui-primary); border-radius:0.5rem; background:var(--ui-bg); padding:0.5rem 1.5rem; margin-top:0.25rem;",[1505,1539,1540,1541],{"style":1516},"KEK ",[1542,1543,1545],"span",{"style":1544},"font-weight:400; color:var(--ui-text-muted);","— key-encryption key",[1505,1547,1548,1549],{"style":1520},"memory only · wiped on ",[1542,1550,1552],{"style":1551},"font-family:ui-monospace,monospace;","close()",[1505,1554],{"style":1555},"width:1px; height:0.5rem; background:var(--ui-border); margin-top:0.25rem;",[1505,1557,1558,1559],{"style":1527},"AES-KW (RFC 3394) unwrap · wrapped DEK read from ",[1542,1560,1561],{"style":1551},"_keyring\u002F\u003Cuser>",[1505,1563],{"style":1524},[1505,1565,1534],{"style":1533},[1505,1567,1568,1574],{"style":1537},[1505,1569,1570,1571],{"style":1516},"DEK ",[1542,1572,1573],{"style":1544},"— data-encryption key, one per collection",[1505,1575,1576],{"style":1520},"memory only while the session is unlocked",[1505,1578],{"style":1555},[1505,1580,1581],{"style":1527},"AES-256-GCM · fresh random 12-byte IV per write",[1505,1583],{"style":1524},[1505,1585,1534],{"style":1533},[1505,1587,1589,1592],{"style":1588},"border:1px solid var(--ui-border); border-radius:0.5rem; background:var(--ui-bg); padding:0.5rem 1.5rem; margin-top:0.25rem;",[1505,1590,1591],{"style":1516},"Envelope",[1505,1593,1594,1595,1598,1599,1602],{"style":1520},"ciphertext in ",[1542,1596,1597],{"style":1551},"_data"," + its ",[1542,1600,1601],{"style":1551},"_iv"," — the only thing a store ever receives",[941,1604,1605],{},"Reading top to bottom, each term in the chart is one link in the chain:",[1195,1607,1608,1631,1645,1658,1673],{},[1198,1609,1610,1613,1614,1617,1618,1621,1622,1624,1625,1627,1628,1630],{},[944,1611,1612],{},"Secret → KEK."," The secret you pass as ",[949,1615,1616],{},"secret"," to ",[949,1619,1620],{},"createNoydb()"," is fed through ",[944,1623,1301],{}," at 600,000 iterations, salted with a random 32-byte salt, to derive the ",[944,1626,1444],{}," (key-encryption key). PBKDF2 is a deliberately slow, brute-force-resistant key-derivation function — the iteration count is the cost an attacker pays per password guess. The KEK is never persisted; it lives only in memory during an active session, and ",[949,1629,977],{}," wipes it.",[1198,1632,1633,1636,1637,1639,1640,1642,1643,1244],{},[944,1634,1635],{},"The keyring."," The salt — and everything else the vault must remember about your access — lives in the ",[944,1638,1142],{},", the persisted record at ",[949,1641,1561],{}," inside the vault. It holds your wrapped keys, never usable ones: see ",[983,1644,69],{"href":1141},[1198,1646,1647,1650,1651,1653,1654,1657],{},[944,1648,1649],{},"DEK."," Each collection gets its own ",[944,1652,1438],{}," (data-encryption key), a randomly generated AES-256-GCM key. Your copy of each DEK is stored in the keyring ",[944,1655,1656],{},"AES-KW-wrapped"," under your KEK — AES-KW (RFC 3394) is the standard construction for encrypting one key under another. Unlocking a session unwraps the DEKs into memory; they are never persisted unwrapped.",[1198,1659,1660,1663,1664,1104,1666,1669,1670,1672],{},[944,1661,1662],{},"Envelope."," A record body is serialized to JSON and encrypted with ",[944,1665,1323],{},[963,1667,1668],{},"authenticated"," cipher: it produces both ciphertext and an integrity tag, so tampering is detected at decrypt time. Every encrypt call uses a fresh random 12-byte ",[944,1671,1463],{}," (initialization vector); an IV is never reused.",[1198,1674,1675,1678,1679,1682,1683,1097],{},[944,1676,1677],{},"CEK."," A collection can additionally opt into per-record ",[944,1680,1681],{},"content-encryption keys"," — one key per record, enabling per-record erasure and sealing — introduced in ",[983,1684,1686],{"href":1685},"#per-record-keys-cek","Per-record keys (CEK)",[941,1688,1689],{},"The two directions are the same chain walked in opposite orders:",[1691,1692,1693,1718],"ol",{},[1198,1694,1695,1698,1699,1702,1703,1706,1707,1710,1711,1714,1715,1717],{},[944,1696,1697],{},"Encrypting a write"," — ",[963,1700,1701],{},"derive"," the KEK from the secret (once per unlock), ",[963,1704,1705],{},"unwrap"," the collection's DEK from the keyring, ",[963,1708,1709],{},"encrypt"," the record body under the DEK with a fresh IV, ",[963,1712,1713],{},"wrap"," the result in an envelope, and ",[963,1716,998],{}," it. The store receives ciphertext, nothing else.",[1198,1719,1720,1723,1724,1726,1727,1730,1731,1733,1734,1736,1737,1740,1741,1744,1745,1748,1749,1752,1753,1756],{},[944,1721,1722],{},"Decrypting a read"," — fetch the ",[963,1725,1469],{}," from the store, ",[963,1728,1729],{},"authenticated-decrypt"," ",[949,1732,1597],{}," under the DEK using the stored ",[949,1735,1601],{}," — the GCM tag is verified as part of decryption — over the body ",[963,1738,1739],{},"and"," the record's bound identity and version — so an envelope that does not authenticate throws ",[949,1742,1743],{},"TamperedError"," and the read ",[944,1746,1747],{},"fails closed",": there is no partial-decryption fallback (a body sealed before that binding also fails, and reports ",[949,1750,1751],{},"reason: 'unbound-legacy-format'",") — then parse the ",[963,1754,1755],{},"plaintext"," JSON body.",[1032,1758,1591],{"id":1469},[941,1760,1435,1761,1763],{},[963,1762,1469],{}," is the wrapper a store receives instead of your record:",[1765,1766,1770],"pre",{"className":1767,"code":1768,"language":141,"meta":1769,"style":1769},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"_noydb\": 1,\n  \"_v\":     3,\n  \"_ts\":    \"2026-04-04T10:00:00.000Z\",\n  \"_iv\":    \"\u003Cbase64>\",\n  \"_data\":  \"\u003Cbase64 ciphertext>\"\n}\n","",[949,1771,1772,1780,1803,1819,1841,1861,1880],{"__ignoreMap":1769},[1542,1773,1776],{"class":1774,"line":1775},"line",1,[1542,1777,1779],{"class":1778},"sMK4o","{\n",[1542,1781,1783,1786,1790,1793,1796,1800],{"class":1774,"line":1782},2,[1542,1784,1785],{"class":1778},"  \"",[1542,1787,1789],{"class":1788},"spNyl","_noydb",[1542,1791,1792],{"class":1778},"\"",[1542,1794,1795],{"class":1778},":",[1542,1797,1799],{"class":1798},"sbssI"," 1",[1542,1801,1802],{"class":1778},",\n",[1542,1804,1806,1808,1810,1812,1814,1817],{"class":1774,"line":1805},3,[1542,1807,1785],{"class":1778},[1542,1809,1203],{"class":1788},[1542,1811,1792],{"class":1778},[1542,1813,1795],{"class":1778},[1542,1815,1816],{"class":1798},"     3",[1542,1818,1802],{"class":1778},[1542,1820,1822,1824,1826,1828,1830,1833,1837,1839],{"class":1774,"line":1821},4,[1542,1823,1785],{"class":1778},[1542,1825,1207],{"class":1788},[1542,1827,1792],{"class":1778},[1542,1829,1795],{"class":1778},[1542,1831,1832],{"class":1778},"    \"",[1542,1834,1836],{"class":1835},"sfazB","2026-04-04T10:00:00.000Z",[1542,1838,1792],{"class":1778},[1542,1840,1802],{"class":1778},[1542,1842,1844,1846,1848,1850,1852,1854,1857,1859],{"class":1774,"line":1843},5,[1542,1845,1785],{"class":1778},[1542,1847,1601],{"class":1788},[1542,1849,1792],{"class":1778},[1542,1851,1795],{"class":1778},[1542,1853,1832],{"class":1778},[1542,1855,1856],{"class":1835},"\u003Cbase64>",[1542,1858,1792],{"class":1778},[1542,1860,1802],{"class":1778},[1542,1862,1864,1866,1868,1870,1872,1874,1877],{"class":1774,"line":1863},6,[1542,1865,1785],{"class":1778},[1542,1867,1597],{"class":1788},[1542,1869,1792],{"class":1778},[1542,1871,1795],{"class":1778},[1542,1873,1785],{"class":1778},[1542,1875,1876],{"class":1835},"\u003Cbase64 ciphertext>",[1542,1878,1879],{"class":1778},"\"\n",[1542,1881,1883],{"class":1774,"line":1882},7,[1542,1884,1885],{"class":1778},"}\n",[941,1887,1888,1204,1890,1892,1893,1895],{},[949,1889,1203],{},[949,1891,1207],{}," (timestamp) are NOT encrypted — the sync engine needs them without keys. Everything inside ",[949,1894,1597],{}," IS encrypted.",[989,1897,1899],{"id":1898},"users-the-keyring","Users & the keyring",[941,1901,1902,1903,1906,1907,1909,1910,1912,1913,1917,1918,1921],{},"The multi-user extension changes nothing about the chain above — it multiplies one link. The collection DEKs stay the same keys; what a member holds is their ",[944,1904,1905],{},"own wrapped copy"," of them, in their own ",[949,1908,1561],{}," record, wrapped under their own KEK (derived from their own secret and salt). Granting a user wraps the DEKs for the new member; revoking one re-wraps the DEKs for the remaining members, so the revoked keyring can no longer unwrap anything current. The keyring is thus both the access-control list and the cryptographic gate: what you can read is exactly what your keyring can unwrap. The single-user primitives live on ",[983,1911,69],{"href":1141},", the roles and grant\u002Frevoke ceremony on ",[983,1914,1916],{"href":1915},"..\u002F06-permissions-and-keyring","Permissions & keyring",", and the multi-user ceremony itself is the opt-in ",[983,1919,868],{"href":1920},"..\u002F..\u002Fservices\u002Fteam"," service.",[1505,1923,1924],{"style":1507},[1505,1925,1926,1935,1938,1941],{"style":1510},[1505,1927,1929,1932],{"style":1928},"border:1px solid var(--ui-primary); border-radius:0.5rem; background:var(--ui-bg); padding:0.5rem 1.5rem;",[1505,1930,1931],{"style":1516},"Collection DEK",[1505,1933,1934],{"style":1520},"one key — every member reads the same ciphertext",[1505,1936],{"style":1937},"width:1px; height:0.6rem; background:var(--ui-border);",[1505,1939,1940],{"style":1527},"AES-KW wrap · once per member, under each member’s KEK",[1505,1942,1944,1954,1961],{"style":1943},"display:flex; gap:0.75rem; margin-top:0.5rem; flex-wrap:wrap; justify-content:center;",[1505,1945,1947,1951],{"style":1946},"border:1px solid var(--ui-border); border-radius:0.5rem; background:var(--ui-bg); padding:0.4rem 1rem;",[1505,1948,1950],{"style":1949},"font-size:0.8125rem; font-family:ui-monospace,monospace; color:var(--ui-text-highlighted);","_keyring\u002Falice",[1505,1952,1953],{"style":1520},"wrapped copy",[1505,1955,1956,1959],{"style":1946},[1505,1957,1958],{"style":1949},"_keyring\u002Fbob",[1505,1960,1953],{"style":1520},[1505,1962,1963,1967],{"style":1946},[1505,1964,1966],{"style":1965},"font-size:0.8125rem; font-family:ui-monospace,monospace; color:var(--ui-text-muted);","_keyring\u002F…",[1505,1968,1969],{"style":1520},"grant = wrap · revoke = re-wrap the rest",[989,1971,1096],{"id":1972},"the-sealing-key",[941,1974,1435,1975,1977,1978,1981,1982,1985,1986,1989,1990,1049,1993,1049,1996,1999,2000,2006],{},[949,1976,1037],{}," extension replaces the ",[963,1979,1980],{},"human"," at the top of the chart with a ",[963,1983,1984],{},"host",". A sealing-key provider is a tiny contract — ",[949,1987,1988],{},"NoydbSealer",", three members: ",[949,1991,1992],{},"id",[949,1994,1995],{},"seal(bytes)",[949,1997,1998],{},"unseal(bytes)"," — implemented by each ",[983,2001,2003,2005],{"href":2002},"..\u002F..\u002Ffamilies\u002Fat\u002F",[949,2004,1037],{}," package"," over whatever the host trusts: an env var, the OS keychain, a cloud KMS.",[941,2008,2009,2010,2013,2014,2017,2018,2021,2022,2025,2026,2029],{},"In ",[944,2011,2012],{},"managed-secret mode"," (",[949,2015,2016],{},"createNoydb({ secretMode: 'managed', sealingKey })",") the hub generates a random 256-bit secret at first open, seals it under the provider, and persists the sealed blob per vault at ",[949,2019,2020],{},"_meta\u002Fsealed-secret","; on reopen it checks the stored provider id, unseals, and feeds the secret into the normal PBKDF2 → KEK chain. The user never sees or types it. The scope of this grant is the ",[944,2023,2024],{},"whole vault",": a host holding the sealing key can open exactly the vaults sealed under its key — nothing else, but nothing less. (Managed mode is also the rubber-hose-resistant posture — see ",[983,2027,844],{"href":2028},"..\u002F..\u002Fservices\u002Fsession-tiers",".)",[941,2031,1435,2032,2034,2035,2037,2038,2041,2042,2045,2046,2048,2049,2053],{},[944,2033,1088],{}," variant is ",[983,2036,824],{"href":1091},": the grantor unwraps one record's CEK, binds it into ",[949,2039,2040],{},"{collection, id, cek, expiresAt}",", seals that binding via the host's pluggable sealer (RSA-OAEP-SHA256 over a fresh AES-GCM transport key in the shipped providers), and writes the delivery envelope at ",[949,2043,2044],{},"_sealed_cek\u002F\u003Ccollection>\u002F\u003Cid>\u002F\u003Cpid>",". The host-side opener verifies the expiry and that the binding names exactly the record it is being used on, then decrypts that one record — it never touches a DEK, and a CEK sealed for record A is rejected against record B. One provider ",[949,2047,1992],{}," string identifies each host across every sealed artefact — frozen once shipped (",[983,2050,2052],{"href":2051},"..\u002F..\u002Fservices\u002Fsealing-pid-stability","sealing-pid-stability",").",[989,2055,1686],{"id":2056},"per-record-keys-cek",[941,2058,2059,2060,2063,2064,2066,2067,1795],{},"By default one per-collection DEK encrypts every record body. Opt a collection into per-record content-encryption keys with ",[949,2061,2062],{},"vault.collection(name, { perRecordKeys: true })"," and each record gets its own AES-256-GCM ",[944,2065,1475],{},", AES-KW-wrapped under the collection DEK and stored on the envelope's ",[949,2068,2069],{},"_cek",[1765,2071,2073],{"className":1767,"code":2072,"language":141,"meta":1769,"style":1769},"{\n  \"_noydb\": 1, \"_v\": 3, \"_ts\": \"…\",\n  \"_iv\": \"\u003Cbase64>\", \"_data\": \"\u003Cbase64 ciphertext, encrypted under the CEK>\",\n  \"_cek\": \"\u003Cbase64 AES-KW-wrapped CEK, wrapped under the collection\u002Ftier DEK>\"\n}\n",[949,2074,2075,2079,2125,2160,2177],{"__ignoreMap":1769},[1542,2076,2077],{"class":1774,"line":1775},[1542,2078,1779],{"class":1778},[1542,2080,2081,2083,2085,2087,2089,2091,2094,2097,2099,2101,2103,2106,2108,2110,2112,2114,2116,2118,2121,2123],{"class":1774,"line":1782},[1542,2082,1785],{"class":1778},[1542,2084,1789],{"class":1788},[1542,2086,1792],{"class":1778},[1542,2088,1795],{"class":1778},[1542,2090,1799],{"class":1798},[1542,2092,2093],{"class":1778},",",[1542,2095,2096],{"class":1778}," \"",[1542,2098,1203],{"class":1788},[1542,2100,1792],{"class":1778},[1542,2102,1795],{"class":1778},[1542,2104,2105],{"class":1798}," 3",[1542,2107,2093],{"class":1778},[1542,2109,2096],{"class":1778},[1542,2111,1207],{"class":1788},[1542,2113,1792],{"class":1778},[1542,2115,1795],{"class":1778},[1542,2117,2096],{"class":1778},[1542,2119,2120],{"class":1835},"…",[1542,2122,1792],{"class":1778},[1542,2124,1802],{"class":1778},[1542,2126,2127,2129,2131,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151,2153,2156,2158],{"class":1774,"line":1805},[1542,2128,1785],{"class":1778},[1542,2130,1601],{"class":1788},[1542,2132,1792],{"class":1778},[1542,2134,1795],{"class":1778},[1542,2136,2096],{"class":1778},[1542,2138,1856],{"class":1835},[1542,2140,1792],{"class":1778},[1542,2142,2093],{"class":1778},[1542,2144,2096],{"class":1778},[1542,2146,1597],{"class":1788},[1542,2148,1792],{"class":1778},[1542,2150,1795],{"class":1778},[1542,2152,2096],{"class":1778},[1542,2154,2155],{"class":1835},"\u003Cbase64 ciphertext, encrypted under the CEK>",[1542,2157,1792],{"class":1778},[1542,2159,1802],{"class":1778},[1542,2161,2162,2164,2166,2168,2170,2172,2175],{"class":1774,"line":1821},[1542,2163,1785],{"class":1778},[1542,2165,2069],{"class":1788},[1542,2167,1792],{"class":1778},[1542,2169,1795],{"class":1778},[1542,2171,2096],{"class":1778},[1542,2173,2174],{"class":1835},"\u003Cbase64 AES-KW-wrapped CEK, wrapped under the collection\u002Ftier DEK>",[1542,2176,1879],{"class":1778},[1542,2178,2179],{"class":1774,"line":1843},[1542,2180,1885],{"class":1778},[1195,2182,2183,2199,2218,2245,2266,2280],{},[1198,2184,2185,2191,2192,2194,2195,2198],{},[944,2186,2187,2188,2190],{},"Discriminant is ",[949,2189,2069],{}," presence, not the flag."," A record with ",[949,2193,2069],{}," is decrypted by unwrapping the CEK under the collection DEK then decrypting the body under the CEK; a record without it takes the legacy path (body directly under the collection DEK). So a collection without ",[949,2196,2197],{},"perRecordKeys"," is byte-identical to before, and a mixed vault — or a recipient that never set the flag — reads both kinds.",[1198,2200,2201,2204,2205,2208,2209,2211,2212,2214,2215,1244],{},[944,2202,2203],{},"Stable across versions."," Insert mints the CEK; updates and history snapshots reuse it, so every ",[949,2206,2207],{},"_history"," envelope for a record carries the same ",[949,2210,2069],{},". (The wrapping key is HKDF-derived from the DEK and the wrap is deterministic, which is what makes the reused ",[949,2213,2069],{}," byte-identical.) A session-scoped LRU caches the unwrapped CEK per ",[949,2216,2217],{},"(collection, id)",[1198,2219,2220,2223,2224,2013,2227,2230,2231,2234,2235,2237,2238,2241,2242,2244],{},[944,2221,2222],{},"Deterministic index slots stay collection-keyed."," A collection can opt specific fields into ",[963,2225,2226],{},"deterministic encryption",[949,2228,2229],{},"deterministicFields",", acknowledged with ",[949,2232,2233],{},"acknowledgeDeterministicRisk: true","): the field value is additionally stored in the envelope's ",[949,2236,1225],{}," map, encrypted so that equal plaintext produces equal ciphertext — enabling blind equality search (",[949,2239,2240],{},"findByDet",") without decrypting every record, at the cost of leaking which records share a value. ",[949,2243,1225],{}," slots are keyed off a key derived from the collection DEK, never the per-record CEK — cross-record equality only works if all records share the key.",[1198,2246,2247,2250,2251,2254,2255,2258,2259,2262,2263,1244],{},[944,2248,2249],{},"Tiers compose."," Moving a record between hierarchical access tiers (",[949,2252,2253],{},"elevate","\u002F",[949,2256,2257],{},"demote",") re-wraps the ",[963,2260,2261],{},"same"," CEK from the source tier DEK to the target tier DEK; the body key is unchanged — the elevation API that drives this re-wrap lives in ",[983,2264,872],{"href":2265},"..\u002F..\u002Fservices\u002Ftiers",[1198,2267,2268,2271,2272,2276,2277,2279],{},[944,2269,2270],{},"Bundles re-wrap."," When records leave the vault as a portable bundle (",[983,2273,2275],{"href":2274},"..\u002F..\u002Fservices\u002Ftransferable-partitions","transferable partitions","), the re-key step unwraps each ",[949,2278,2069],{}," under the source DEK and re-wraps it under the fresh destination DEK, so adopted records stay decryptable.",[1198,2281,2282,2285,2286,2289,2290,2254,2292,2294,2295,2298,2299,1244],{},[944,2283,2284],{},"Tombstone-tolerant read."," A ",[949,2287,2288],{},"get()"," on an envelope with no ",[949,2291,1597],{},[949,2293,2069],{}," returns ",[949,2296,2297],{},"null"," rather than throwing ",[949,2300,1743],{},[941,2302,2303,2304,2308,2309,2311],{},"Per-record keys are the foundation that makes per-record erasure (crypto-shred — see the ",[983,2305,2307],{"href":2306},"..\u002F..\u002Fservices\u002Fforget","forget service",") and record-scoped sealing (",[983,2310,824],{"href":1091},") possible: destroy one record's wrapped CEK and only that record becomes undecryptable.",[1032,2313,2315,2316,2319],{"id":2314},"sealed-fields-_sealed","Sealed fields (",[949,2317,2318],{},"_sealed",")",[941,2321,2322,2323,2326,2327,2331,2332,2335,2336,2338,2339,2341,2342,2345,2346,2349],{},"A collection can additionally pull individual sensitive fields out of the record body: declare them in the collection's ",[949,2324,2325],{},"sensitive: [...]"," option and each declared field is encrypted into its own slot in the envelope's ",[944,2328,2329],{},[949,2330,2318],{}," map — an ",[949,2333,2334],{},"iv:data"," blob per field — instead of travelling inside ",[949,2337,1597],{},". A reader who can open ",[949,2340,1597],{}," still cannot see a sealed field without deriving that field's key: each field gets a ",[944,2343,2344],{},"distinct"," AES-256-GCM key, HKDF-derived with an injective ",[949,2347,2348],{},"[domain, collection, field]"," context, so one field's ciphertext does not authenticate under another field's key — sealed fields are cryptographically isolated from one another, and from the same field name in any other collection.",[941,2351,2352],{},"The field key's parent follows the record's key model:",[1195,2354,2355,2371],{},[1198,2356,2357,2358,2360,2361,2363,2364,2367,2368,2370],{},"On a ",[949,2359,2197],{}," collection the field key derives from the record's ",[944,2362,1475],{}," (HKDF domain ",[949,2365,2366],{},"noydb-sealed-cek",") — which extends the crypto-shred guarantee to sealed fields: destroying the record's wrapped ",[949,2369,2069],{}," makes every sealed field unrecoverable along with the body.",[1198,2372,2373,2374,2376,2377,2380,2381,2383,2384,2387],{},"Without per-record keys it derives from the collection ",[944,2375,1438],{}," (domain ",[949,2378,2379],{},"noydb-sealed",") — and ",[983,2382,685],{"href":2306}," then reports those slots as ",[963,2385,2386],{},"residue"," rather than shredded: a synced or backed-up copy stays decryptable as long as the collection DEK survives.",[941,2389,2390,2391,2394],{},"Reads dual-read — the CEK-derived key first, then the DEK-derived key as the legacy fallback — so records sealed before a collection adopted per-record keys stay readable. The ergonomic layer on top is the ",[983,2392,633],{"href":2393},"..\u002F..\u002Fservices\u002Fclassified"," service: declare a field once with a preset and it routes to sealed (recoverable) or digest-only storage, with safe projections and audited reveal.",[989,2396,2398],{"id":2397},"envelope-slots-the-reference","Envelope slots — the reference",[941,2400,2401,2402,2405],{},"Every layer above writes into the same wrapper. This is the complete set of ",[949,2403,2404],{},"_","-slots a record envelope can carry — five slots every envelope has, and the rest present only when a feature writes them:",[1275,2407,2408,2427],{},[1278,2409,2410],{},[1281,2411,2412,2415,2418,2421,2424],{},[1284,2413,2414],{},"Slot",[1284,2416,2417],{},"What it holds",[1284,2419,2420],{},"Encrypted?",[1284,2422,2423],{},"Key",[1284,2425,2426],{},"Introduced by",[1294,2428,2429,2446,2462,2478,2494,2516,2533,2560,2579,2599,2623,2646,2669,2697,2719,2743],{},[1281,2430,2431,2435,2438,2441,2443],{},[1299,2432,2433],{},[949,2434,1789],{},[1299,2436,2437],{},"format version marker",[1299,2439,2440],{},"no",[1299,2442,1359],{},[1299,2444,2445],{},"core — every envelope",[1281,2447,2448,2452,2455,2458,2460],{},[1299,2449,2450],{},[949,2451,1203],{},[1299,2453,2454],{},"version counter",[1299,2456,2457],{},"no — sync orders by it without keys",[1299,2459,1359],{},[1299,2461,2445],{},[1281,2463,2464,2468,2471,2474,2476],{},[1299,2465,2466],{},[949,2467,1207],{},[1299,2469,2470],{},"write timestamp (ISO 8601)",[1299,2472,2473],{},"no — sync needs it without keys",[1299,2475,1359],{},[1299,2477,2445],{},[1281,2479,2480,2484,2487,2490,2492],{},[1299,2481,2482],{},[949,2483,1601],{},[1299,2485,2486],{},"the body's fresh random IV",[1299,2488,2489],{},"no — an IV is not secret",[1299,2491,1359],{},[1299,2493,2445],{},[1281,2495,2496,2500,2503,2508,2514],{},[1299,2497,2498],{},[949,2499,1597],{},[1299,2501,2502],{},"the record body, ciphertext",[1299,2504,2505],{},[944,2506,2507],{},"yes",[1299,2509,2510,2511,2513],{},"collection\u002Ftier DEK — or the record's CEK when ",[949,2512,2069],{}," is present",[1299,2515,2445],{},[1281,2517,2518,2523,2526,2528,2530],{},[1299,2519,2520],{},[949,2521,2522],{},"_by",[1299,2524,2525],{},"actor id who wrote this version",[1299,2527,2440],{},[1299,2529,1359],{},[1299,2531,2532],{},"core — stamped when the writer is known",[1281,2534,2535,2544,2547,2549,2551],{},[1299,2536,2537,2540,2541],{},[949,2538,2539],{},"_source"," \u002F ",[949,2542,2543],{},"_sourceTs",[1299,2545,2546],{},"provenance source id + timestamp",[1299,2548,2440],{},[1299,2550,1359],{},[1299,2552,2553,1698,2556],{},[949,2554,2555],{},"provenance: true",[983,2557,2559],{"href":2558},"..\u002F..\u002Fservices\u002Ffield-metadata","field-metadata",[1281,2561,2562,2567,2570,2573,2575],{},[1299,2563,2564],{},[949,2565,2566],{},"_tier",[1299,2568,2569],{},"the record's access tier",[1299,2571,2572],{},"no — reads route to the right tier DEK without try-decrypting",[1299,2574,1359],{},[1299,2576,2577],{},[983,2578,872],{"href":2265},[1281,2580,2581,2586,2591,2593,2595],{},[1299,2582,2583],{},[949,2584,2585],{},"_elevatedBy",[1299,2587,2588,2589,2319],{},"who elevated the record (gates ",[949,2590,2257],{},[1299,2592,2440],{},[1299,2594,1359],{},[1299,2596,2597],{},[983,2598,872],{"href":2265},[1281,2600,2601,2605,2608,2613,2616],{},[1299,2602,2603],{},[949,2604,2069],{},[1299,2606,2607],{},"the record's own key, AES-KW-wrapped",[1299,2609,2610,2612],{},[944,2611,2507],{}," — a wrapped key",[1299,2614,2615],{},"wrapped under the collection\u002Ftier DEK",[1299,2617,2618,1698,2620],{},[949,2619,2197],{},[983,2621,2622],{"href":1685},"above",[1281,2624,2625,2629,2632,2637,2640],{},[1299,2626,2627],{},[949,2628,1225],{},[1299,2630,2631],{},"deterministic equality index, per field",[1299,2633,2634,2636],{},[944,2635,2507],{}," — deterministic: equal values → equal ciphertext (acknowledged leak)",[1299,2638,2639],{},"HKDF(DEK) deterministic-index key",[1299,2641,2642,1698,2644],{},[949,2643,2229],{},[983,2645,2622],{"href":1685},[1281,2647,2648,2652,2655,2659,2662],{},[1299,2649,2650],{},[949,2651,2318],{},[1299,2653,2654],{},"per-field sealed ciphertext",[1299,2656,2657],{},[944,2658,2507],{},[1299,2660,2661],{},"HKDF per-field key from the CEK (or the DEK for legacy records)",[1299,2663,2664,1698,2666],{},[949,2665,2325],{},[983,2667,2622],{"href":2668},"#sealed-fields-_sealed",[1281,2670,2671,2676,2679,2687,2692],{},[1299,2672,2673],{},[949,2674,2675],{},"_vdig",[1299,2677,2678],{},"classified verify-digest blobs (digest + reuse ring)",[1299,2680,2681,2683,2684],{},[944,2682,2507],{}," — AAD-bound to ",[949,2685,2686],{},"[collection, record, field]",[1299,2688,2689,2690],{},"HKDF(CEK) vdig slot key — CEK-only, dies with ",[949,2691,2069],{},[1299,2693,2694,2695],{},"classified digest-only fields — ",[983,2696,633],{"href":2393},[1281,2698,2699,2703,2706,2709,2712],{},[1299,2700,2701],{},[949,2702,1236],{},[1299,2704,2705],{},"classified equality tag (cost byte ‖ keyed MAC)",[1299,2707,2708],{},"not reversible ciphertext — a store-visible keyed MAC",[1299,2710,2711],{},"HMAC key HKDF-derived from the DEK",[1299,2713,2714,2715,1698,2717],{},"classified ",[949,2716,1232],{},[983,2718,633],{"href":2393},[1281,2720,2721,2726,2729,2732,2734],{},[1299,2722,2723],{},[949,2724,2725],{},"_debug",[1299,2727,2728],{},"debug-plaintext marker; fields inlined beside it",[1299,2730,2731],{},"no — the whole envelope is plaintext",[1299,2733,1359],{},[1299,2735,2736,1698,2739],{},[949,2737,2738],{},"debugPlaintext",[983,2740,2742],{"href":2741},"#debug-plaintext-layout-debugplaintext","below",[1281,2744,2745,2750,2753,2755,2757],{},[1299,2746,2747],{},[949,2748,2749],{},"_del",[1299,2751,2752],{},"delete marker (empty body, version-ordered)",[1299,2754,2440],{},[1299,2756,1359],{},[1299,2758,2759,2760],{},"deletes under ",[983,2761,864],{"href":2762},"..\u002F..\u002Fservices\u002Fsync",[941,2764,2765,2766,2768,2769,2771,2772,2775,2776,2254,2778,2781,2782,2785,2786,2053],{},"Two neighbours of the record envelope keep their own slot sets: ",[949,2767,2207],{}," envelopes are ordinary envelopes (same slots — and the same ",[949,2770,2069],{},", which is what lets per-record erasure cover history), and blob ",[963,2773,2774],{},"index"," objects carry their own ",[949,2777,2069],{},[949,2779,2780],{},"_cekPending"," wrapped content keys under the ",[949,2783,2784],{},"_blob"," DEK (",[983,2787,621],{"href":2788},"..\u002F..\u002Fservices\u002Fblobs",[989,2790,2792],{"id":2791},"key-lifecycle-rotation","Key lifecycle & rotation",[941,2794,2795],{},"Every key above has a rotation story. This is the whole map — the trigger, what actually gets re-encrypted or re-wrapped, and where each ceremony is documented:",[1275,2797,2798,2814],{},[1278,2799,2800],{},[1281,2801,2802,2805,2808,2811],{},[1284,2803,2804],{},"What rotates",[1284,2806,2807],{},"Trigger \u002F API",[1284,2809,2810],{},"What is re-wrapped or re-encrypted",[1284,2812,2813],{},"Where documented",[1294,2815,2816,2840,2865,2889,2920,2940,2967,2987,3007],{},[1281,2817,2818,2823,2833,2836],{},[1299,2819,2820],{},[944,2821,2822],{},"Secret → KEK",[1299,2824,2825,2828,2829,2832],{},[949,2826,2827],{},"db.team.rotateSecret(vault, input)"," — user remembers the old one; behind the ",[949,2830,2831],{},"rotate-secret"," policy gate",[1299,2834,2835],{},"a fresh salt and KEK are derived; the keyring's DEKs are unwrapped under the old KEK and re-wrapped under the new one — the DEKs themselves do not change",[1299,2837,2838],{},[983,2839,69],{"href":1141},[1281,2841,2842,2847,2853,2856],{},[1299,2843,2844],{},[944,2845,2846],{},"Secret, forgotten",[1299,2848,2849,2852],{},[949,2850,2851],{},"db.team.recoverSecret(vault, input)"," — a recovery proof stands in for the old secret",[1299,2854,2855],{},"the DEK set is recovered via the enrolled profile and re-wrapped under the new secret's KEK",[1299,2857,2858,2860,2861],{},[983,2859,69],{"href":1141}," · ",[983,2862,2864],{"href":2863},".\u002Frecovery","Recovery",[1281,2866,2867,2872,2882,2885],{},[1299,2868,2869],{},[944,2870,2871],{},"Managed secret",[1299,2873,2874,2877,2878,2881],{},[949,2875,2876],{},"db.team.recoverManagedSecret(vault, options)"," — in managed mode ",[949,2879,2880],{},"rotateSecret"," is unavailable; recovery is the sanctioned reset",[1299,2883,2884],{},"the machine-minted secret is replaced and re-sealed under the sealing-key provider (the provider itself is unchanged)",[1299,2886,2887],{},[983,2888,2864],{"href":2863},[1281,2890,2891,2896,2909,2916],{},[1299,2892,2893],{},[944,2894,2895],{},"Collection DEKs",[1299,2897,2898,1698,2901,2904,2905,2908],{},[949,2899,2900],{},"db.rotate(vault, collections)",[944,2902,2903],{},"other members lose access to the rotated collections","; or ",[949,2906,2907],{},"db.revoke(vault, { userId })",", which always rotates when a member is removed",[1299,2910,2911,2912,2915],{},"fresh DEKs are minted, ",[944,2913,2914],{},"every record in each collection is re-encrypted",", and only the caller's keyring gets the new DEKs — every other member's entries for those collections are dropped and must be re-granted",[1299,2917,2918],{},[983,2919,1916],{"href":1915},[1281,2921,2922,2927,2930,2933],{},[1299,2923,2924],{},[944,2925,2926],{},"HKDF-derived subkeys",[1299,2928,2929],{},"automatic — the presence key, the deterministic-index key, and the DEK-derived sealed-field keys are HKDF children of the collection DEK",[1299,2931,2932],{},"they rotate whenever their parent DEK rotates; a revoked user cannot derive the new presence key",[1299,2934,2935,2936],{},"this page — ",[983,2937,2939],{"href":2938},"#zero-crypto-dependencies","primitives",[1281,2941,2942,2947,2956,2963],{},[1299,2943,2944],{},[944,2945,2946],{},"A record's CEK",[1299,2948,2949,2952,2953],{},[949,2950,2951],{},"vault.rotateRecordCek(collection, id)"," — directly, or via ",[949,2954,2955],{},"revokeSealedRecord(…, { hard: true })",[1299,2957,2958,2959,2962],{},"the live body is re-encrypted under a fresh CEK and every ",[949,2960,2961],{},"_sealed_cek"," delivery envelope for the record is deleted; history versions keep their original CEK",[1299,2964,2965],{},[983,2966,824],{"href":1091},[1281,2968,2969,2974,2980,2983],{},[1299,2970,2971],{},[944,2972,2973],{},"Recovery material",[1299,2975,2976,2979],{},[949,2977,2978],{},"db.team.rotateRecovery(vault, options)"," — deliberate paper\u002FShamir regeneration",[1299,2981,2982],{},"the enrolled recovery entry is replaced — a reissued paper sheet or a re-shared Shamir entry",[1299,2984,2985],{},[983,2986,2864],{"href":2863},[1281,2988,2989,2994,2999,3002],{},[1299,2990,2991],{},[944,2992,2993],{},"Broker seed",[1299,2995,2996],{},[949,2997,2998],{},"vault.broker().rotate()",[1299,3000,3001],{},"a new seed is registered before the old is dropped, with a grace window for in-flight proofs",[1299,3003,3004],{},[983,3005,625],{"href":3006},"..\u002F..\u002Fservices\u002Fbroker",[1281,3008,3009,3014,3016,3022],{},[1299,3010,3011],{},[944,3012,3013],{},"Sealing provider id — never",[1299,3015,1359],{},[1299,3017,3018,3019,3021],{},"a provider's ",[949,3020,1992],{}," string is frozen once shipped; every sealed artefact names it forever",[1299,3023,3024],{},[983,3025,2052],{"href":2051},[989,3027,3029],{"id":3028},"invariants","Invariants",[941,3031,3032],{},"These are the bright lines, ordered from the outermost boundary inward. Any change to one of them is a security review.",[1275,3034,3035,3045],{},[1278,3036,3037],{},[1281,3038,3039,3042],{},[1284,3040,3041],{},"Invariant",[1284,3043,3044],{},"Enforcement",[1294,3046,3047,3064,3091,3118,3137,3147,3160],{},[1281,3048,3049,3054],{},[1299,3050,3051],{},[944,3052,3053],{},"Stores see only ciphertext",[1299,3055,3056,3057,1730,3060,3063],{},"Encryption happens in ",[949,3058,3059],{},"Collection.put",[963,3061,3062],{},"before"," the adapter call. No code path puts plaintext into a store.",[1281,3065,3066,3071],{},[1299,3067,3068],{},[944,3069,3070],{},"Authenticated decryption fails closed",[1299,3072,3073,3074,3076,3077,3082,3083,3086,3087,3090],{},"An envelope that does not authenticate throws ",[949,3075,1743],{},"; no partial-decryption fallback. ",[944,3078,3079,3081],{},[949,3080,1743],{}," is not by itself proof of an attack"," — read ",[949,3084,3085],{},"err.reason",", which distinguishes a genuine tamper from a record written before the ",[949,3088,3089],{},"0.6.0-pre.18"," format change.",[1281,3092,3093,3098],{},[1299,3094,3095],{},[944,3096,3097],{},"Per-record CEK is stable + DEK-scoped",[1299,3099,3100,3101,3103,3104,2254,3107,3110,3111,3114,3115,3117],{},"Under ",[949,3102,2197],{},", a record's CEK is reused across all its versions\u002Fhistory and is only ever AES-KW-wrapped under the collection\u002Ftier DEK (",[949,3105,3106],{},"wrapCek",[949,3108,3109],{},"unwrapCek"," in ",[949,3112,3113],{},"capsule\u002Fenclave-aes\u002Fcrypto.ts","). ",[949,3116,1225],{}," slots are never CEK-keyed.",[1281,3119,3120,3125],{},[1299,3121,3122],{},[944,3123,3124],{},"AES-256-GCM with random 12-byte IV per op",[1299,3126,3127,3129,3130,3133,3134,3136],{},[949,3128,3113],{}," generates IVs via ",[949,3131,3132],{},"crypto.getRandomValues(new Uint8Array(12))",". Never deterministic (except opt-in ",[949,3135,1225],{}," slots, whose equality leak is acknowledged per collection).",[1281,3138,3139,3144],{},[1299,3140,3141],{},[944,3142,3143],{},"AES-KW for DEK wrapping",[1299,3145,3146],{},"Standard RFC 3394. No custom KDF.",[1281,3148,3149,3154],{},[1299,3150,3151],{},[944,3152,3153],{},"KEK never on disk",[1299,3155,3156,3157,3159],{},"Only ",[949,3158,1561],{}," records persist (which carry wrapped DEKs, not the KEK).",[1281,3161,3162,3167],{},[1299,3163,3164],{},[944,3165,3166],{},"PBKDF2-SHA256 600,000 iterations",[1299,3168,3169,3172],{},[949,3170,3171],{},"deriveKey()"," constant. Lowering this is a breaking security change.",[989,3174,3176],{"id":3175},"plaintext-modes","Plaintext modes",[941,3178,3179],{},"Two dev-only escape hatches switch the enclave off. Both are explicit, loud, and never for production or client data.",[1032,3181,3183,3184,2319],{"id":3182},"plaintext-mode-encrypt-false","Plaintext mode (",[949,3185,3186],{},"encrypt: false",[941,3188,3189,3192,3193,3195],{},[949,3190,3191],{},"createNoydb({ encrypt: false })"," skips the crypto path entirely. Records are stored as raw JSON in ",[949,3194,1597],{},". Use only for testing \u002F debugging — no privacy guarantees.",[1032,3197,3199,3200,2319],{"id":3198},"debug-plaintext-layout-debugplaintext","Debug-plaintext layout (",[949,3201,2738],{},[941,3203,3204,3205,3208,3209,1730,3211,1730,3213,1795],{},"Zero-knowledge encryption is the default. During ",[944,3206,3207],{},"local development",", though, you sometimes want to point your store's native tools straight at the data. Open the vault with ",[949,3210,3186],{},[944,3212,1739],{},[949,3214,3215],{},"debugPlaintext: true",[1765,3217,3221],{"className":3218,"code":3219,"language":3220,"meta":1769,"style":1769},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createNoydb } from '@noy-db\u002Fhub'\nimport { toFile } from '@noy-db\u002Fto-file'\n\nconst db = await createNoydb({\n  store: toFile({ dir: '.\u002Fdata' }),\n  user: 'dev',\n  encrypt: false,\n  debugPlaintext: true,\n})\n","ts",[949,3222,3223,3250,3270,3276,3298,3332,3348,3361,3374],{"__ignoreMap":1769},[1542,3224,3225,3229,3232,3236,3239,3242,3245,3247],{"class":1774,"line":1775},[1542,3226,3228],{"class":3227},"s7zQu","import",[1542,3230,3231],{"class":1778}," {",[1542,3233,3235],{"class":3234},"sTEyZ"," createNoydb",[1542,3237,3238],{"class":1778}," }",[1542,3240,3241],{"class":3227}," from",[1542,3243,3244],{"class":1778}," '",[1542,3246,960],{"class":1835},[1542,3248,3249],{"class":1778},"'\n",[1542,3251,3252,3254,3256,3259,3261,3263,3265,3268],{"class":1774,"line":1782},[1542,3253,3228],{"class":3227},[1542,3255,3231],{"class":1778},[1542,3257,3258],{"class":3234}," toFile",[1542,3260,3238],{"class":1778},[1542,3262,3241],{"class":3227},[1542,3264,3244],{"class":1778},[1542,3266,3267],{"class":1835},"@noy-db\u002Fto-file",[1542,3269,3249],{"class":1778},[1542,3271,3272],{"class":1774,"line":1805},[1542,3273,3275],{"emptyLinePlaceholder":3274},true,"\n",[1542,3277,3278,3281,3284,3287,3290,3293,3296],{"class":1774,"line":1821},[1542,3279,3280],{"class":1788},"const",[1542,3282,3283],{"class":3234}," db ",[1542,3285,3286],{"class":1778},"=",[1542,3288,3289],{"class":3227}," await",[1542,3291,3235],{"class":3292},"s2Zo4",[1542,3294,3295],{"class":3234},"(",[1542,3297,1779],{"class":1778},[1542,3299,3300,3304,3306,3308,3310,3313,3316,3318,3320,3323,3326,3328,3330],{"class":1774,"line":1843},[1542,3301,3303],{"class":3302},"swJcz","  store",[1542,3305,1795],{"class":1778},[1542,3307,3258],{"class":3292},[1542,3309,3295],{"class":3234},[1542,3311,3312],{"class":1778},"{",[1542,3314,3315],{"class":3302}," dir",[1542,3317,1795],{"class":1778},[1542,3319,3244],{"class":1778},[1542,3321,3322],{"class":1835},".\u002Fdata",[1542,3324,3325],{"class":1778},"'",[1542,3327,3238],{"class":1778},[1542,3329,2319],{"class":3234},[1542,3331,1802],{"class":1778},[1542,3333,3334,3337,3339,3341,3344,3346],{"class":1774,"line":1863},[1542,3335,3336],{"class":3302},"  user",[1542,3338,1795],{"class":1778},[1542,3340,3244],{"class":1778},[1542,3342,3343],{"class":1835},"dev",[1542,3345,3325],{"class":1778},[1542,3347,1802],{"class":1778},[1542,3349,3350,3353,3355,3359],{"class":1774,"line":1882},[1542,3351,3352],{"class":3302},"  encrypt",[1542,3354,1795],{"class":1778},[1542,3356,3358],{"class":3357},"sfNiH"," false",[1542,3360,1802],{"class":1778},[1542,3362,3364,3367,3369,3372],{"class":1774,"line":3363},8,[1542,3365,3366],{"class":3302},"  debugPlaintext",[1542,3368,1795],{"class":1778},[1542,3370,3371],{"class":3357}," true",[1542,3373,1802],{"class":1778},[1542,3375,3377,3380],{"class":1774,"line":3376},9,[1542,3378,3379],{"class":1778},"}",[1542,3381,3382],{"class":3234},")\n",[941,3384,3385,3386,3389],{},"This changes the on-store ",[963,3387,3388],{},"layout"," so it's directly legible:",[1195,3391,3392,3416],{},[1198,3393,3394,3397,3398,3401,3402,3404,3405,3407,3408,3411,3412,3415],{},[944,3395,3396],{},"Records"," are written with their fields inlined beside the envelope metadata (",[949,3399,3400],{},"_debug: 1",", empty ",[949,3403,1597],{},") instead of stuffed into ",[949,3406,1597],{}," as a JSON string — so ",[949,3409,3410],{},"jq '.total'"," over a ",[949,3413,3414],{},"to-file"," object resolves directly.",[1198,3417,3418,3421,3422,3424,3425,2053],{},[944,3419,3420],{},"Blobs"," are written as a single un-gzipped object — the chunk's base64 ",[949,3423,1597],{}," decodes straight to the original bytes (",[949,3426,3427],{},"base64 -d",[941,3429,3430,3431,3434,3435,3438],{},"To unwrap an envelope programmatically (the core of a ",[949,3432,3433],{},"noydb cat"," script), use ",[949,3436,3437],{},"readPlaintextRecord(envelope)"," — it handles both the inlined and the classic plaintext layouts, and throws on an encrypted envelope:",[1765,3440,3442],{"className":3218,"code":3441,"language":3220,"meta":1769,"style":1769},"import { readFileSync } from 'node:fs'\nimport { readPlaintextRecord } from '@noy-db\u002Fhub\u002Fdebug'\n\nconst env = JSON.parse(readFileSync('data\u002Facme\u002Finvoices\u002Finv-1.json', 'utf8'))\nreadPlaintextRecord(env)\n\u002F\u002F → { id: 'inv-1', total: '120.00', … }\n",[949,3443,3444,3464,3484,3488,3531,3539],{"__ignoreMap":1769},[1542,3445,3446,3448,3450,3453,3455,3457,3459,3462],{"class":1774,"line":1775},[1542,3447,3228],{"class":3227},[1542,3449,3231],{"class":1778},[1542,3451,3452],{"class":3234}," readFileSync",[1542,3454,3238],{"class":1778},[1542,3456,3241],{"class":3227},[1542,3458,3244],{"class":1778},[1542,3460,3461],{"class":1835},"node:fs",[1542,3463,3249],{"class":1778},[1542,3465,3466,3468,3470,3473,3475,3477,3479,3482],{"class":1774,"line":1782},[1542,3467,3228],{"class":3227},[1542,3469,3231],{"class":1778},[1542,3471,3472],{"class":3234}," readPlaintextRecord",[1542,3474,3238],{"class":1778},[1542,3476,3241],{"class":3227},[1542,3478,3244],{"class":1778},[1542,3480,3481],{"class":1835},"@noy-db\u002Fhub\u002Fdebug",[1542,3483,3249],{"class":1778},[1542,3485,3486],{"class":1774,"line":1805},[1542,3487,3275],{"emptyLinePlaceholder":3274},[1542,3489,3490,3492,3495,3497,3500,3502,3505,3507,3510,3512,3514,3517,3519,3521,3523,3526,3528],{"class":1774,"line":1821},[1542,3491,3280],{"class":1788},[1542,3493,3494],{"class":3234}," env ",[1542,3496,3286],{"class":1778},[1542,3498,3499],{"class":3234}," JSON",[1542,3501,1244],{"class":1778},[1542,3503,3504],{"class":3292},"parse",[1542,3506,3295],{"class":3234},[1542,3508,3509],{"class":3292},"readFileSync",[1542,3511,3295],{"class":3234},[1542,3513,3325],{"class":1778},[1542,3515,3516],{"class":1835},"data\u002Facme\u002Finvoices\u002Finv-1.json",[1542,3518,3325],{"class":1778},[1542,3520,2093],{"class":1778},[1542,3522,3244],{"class":1778},[1542,3524,3525],{"class":1835},"utf8",[1542,3527,3325],{"class":1778},[1542,3529,3530],{"class":3234},"))\n",[1542,3532,3533,3536],{"class":1774,"line":1843},[1542,3534,3535],{"class":3292},"readPlaintextRecord",[1542,3537,3538],{"class":3234},"(env)\n",[1542,3540,3541],{"class":1774,"line":1863},[1542,3542,3544],{"class":3543},"sHwdD","\u002F\u002F → { id: 'inv-1', total: '120.00', … }\n",[941,3546,3547],{},"Guardrails:",[1195,3549,3550,3559,3565],{},[1198,3551,3552,3554,3555,3558],{},[949,3553,3215],{}," combined with encryption throws ",[949,3556,3557],{},"DebugPlaintextError"," at construction — it is an unencrypted-only inspection mode.",[1198,3560,3561,3562,1244],{},"Opening a vault in this mode prints a loud ",[949,3563,3564],{},"console.warn",[1198,3566,3567,3568,3571,3572,3574],{},"A CI architecture check (",[949,3569,3570],{},"no-debug-plaintext-in-source",") forbids hardcoding ",[949,3573,3215],{}," in shipped library source.",[941,3576,3577,3580],{},[944,3578,3579],{},"Never use this for production or client data."," It stores everything in cleartext and is not crypto-shreddable.",[989,3582,3584],{"id":3583},"encryption-elsewhere-in-the-family","Encryption elsewhere in the family",[941,3586,3587],{},"The record path above is not the only place the family does real cryptography. The same zero-dependency Web Crypto discipline covers every one of these:",[1195,3589,3590,3609,3623,3636,3694,3704,3713,3731,3744],{},[1198,3591,3592,3595,3596,3598,3599,3602,3603,3606,3607,1244],{},[944,3593,3594],{},"Blobs."," Binary attachments are chunked and each chunk encrypted with AES-256-GCM under a dedicated ",[949,3597,2784],{}," collection DEK, with the chunk's parent blob and position bound in as additional authenticated data (",[949,3600,3601],{},"{eTag}:{chunkIndex}:{chunkCount}",") — so chunks cannot be reordered, substituted, or truncated undetected. The dedup address is ",[949,3604,3605],{},"eTag = HMAC-SHA256(blob DEK, plaintext)",", keyed so an observer with store access cannot pre-compute eTags for known files. See ",[983,3608,621],{"href":2788},[1198,3610,3611,1730,3614,3618,3619,3622],{},[944,3612,3613],{},"Magic links.",[983,3615,3617],{"href":3616},"..\u002F..\u002Ffamilies\u002Fon\u002Fmagic-link","on-magic-link"," grants read-only access from a single-use URL that carries only an opaque token — no key material. Server and client each derive the ",[963,3620,3621],{},"same viewer KEK"," via HKDF-SHA256 from a server-held secret salted with the token's hash; that KEK unlocks a purpose-built viewer keyring directly (bypassing PBKDF2), so it covers only the DEKs granted to the viewer.",[1198,3624,3625,3628,3629,3631,3632,3635],{},[944,3626,3627],{},"Credential broker."," The ",[983,3630,625],{"href":3006}," authenticates a client to a remote credential-minting host without the host ever holding a secret: a 32-byte seed is stored encrypted in the reserved ",[949,3633,3634],{},"_broker"," collection under its own DEK, an HKDF-SHA256-derived proof key HMAC-SHA256-signs the host's challenge, and the host verifies the signature (constant-time) against a short-TTL challenge.",[1198,3637,3638,3641,3642,3648,3649,3653,3654,3657,3658,3662,3663,3667,3668,3670,3671,3673,3674,3678,3679,3683,3684,3688,3689,3693],{},[944,3639,3640],{},"Unlock factors."," Each ",[983,3643,3645,3647],{"href":3644},"..\u002F..\u002Fservices\u002Fauth-landscape",[949,3646,1014],{}," method"," wraps or proves with real primitives of its own: ",[983,3650,3652],{"href":3651},"..\u002F..\u002Ffamilies\u002Fon\u002Fwebauthn","on-webauthn"," derives an AES-GCM wrapping key via HKDF-SHA256 from the passkey's PRF output (falling back to the credential's ",[949,3655,3656],{},"rawId"," on authenticators without PRF); ",[983,3659,3661],{"href":3660},"..\u002F..\u002Ffamilies\u002Fon\u002Fpassword","on-password"," wraps the DEK set under PBKDF2-SHA256 (600,000 iterations); ",[983,3664,3666],{"href":3665},"..\u002F..\u002Ffamilies\u002Fon\u002Fpin","on-pin"," quick-unlock wraps ",[963,3669,973],{}," the session's cached DEK map (never the KEK) under a PIN-derived AES-GCM key (PBKDF2, 100,000 iterations, attempt-bounded + TTL — see ",[983,3672,844],{"href":2028},"); ",[983,3675,3677],{"href":3676},"..\u002F..\u002Ffamilies\u002Fon\u002Foidc","on-oidc"," XOR-splits the key payload into a device half (HKDF-derived from a per-device random secret that never leaves the device) and a server half encrypted under a key derived from the ID token; ",[983,3680,3682],{"href":3681},"..\u002F..\u002Ffamilies\u002Fon\u002Ftotp","on-totp"," is RFC 6238 HMAC; ",[983,3685,3687],{"href":3686},"..\u002F..\u002Ffamilies\u002Fon\u002Femail-otp","on-email-otp"," stores only salted SHA-256 digests of codes; ",[983,3690,3692],{"href":3691},"..\u002F..\u002Ffamilies\u002Fon\u002Fthreat","on-threat"," detects duress secrets via a PBKDF2 hash compared in constant time.",[1198,3695,3696,1730,3699,3703],{},[944,3697,3698],{},"Shamir secret sharing.",[983,3700,3702],{"href":3701},"..\u002F..\u002Ffamilies\u002Fon\u002Fshamir","on-shamir"," splits the KEK into k-of-n shares with genuine Shamir secret sharing over GF(2⁸) — any k shares reconstruct it by Lagrange interpolation; fewer than k leak zero bits.",[1198,3705,3706,3628,3709,3712],{},[944,3707,3708],{},"Attestations.",[983,3710,609],{"href":3711},"..\u002F..\u002Fservices\u002Fattestation"," package signs selective-disclosure attestations with Ed25519 over a canonical core of salted SHA-256 field hashes — a verifier checks that a record contained given field values without seeing the others.",[1198,3714,3715,1730,3718,3720,3721,3723,3724,3726,3727,3730],{},[944,3716,3717],{},"Classified blind index.",[983,3719,633],{"href":2393}," fields marked ",[949,3722,1232],{}," get an HMAC-SHA256 equality tag under an HKDF-derived index key — searchable without decryption. (The related deterministic ",[949,3725,1225],{}," slots are covered under ",[983,3728,3729],{"href":1685},"Per-record keys"," above.)",[1198,3732,3733,3736,3737,3740,3741,3743],{},[944,3734,3735],{},"Integrity chains."," The audit ",[983,3738,776],{"href":3739},"..\u002F..\u002Fservices\u002Fperiods"," ledger is a tamper-evident SHA-256 hash chain — integrity, not secrecy — and the ",[983,3742,685],{"href":2306}," subject index pseudonymizes subject ids as HMAC-SHA256 under a dedicated index DEK.",[1198,3745,3746,1730,3749,3753,3754,3756],{},[944,3747,3748],{},"Encrypted ZIP export.",[983,3750,3752],{"href":3751},"..\u002F..\u002Ffamilies\u002Fas\u002Fzip","as-zip"," can optionally encrypt the archive it produces in the standard WinZip-AES-256 format under a user-supplied password — protection for the exported ",[963,3755,383],{},", orthogonal to the vault's own keys.",[941,3758,1435,3759,3761,3762,1049,3766,3770,3771,3774],{},[949,3760,1022],{}," session-share transports (",[983,3763,3765],{"href":3764},"..\u002F..\u002Ffamilies\u002Fby\u002Fpeer","by-peer",[983,3767,3769],{"href":3768},"..\u002F..\u002Ffamilies\u002Fby\u002Ftabs","by-tabs",") deliberately have ",[944,3772,3773],{},"no crypto of their own"," — they carry the already-encrypted envelopes and rely on the transport layer (DTLS, same-origin) for the wire, exactly as the enclave boundary intends.",[989,3776,3778],{"id":3777},"see-also","See also",[1195,3780,3781,3788,3793,3798,3803,3809],{},[1198,3782,3783,3787],{},[983,3784,3786],{"href":3785},"..\u002F05-stores","Core 05 — Stores"," — the contract that holds these invariants in place",[1198,3789,3790,3792],{},[983,3791,69],{"href":1141}," — the secret, the single-user keyring, and its primitives",[1198,3794,3795,3797],{},[983,3796,1916],{"href":1915}," — how wrapped DEKs are granted and revoked",[1198,3799,3800,3802],{},[983,3801,1181],{"href":1180}," — the architecture of the crypto interior",[1198,3804,3805,3808],{},[983,3806,25],{"href":3807},"..\u002F..\u002Farchitecture\u002Fkernel\u002Fforking-the-enclave"," — the frozen contract a replacement enclave must satisfy",[1198,3810,3811,3815],{},[983,3812,3814],{"href":3813},"\u002Ffaq\u002Fthreat-model#reporting-a-vulnerability","Reporting a vulnerability"," — how to disclose privately",[3817,3818,3819],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":1769,"searchDepth":1805,"depth":1805,"links":3821},[3822,3828,3829,3834,3835,3836,3840,3841,3842,3843,3849,3850],{"id":991,"depth":1782,"text":992,"children":3823},[3824,3826],{"id":1034,"depth":1805,"text":3825},"at-* — delegated decryption",{"id":1118,"depth":1805,"text":3827},"as-* — the designed output channel",{"id":1247,"depth":1782,"text":1248},{"id":1402,"depth":1782,"text":1403,"children":3830},[3831,3832,3833],{"id":1406,"depth":1805,"text":1407},{"id":1499,"depth":1805,"text":1500},{"id":1469,"depth":1805,"text":1591},{"id":1898,"depth":1782,"text":1899},{"id":1972,"depth":1782,"text":1096},{"id":2056,"depth":1782,"text":1686,"children":3837},[3838],{"id":2314,"depth":1805,"text":3839},"Sealed fields (_sealed)",{"id":2397,"depth":1782,"text":2398},{"id":2791,"depth":1782,"text":2792},{"id":3028,"depth":1782,"text":3029},{"id":3175,"depth":1782,"text":3176,"children":3844},[3845,3847],{"id":3182,"depth":1805,"text":3846},"Plaintext mode (encrypt: false)",{"id":3198,"depth":1805,"text":3848},"Debug-plaintext layout (debugPlaintext)",{"id":3583,"depth":1782,"text":3584},{"id":3777,"depth":1782,"text":3778},null,"The enclave — the trusted region inside the hub where keys and plaintext exist at all: the KEK\u002FDEK\u002FCEK hierarchy, the envelope, sealing, and invariants.","md",{},{"title":21,"description":3852},"stable","essential","cGOSC0aFIA2ifJ2spObMhzGMVr1QdN1ywcEw8Usf0Dc",1791896579499]