selfstore 1.8.2 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.d.ts +8 -4
- package/dist/advanced.js +14 -13
- package/dist/advanced.js.map +1 -1
- package/dist/backups.d.ts +31 -179
- package/dist/backups.js +40 -3
- package/dist/backups.js.map +1 -1
- package/dist/{cache-lock-RCN3JJ4Q.js → cache-lock-KWJUORTS.js} +3 -4
- package/dist/cache-lock-KWJUORTS.js.map +1 -0
- package/dist/{chunk-HK4VPO65.js → chunk-3OBJOMQ2.js} +28 -4
- package/dist/chunk-3OBJOMQ2.js.map +1 -0
- package/dist/{chunk-HDR75TQ7.js → chunk-DCEXWSM6.js} +3 -3
- package/dist/{chunk-HDR75TQ7.js.map → chunk-DCEXWSM6.js.map} +1 -1
- package/dist/{chunk-7N2YR3QW.js → chunk-ELDSPUTS.js} +7 -8
- package/dist/chunk-ELDSPUTS.js.map +1 -0
- package/dist/chunk-J5MFXJU6.js +310 -0
- package/dist/chunk-J5MFXJU6.js.map +1 -0
- package/dist/{chunk-BNDFMU3J.js → chunk-MGDXR3RB.js} +5 -6
- package/dist/chunk-MGDXR3RB.js.map +1 -0
- package/dist/{chunk-453KRCMM.js → chunk-O3Y6FORN.js} +3 -4
- package/dist/chunk-O3Y6FORN.js.map +1 -0
- package/dist/{chunk-JMJZIZKY.js → chunk-PNX7AJYO.js} +13 -12
- package/dist/chunk-PNX7AJYO.js.map +1 -0
- package/dist/{chunk-5NS7YQNP.js → chunk-TKWU52LK.js} +26 -312
- package/dist/chunk-TKWU52LK.js.map +1 -0
- package/dist/{chunk-U5F4GI7C.js → chunk-W22V5CRM.js} +3 -3
- package/dist/{chunk-U5F4GI7C.js.map → chunk-W22V5CRM.js.map} +1 -1
- package/dist/{drive-l_4-m1eT.d.ts → drive-CTYvGg_7.d.ts} +23 -110
- package/dist/{flows-C_uookek.d.ts → flows-1EntUZ91.d.ts} +2 -1
- package/dist/flows.d.ts +3 -2
- package/dist/flows.js +16 -16
- package/dist/flows.js.map +1 -1
- package/dist/groups.js +3 -4
- package/dist/groups.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/{local-bfv4Ld7s.d.ts → local-C52j3DeH.d.ts} +1 -1
- package/dist/local-DPS35F5C.js +6 -0
- package/dist/{local-2YREU4Q2.js.map → local-DPS35F5C.js.map} +1 -1
- package/dist/manager-DZ1c_aSS.d.ts +181 -0
- package/dist/s3-DvsnA-FK.d.ts +112 -0
- package/dist/widgets.d.ts +4 -3
- package/dist/widgets.js +7 -7
- package/package.json +1 -1
- package/dist/cache-lock-RCN3JJ4Q.js.map +0 -1
- package/dist/chunk-453KRCMM.js.map +0 -1
- package/dist/chunk-5NS7YQNP.js.map +0 -1
- package/dist/chunk-7N2YR3QW.js.map +0 -1
- package/dist/chunk-BNDFMU3J.js.map +0 -1
- package/dist/chunk-CPN2KUD5.js +0 -29
- package/dist/chunk-CPN2KUD5.js.map +0 -1
- package/dist/chunk-HK4VPO65.js.map +0 -1
- package/dist/chunk-JMJZIZKY.js.map +0 -1
- package/dist/local-2YREU4Q2.js +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/selfstore/group.ts"],"names":[],"mappings":";;;AAiBO,IAAM,YAAA,GAAe;AAI5B,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,eAAA,GAAkB,EAAA;AAGjB,IAAM,cAAA,GAAiB,GAAA;AAI9B,IAAM,UAAA,GAAa,wBAAA;AACnB,IAAM,eAAA,GAAkB,6BAAA;AACxB,IAAM,SAAA,GAAY,yBAAA;AAElB,IAAM,IAAA,GAAO,IAAI,WAAA,EAAY;AAmD7B,SAAS,IAAI,EAAA,EAAyC;AACrD,EAAA,OAAO,EAAA;AACR;AAEA,SAAS,UAAU,KAAA,EAAiC;AACnD,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAC,CAAA;AAClE,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACtB,IAAA,GAAA,CAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AACZ,IAAA,CAAA,IAAK,CAAA,CAAE,MAAA;AAAA,EACR;AACA,EAAA,OAAO,GAAA;AACR;AAEA,eAAe,OAAO,KAAA,EAAwC;AAC7D,EAAA,OAAO,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,SAAA,EAAW,GAAA,CAAI,KAAK,CAAC,CAAC,CAAA;AACxE;AAEA,IAAI,QAAA,GAAoC,IAAA;AAGjC,SAAS,oBAAA,GAAyC;AACxD,EAAA,QAAA,KAAA,CAAc,YAAY;AACzB,IAAA,IAAI;AACH,MAAA,MAAM,MAAA,CAAO,OAAO,WAAA,CAAY,SAAA,EAAW,OAAO,CAAC,MAAA,EAAQ,QAAQ,CAAC,CAAA;AACpE,MAAA,MAAM,OAAO,MAAA,CAAO,WAAA,CAAY,UAAU,KAAA,EAAO,CAAC,YAAY,CAAC,CAAA;AAC/D,MAAA,OAAO,IAAA;AAAA,IACR,CAAA,CAAA,MAAQ;AACP,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD,CAAA,GAAG;AACH,EAAA,OAAO,QAAA;AACR;AAEA,eAAe,aAAA,GAA+B;AAC7C,EAAA,IAAI,CAAE,MAAM,oBAAA,EAAqB,EAAI;AACpC,IAAA,MAAM,IAAI,SAAA;AAAA,MACT;AAAA,KAED;AAAA,EACD;AACD;AAEA,IAAM,gBAAgB,CAAC,GAAA,KACtB,MAAA,CAAO,MAAA,CAAO,UAAU,OAAA,EAAS,GAAA,CAAI,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,CAAC,MAAM,CAAC,CAAA;AAClF,IAAM,eAAe,CAAC,GAAA,KACrB,MAAA,CAAO,MAAA,CAAO,UAAU,KAAA,EAAO,GAAA,CAAI,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,CAAC,QAAQ,CAAC,CAAA;AAClF,IAAM,gBAAgB,CAAC,GAAA,KACtB,MAAA,CAAO,MAAA,CAAO,UAAU,OAAA,EAAS,GAAA,CAAI,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,QAAA,EAAU,KAAA,EAAO,CAAC,YAAY,CAAC,CAAA;AACvF,IAAM,YAAA,GAAe,CAAC,GAAA,KACrB,MAAA,CAAO,OAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,UAAA,CAAW,GAAG,CAAC,CAAA,EAAG,QAAA,EAAU,KAAA,EAAO,EAAE,CAAA;AAGzE,eAAsB,gBAAA,GAA2C;AAChE,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,MAAM,MAAO,MAAM,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,WAAW,IAAA,EAAM;AAAA,IAC7D,MAAA;AAAA,IACA;AAAA,GACA,CAAA;AACD,EAAA,MAAM,GAAA,GAAO,MAAM,MAAA,CAAO,MAAA,CAAO,YAAY,QAAA,EAAU,IAAA,EAAM,CAAC,YAAY,CAAC,CAAA;AAC3E,EAAA,MAAM,GAAA,GAAM,OAAO,CAAA,KAClB,QAAA,CAAS,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,CAAC,CAAC,CAAC,CAAA;AACjE,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAA,KACpB,QAAA,CAAS,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,OAAA,EAAS,CAAC,CAAC,CAAC,CAAA;AACnE,EAAA,OAAO;AAAA,IACN,MAAA,EAAQ,MAAM,GAAA,CAAI,GAAA,CAAI,SAAS,CAAA;AAAA,IAC/B,OAAA,EAAS,MAAM,KAAA,CAAM,GAAA,CAAI,UAAU,CAAA;AAAA,IACnC,MAAA,EAAQ,MAAM,GAAA,CAAI,GAAA,CAAI,SAAS,CAAA;AAAA,IAC/B,OAAA,EAAS,MAAM,KAAA,CAAM,GAAA,CAAI,UAAU;AAAA,GACpC;AACD;AAGO,SAAS,eAAe,EAAA,EAAiD;AAC/E,EAAA,OAAO,EAAE,GAAA,EAAK,EAAA,CAAG,MAAA,EAAQ,GAAA,EAAK,GAAG,MAAA,EAAO;AACzC;AAGO,SAAS,UAAA,GAAqB;AACpC,EAAA,OAAO,SAAS,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAC,CAAA;AAC3D;AAGA,eAAsB,MAAM,SAAA,EAAoC;AAC/D,EAAA,OAAO,QAAA,CAAA,CAAU,MAAM,MAAA,CAAO,UAAA,CAAW,SAAS,CAAC,CAAA,EAAG,QAAA,CAAS,CAAA,EAAG,CAAC,CAAC,CAAA;AACrE;AAIA,eAAe,aAAA,CACd,IAAA,EACA,QAAA,EACA,SAAA,EACA,iBACA,KAAA,EACqB;AACrB,EAAA,MAAM,SAAS,IAAI,UAAA;AAAA,IAClB,MAAM,MAAA,CAAO,MAAA,CAAO,UAAA,CAAW,EAAE,IAAA,EAAM,QAAA,EAAU,MAAA,EAAQ,QAAA,EAAS,EAAG,IAAA,EAAM,GAAG;AAAA,GAC/E;AACA,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,MAAM,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,CAAC,YAAY,CAAC,CAAA;AAC3F,EAAA,MAAM,OAAO,IAAI,UAAA;AAAA,IAChB,MAAM,OAAO,MAAA,CAAO,UAAA;AAAA,MACnB;AAAA,QACC,IAAA,EAAM,MAAA;AAAA,QACN,IAAA,EAAM,SAAA;AAAA,QACN,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,SAAA,EAAW,eAAe,CAAC,CAAA;AAAA,QAC5C,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,SAAS,CAAC;AAAA,OACjC;AAAA,MACA,GAAA;AAAA,MACA;AAAA;AACD,GACD;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,IAAI,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,CAAC,KAAK,CAAC,CAAA;AAC3E;AAGA,eAAsB,WAAA,CACrB,SACA,mBAAA,EAC6B;AAC7B,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,IAAI,OAAA,CAAQ,WAAW,cAAA,EAAgB;AACtC,IAAA,MAAM,IAAI,SAAA,CAAU,CAAA,8BAAA,EAAiC,cAAc,CAAA,iBAAA,CAAmB,CAAA;AAAA,EACvF;AACA,EAAA,IAAI,mBAAA,CAAoB,SAAS,cAAA,EAAgB;AAChD,IAAA,MAAM,IAAI,SAAA,CAAU,CAAA,sCAAA,EAAyC,cAAc,CAAA,EAAA,CAAI,CAAA;AAAA,EAChF;AACA,EAAA,MAAM,MAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,KAAK,mBAAA,EAAqB;AACpC,IAAA,MAAM,GAAA,GAAO,MAAM,MAAA,CAAO,MAAA,CAAO,YAAY,QAAA,EAAU,KAAA,EAAO,CAAC,YAAY,CAAC,CAAA;AAC5E,IAAA,MAAM,SAAA,GAAY,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,OAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,SAAS,CAAC,CAAA;AACpF,IAAA,MAAM,MAAM,MAAM,aAAA;AAAA,MACjB,GAAA,CAAI,UAAA;AAAA,MACJ,MAAM,aAAa,CAAC,CAAA;AAAA,MACpB,SAAA;AAAA,MACA,WAAW,CAAC,CAAA;AAAA,MACZ;AAAA,KACD;AACA,IAAA,MAAM,KAAK,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA;AACpD,IAAA,MAAM,OAAO,IAAI,UAAA;AAAA,MAChB,MAAM,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,EAAG,EAAG,GAAA,EAAK,GAAA,CAAI,OAAO,CAAC;AAAA,KACvE;AACA,IAAA,GAAA,CAAI,IAAA,CAAK;AAAA,MACR,GAAA,EAAK,MAAM,KAAA,CAAM,CAAC,CAAA;AAAA,MAClB,GAAA,EAAK,SAAS,SAAS,CAAA;AAAA,MACvB,EAAA,EAAI,SAAS,EAAE,CAAA;AAAA,MACf,IAAA,EAAM,SAAS,IAAI;AAAA,KACnB,CAAA;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACR;AAOA,eAAsB,WAAA,CACrB,SACA,QAAA,EACsB;AACtB,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,IAAI,OAAA,CAAQ,SAAS,cAAA,EAAgB;AACpC,IAAA,MAAM,IAAI,cAAA,CAAe,YAAA,EAAc,CAAA,gCAAA,EAAmC,cAAc,CAAA,EAAA,CAAI,CAAA;AAAA,EAC7F;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACzC,EAAA,MAAM,OAAO,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,KAAK,CAAA;AAElD,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,IAAA,GAAO,OAAA;AAC5C,EAAA,MAAM,IAAA,GAAO,MAAM,aAAA,CAAc,QAAA,CAAS,OAAO,CAAA;AACjD,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,QAAA,CAAS,MAAM,CAAA;AAC3C,EAAA,KAAA,MAAW,KAAK,UAAA,EAAY;AAC3B,IAAA,IAAI;AACH,MAAA,MAAM,MAAM,MAAM,aAAA;AAAA,QACjB,IAAA;AAAA,QACA,MAAM,YAAA,CAAa,CAAA,CAAE,GAAG,CAAA;AAAA,QACxB,UAAA,CAAW,EAAE,GAAG,CAAA;AAAA,QAChB,QAAA;AAAA,QACA;AAAA,OACD;AACA,MAAA,MAAM,KAAK,IAAI,UAAA;AAAA,QACd,MAAM,OAAO,MAAA,CAAO,OAAA;AAAA,UACnB,EAAE,MAAM,SAAA,EAAW,EAAA,EAAI,IAAI,UAAA,CAAW,CAAA,CAAE,EAAE,CAAC,CAAA,EAAE;AAAA,UAC7C,GAAA;AAAA,UACA,GAAA,CAAI,UAAA,CAAW,CAAA,CAAE,IAAI,CAAC;AAAA;AACvB,OACD;AAEA,MAAA,IAAI,EAAA,CAAG,MAAA,KAAW,cAAA,EAAgB,OAAO,EAAA;AAAA,IAC1C,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACD;AACA,EAAA,MAAM,IAAI,cAAA;AAAA,IACT,iBAAA;AAAA,IACA;AAAA,GACD;AACD;AAGA,eAAsB,UAAA,CACrB,OACA,SAAA,EACkD;AAClD,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,KAAK,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,CAAC,SAAS,CAAC,CAAA;AAC1F,EAAA,MAAM,KAAK,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA;AACpD,EAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,EAAG,EAAG,GAAA,EAAK,GAAA,CAAI,SAAS,CAAC,CAAA;AACnF,EAAA,OAAO,EAAE,IAAI,QAAA,CAAS,EAAE,GAAG,UAAA,EAAY,IAAI,UAAA,CAAW,EAAE,CAAA,EAAE;AAC3D;AAGA,eAAsB,UAAA,CACrB,KAAA,EACA,KAAA,EACA,UAAA,EACsB;AACtB,EAAA,IAAI;AACH,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,GAAA,CAAI,KAAK,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,CAAC,SAAS,CAAC,CAAA;AAC1F,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,MAAA,CAAO,OAAA;AAAA,MAC9B,EAAE,MAAM,SAAA,EAAW,EAAA,EAAI,IAAI,UAAA,CAAW,KAAK,CAAC,CAAA,EAAE;AAAA,MAC9C,GAAA;AAAA,MACA,IAAI,UAAU;AAAA,KACf;AACA,IAAA,OAAO,IAAI,WAAW,EAAE,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACP,IAAA,MAAM,IAAI,cAAA,CAAe,gBAAA,EAAkB,2CAA2C,CAAA;AAAA,EACvF;AACD;AAOA,eAAsB,OAAA,CACrB,SAAA,EACA,OAAA,EACA,UAAA,EACsB;AACtB,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,EAAG,MAAM,MAAA,CAAO,SAAS,CAAA,EAAG,MAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAC1F,EAAA,MAAM,GAAA,GAAM,MAAM,aAAA,CAAc,UAAU,CAAA;AAC1C,EAAA,OAAO,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,GAAA,EAAK,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AACzE;AAGA,eAAsB,SAAA,CACrB,SAAA,EACA,OAAA,EACA,GAAA,EACA,SAAA,EACmB;AACnB,EAAA,IAAI;AACH,IAAA,MAAM,aAAA,EAAc;AACpB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,EAAG,MAAM,MAAA,CAAO,SAAS,CAAA,EAAG,MAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAC1F,IAAA,OAAO,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,MAAM,YAAA,CAAa,SAAS,CAAA,EAAG,GAAA,CAAI,GAAG,CAAA,EAAG,GAAA,CAAI,GAAG,CAAC,CAAA;AAAA,EAC/F,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,KAAA;AAAA,EACR;AACD;AAGA,eAAsB,YAAA,CACrB,UACA,eAAA,EAC0B;AAC1B,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,MAAM,UAAU,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,MAAM,aAAA,CAAc,eAAe,CAAA;AAC/C,EAAA,MAAM,MAAM,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,eAAe,GAAG,OAAO,CAAA;AACxD,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,GAAA,EAAK,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AAC7E,EAAA,OAAO,EAAE,iBAAA,EAAmB,CAAA,EAAG,OAAA,EAAS,QAAA,CAAS,OAAO,CAAA,EAAG,GAAA,EAAK,QAAA,CAAS,GAAG,CAAA,EAAE;AAC/E;AAOA,eAAsB,YAAA,CACrB,MAAA,EACA,cAAA,EACA,gBAAA,EACyB;AACzB,EAAA,MAAM,aAAA,EAAc;AACpB,EAAA,MAAM,MAAM,CAAC,GAAA,KAAgC,IAAI,cAAA,CAAe,qBAAqB,GAAG,CAAA;AACxF,EAAA,IAAI,CAAC,UAAU,MAAA,CAAO,iBAAA,KAAsB,KAAK,OAAO,MAAA,CAAO,YAAY,QAAA,EAAU;AACpF,IAAA,MAAM,IAAI,kCAAkC,CAAA;AAAA,EAC7C;AACA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,EAAA;AACJ,EAAA,IAAI;AACH,IAAA,OAAA,GAAU,UAAA,CAAW,OAAO,OAAO,CAAA;AACnC,IAAA,MAAM,MAAM,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,eAAe,GAAG,OAAO,CAAA;AACxD,IAAA,EAAA,GAAK,MAAM,OAAO,MAAA,CAAO,MAAA;AAAA,MACxB,SAAA;AAAA,MACA,MAAM,aAAa,cAAc,CAAA;AAAA,MACjC,GAAA,CAAI,UAAA,CAAW,MAAA,CAAO,GAAA,IAAO,EAAE,CAAC,CAAA;AAAA,MAChC,IAAI,GAAG;AAAA,KACR;AAAA,EACD,CAAA,CAAA,MAAQ;AACP,IAAA,MAAM,IAAI,uCAAuC,CAAA;AAAA,EAClD;AACA,EAAA,IAAI,CAAC,EAAA,EAAI,MAAM,GAAA,CAAI,sDAAsD,CAAA;AACzE,EAAA,MAAM,CAAA,GAAI,KAAK,KAAA,CAAM,IAAI,aAAY,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA;AAEtD,EAAA,MAAM,WAAA,GAAc,CAAC,GAAA,KAAyB;AAC7C,IAAA,IAAI;AACH,MAAA,OAAO,UAAA,CAAW,GAAG,CAAA,CAAE,MAAA,KAAW,eAAA;AAAA,IACnC,CAAA,CAAA,MAAQ;AACP,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD,CAAA;AACA,EAAA,MAAM,OAAA,GACL,CAAA,IACA,CAAA,CAAE,CAAA,KAAM,CAAA,IACR,OAAO,CAAA,CAAE,KAAA,KAAU,QAAA,IACnB,MAAA,CAAO,SAAA,CAAU,CAAA,CAAE,GAAG,CAAA,IACtB,CAAA,CAAE,GAAA,IAAO,CAAA,IACT,CAAA,CAAE,KAAA,KAAU,cAAA,IACZ,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,OAAO,CAAA,IACvB,CAAA,CAAE,OAAA,CAAQ,MAAA,IAAU,cAAA,IACpB,EAAE,OAAA,CAAQ,KAAA;AAAA,IACT,CAAC,GAAA,KACA,GAAA,IACA,OAAO,GAAA,CAAI,OAAO,QAAA,IAClB,GAAA,CAAI,EAAA,CAAG,MAAA,GAAS,KAChB,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA,IACnB,WAAA,CAAY,IAAI,GAAG;AAAA,GACrB;AACD,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,GAAA,CAAI,+CAA+C,CAAA;AAEvE,EAAA,IAAI,IAAI,GAAA,CAAI,CAAA,CAAE,OAAA,CAAQ,IAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,EAAE,CAAC,CAAA,CAAE,IAAA,KAAS,CAAA,CAAE,QAAQ,MAAA,EAAQ;AACtE,IAAA,MAAM,IAAI,oCAAoC,CAAA;AAAA,EAC/C;AAGA,EAAA,IAAI,gBAAA,KAAqB,MAAA,IAAa,CAAA,CAAE,KAAA,KAAU,gBAAA,EAAkB;AACnE,IAAA,MAAM,IAAI,kDAAkD,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,CAAA;AACR","file":"chunk-O3Y6FORN.js","sourcesContent":["// Passwordless groups: the public-key layer under peers (see PEERS.md).\n//\n// Each member holds an Ed25519 keypair to sign the copies they publish and an\n// X25519 keypair to receive data keys. A copy is encrypted once under a fresh\n// AES-256-GCM data key, enveloped per member (ephemeral ECDH + HKDF + GCM\n// wrap - the age recipient model). Membership is a manifest signed by a\n// single admin key; a copy is trusted only when its signature verifies and\n// its author is in the manifest.\n//\n// WebCrypto only, no polyfill: the supply-chain surface stays flat, and\n// evergreen browsers plus Node 20+ have everything needed.\n\nimport type { RecipientStanza } from './types';\nimport { toBase64, fromBase64 } from './base64';\nimport { SelfstoreError } from './errors';\n\n/** The `keying` header value for group-mode boxes (see SPEC.md section 12). */\nexport const GROUP_KEYING = 'x25519-hkdf-sha256';\n\n// Enforced on both seal and open, so a member cannot publish a copy under a\n// narrower key (16 bytes -> AES-128) and have readers accept it.\nconst DATA_KEY_BYTES = 32;\nconst CURVE_PUB_BYTES = 32;\n// Group mode targets a handful of members; the cap keeps a crafted copy from\n// demanding one asymmetric operation per stanza without bound.\nexport const MAX_RECIPIENTS = 256;\n\n// Domain separation: every signature and derivation binds its purpose, so\n// bytes signed in one role can never be replayed in another.\nconst DOMAIN_BOX = 'selfstore-group-sig-v1';\nconst DOMAIN_MANIFEST = 'selfstore-group-manifest-v1';\nconst HKDF_INFO = 'selfstore-group-wrap-v1';\n\nconst utf8 = new TextEncoder();\n\n/**\n * A member's full identity: private halves PKCS#8 DER, public halves raw 32\n * bytes, all base64. Treat the *Priv fields like a password - seal them at\n * rest (identityVault) and move them only over a trusted channel.\n */\nexport interface GroupIdentity {\n\tsigPub: string;\n\tsigPriv: string;\n\tencPub: string;\n\tencPriv: string;\n}\n\n/** One member as the manifest lists them: public keys only. */\nexport interface GroupMember {\n\tid: string;\n\tlabel?: string;\n\t/** Ed25519 public key (base64 raw): verifies the copies this member signs. */\n\tsig: string;\n\t/** X25519 public key (base64 raw): receives the data-key envelopes. */\n\tenc: string;\n}\n\n/**\n * The membership document, single-writer (the admin), carried as a\n * SignedManifest. `seq` grows on every change; consumers refuse a lower seq\n * than one already applied (the store persists the high-water mark).\n */\nexport interface GroupManifest {\n\tv: 1;\n\t/** Random group id (base64), so seq high-water marks never collide. */\n\tgroup: string;\n\tseq: number;\n\t/** The admin's Ed25519 public key. Members pin it at join time (TOFU). */\n\tadmin: string;\n\tmembers: GroupMember[];\n}\n\n/**\n * A manifest as it travels: the exact signed payload bytes plus the admin's\n * signature. Signing bytes rather than re-serialized JSON sidesteps\n * canonicalization entirely.\n */\nexport interface SignedManifest {\n\tselfstoreManifest: 1;\n\tpayload: string;\n\tsig: string;\n}\n\n/** Coerce to the ArrayBuffer-backed view WebCrypto's types want (safe here). */\nfunction src(u8: Uint8Array): Uint8Array<ArrayBuffer> {\n\treturn u8 as Uint8Array<ArrayBuffer>;\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n\tconst out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));\n\tlet o = 0;\n\tfor (const p of parts) {\n\t\tout.set(p, o);\n\t\to += p.length;\n\t}\n\treturn out;\n}\n\nasync function sha256(bytes: Uint8Array): Promise<Uint8Array> {\n\treturn new Uint8Array(await crypto.subtle.digest('SHA-256', src(bytes)));\n}\n\nlet curvesOk: Promise<boolean> | null = null;\n\n/** Whether WebCrypto implements Ed25519 + X25519 here. Password mode never needs this. */\nexport function groupCryptoAvailable(): Promise<boolean> {\n\tcurvesOk ??= (async () => {\n\t\ttry {\n\t\t\tawait crypto.subtle.generateKey('Ed25519', false, ['sign', 'verify']);\n\t\t\tawait crypto.subtle.generateKey('X25519', false, ['deriveBits']);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t})();\n\treturn curvesOk;\n}\n\nasync function requireCurves(): Promise<void> {\n\tif (!(await groupCryptoAvailable())) {\n\t\tthrow new TypeError(\n\t\t\t'Group mode needs WebCrypto Ed25519 and X25519 (evergreen browsers, Node 20+); ' +\n\t\t\t\t'this platform does not provide them. Use password mode instead, or upgrade the runtime.'\n\t\t);\n\t}\n}\n\nconst importSigPriv = (b64: string): Promise<CryptoKey> =>\n\tcrypto.subtle.importKey('pkcs8', src(fromBase64(b64)), 'Ed25519', false, ['sign']);\nconst importSigPub = (b64: string): Promise<CryptoKey> =>\n\tcrypto.subtle.importKey('raw', src(fromBase64(b64)), 'Ed25519', false, ['verify']);\nconst importEncPriv = (b64: string): Promise<CryptoKey> =>\n\tcrypto.subtle.importKey('pkcs8', src(fromBase64(b64)), 'X25519', false, ['deriveBits']);\nconst importEncPub = (b64: string): Promise<CryptoKey> =>\n\tcrypto.subtle.importKey('raw', src(fromBase64(b64)), 'X25519', false, []);\n\n/** Generate a fresh member identity (two keypairs). */\nexport async function generateIdentity(): Promise<GroupIdentity> {\n\tawait requireCurves();\n\tconst sig = (await crypto.subtle.generateKey('Ed25519', true, [\n\t\t'sign',\n\t\t'verify'\n\t])) as CryptoKeyPair;\n\tconst enc = (await crypto.subtle.generateKey('X25519', true, ['deriveBits'])) as CryptoKeyPair;\n\tconst raw = async (k: CryptoKey): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await crypto.subtle.exportKey('raw', k)));\n\tconst pkcs8 = async (k: CryptoKey): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await crypto.subtle.exportKey('pkcs8', k)));\n\treturn {\n\t\tsigPub: await raw(sig.publicKey),\n\t\tsigPriv: await pkcs8(sig.privateKey),\n\t\tencPub: await raw(enc.publicKey),\n\t\tencPriv: await pkcs8(enc.privateKey)\n\t};\n}\n\n/** The shareable half of an identity: what the admin puts in the manifest. */\nexport function publicIdentity(id: GroupIdentity): { sig: string; enc: string } {\n\treturn { sig: id.sigPub, enc: id.encPub };\n}\n\n/** A fresh random group id for a new manifest. */\nexport function newGroupId(): string {\n\treturn toBase64(crypto.getRandomValues(new Uint8Array(16)));\n}\n\n/** First 8 bytes of SHA-256(raw X25519 public), base64: finds a reader's stanza while naming nobody. */\nexport async function keyId(encPubB64: string): Promise<string> {\n\treturn toBase64((await sha256(fromBase64(encPubB64))).subarray(0, 8));\n}\n\n// Wrap key for one stanza: HKDF-SHA256 over the X25519 shared secret, salted\n// with ephemeralPub || recipientPub so the key binds to this exact pair.\nasync function stanzaWrapKey(\n\tpriv: CryptoKey,\n\totherPub: CryptoKey,\n\tephPubRaw: Uint8Array,\n\trecipientPubRaw: Uint8Array,\n\tusage: 'encrypt' | 'decrypt'\n): Promise<CryptoKey> {\n\tconst shared = new Uint8Array(\n\t\tawait crypto.subtle.deriveBits({ name: 'X25519', public: otherPub }, priv, 256)\n\t);\n\tconst ikm = await crypto.subtle.importKey('raw', src(shared), 'HKDF', false, ['deriveBits']);\n\tconst bits = new Uint8Array(\n\t\tawait crypto.subtle.deriveBits(\n\t\t\t{\n\t\t\t\tname: 'HKDF',\n\t\t\t\thash: 'SHA-256',\n\t\t\t\tsalt: src(concat(ephPubRaw, recipientPubRaw)),\n\t\t\t\tinfo: src(utf8.encode(HKDF_INFO))\n\t\t\t},\n\t\t\tikm,\n\t\t\t256\n\t\t)\n\t);\n\treturn crypto.subtle.importKey('raw', src(bits), 'AES-GCM', false, [usage]);\n}\n\n/** Envelope a data key: one ephemeral keypair and one stanza per recipient. */\nexport async function sealDataKey(\n\tdataKey: Uint8Array,\n\trecipientEncPubsB64: string[]\n): Promise<RecipientStanza[]> {\n\tawait requireCurves();\n\tif (dataKey.length !== DATA_KEY_BYTES) {\n\t\tthrow new TypeError(`sealDataKey: data key must be ${DATA_KEY_BYTES} bytes (AES-256).`);\n\t}\n\tif (recipientEncPubsB64.length > MAX_RECIPIENTS) {\n\t\tthrow new TypeError(`sealDataKey: too many recipients (max ${MAX_RECIPIENTS}).`);\n\t}\n\tconst out: RecipientStanza[] = [];\n\tfor (const r of recipientEncPubsB64) {\n\t\tconst eph = (await crypto.subtle.generateKey('X25519', false, ['deriveBits'])) as CryptoKeyPair;\n\t\tconst ephPubRaw = new Uint8Array(await crypto.subtle.exportKey('raw', eph.publicKey));\n\t\tconst key = await stanzaWrapKey(\n\t\t\teph.privateKey,\n\t\t\tawait importEncPub(r),\n\t\t\tephPubRaw,\n\t\t\tfromBase64(r),\n\t\t\t'encrypt'\n\t\t);\n\t\tconst iv = crypto.getRandomValues(new Uint8Array(12));\n\t\tconst wrap = new Uint8Array(\n\t\t\tawait crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, src(dataKey))\n\t\t);\n\t\tout.push({\n\t\t\tkid: await keyId(r),\n\t\t\tepk: toBase64(ephPubRaw),\n\t\t\tiv: toBase64(iv),\n\t\t\twrap: toBase64(wrap)\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Open the stanza addressed to this identity and return the data key.\n * NOT_A_RECIPIENT when none opens (identity removed, or the copy predates\n * its joining).\n */\nexport async function openDataKey(\n\tstanzas: RecipientStanza[],\n\tidentity: Pick<GroupIdentity, 'encPub' | 'encPriv'>\n): Promise<Uint8Array> {\n\tawait requireCurves();\n\tif (stanzas.length > MAX_RECIPIENTS) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', `Too many recipient stanzas (max ${MAX_RECIPIENTS}).`);\n\t}\n\tconst myKid = await keyId(identity.encPub);\n\tconst mine = stanzas.filter((s) => s.kid === myKid);\n\t// On a kid miss try them all; MAX_RECIPIENTS bounds that work.\n\tconst candidates = mine.length > 0 ? mine : stanzas;\n\tconst priv = await importEncPriv(identity.encPriv);\n\tconst myPubRaw = fromBase64(identity.encPub);\n\tfor (const s of candidates) {\n\t\ttry {\n\t\t\tconst key = await stanzaWrapKey(\n\t\t\t\tpriv,\n\t\t\t\tawait importEncPub(s.epk),\n\t\t\t\tfromBase64(s.epk),\n\t\t\t\tmyPubRaw,\n\t\t\t\t'decrypt'\n\t\t\t);\n\t\t\tconst pt = new Uint8Array(\n\t\t\t\tawait crypto.subtle.decrypt(\n\t\t\t\t\t{ name: 'AES-GCM', iv: src(fromBase64(s.iv)) },\n\t\t\t\t\tkey,\n\t\t\t\t\tsrc(fromBase64(s.wrap))\n\t\t\t\t)\n\t\t\t);\n\t\t\t// Any other length is a key-downgrade attempt, not a valid envelope.\n\t\t\tif (pt.length === DATA_KEY_BYTES) return pt;\n\t\t} catch {\n\t\t\t/* not our stanza (or tampered): try the next candidate */\n\t\t}\n\t}\n\tthrow new SelfstoreError(\n\t\t'NOT_A_RECIPIENT',\n\t\t'No envelope opens for this identity: it is not (or no longer) a recipient of this copy.'\n\t);\n}\n\n/** AES-256-GCM under a raw 32-byte key (the group data key). */\nexport async function gcmSealRaw(\n\tkey32: Uint8Array,\n\tplaintext: Uint8Array\n): Promise<{ iv: string; ciphertext: Uint8Array }> {\n\tconst key = await crypto.subtle.importKey('raw', src(key32), 'AES-GCM', false, ['encrypt']);\n\tconst iv = crypto.getRandomValues(new Uint8Array(12));\n\tconst ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, src(plaintext));\n\treturn { iv: toBase64(iv), ciphertext: new Uint8Array(ct) };\n}\n\n/** Decrypt AES-256-GCM under a raw key; a tag failure is DECRYPT_FAILED. */\nexport async function gcmOpenRaw(\n\tkey32: Uint8Array,\n\tivB64: string,\n\tciphertext: Uint8Array\n): Promise<Uint8Array> {\n\ttry {\n\t\tconst key = await crypto.subtle.importKey('raw', src(key32), 'AES-GCM', false, ['decrypt']);\n\t\tconst pt = await crypto.subtle.decrypt(\n\t\t\t{ name: 'AES-GCM', iv: src(fromBase64(ivB64)) },\n\t\t\tkey,\n\t\t\tsrc(ciphertext)\n\t\t);\n\t\treturn new Uint8Array(pt);\n\t} catch {\n\t\tthrow new SelfstoreError('DECRYPT_FAILED', 'Corrupted or mismatched group ciphertext.');\n\t}\n}\n\n/**\n * Ed25519 over domain || SHA-256(meta.json) || SHA-256(data.enc): the two\n * digests cover everything a reader trusts (recipients, author claim, iv,\n * ciphertext). Returns the raw 64-byte sig.bin entry.\n */\nexport async function signBox(\n\tmetaBytes: Uint8Array,\n\tdataEnc: Uint8Array,\n\tsigPrivB64: string\n): Promise<Uint8Array> {\n\tawait requireCurves();\n\tconst msg = concat(utf8.encode(DOMAIN_BOX), await sha256(metaBytes), await sha256(dataEnc));\n\tconst key = await importSigPriv(sigPrivB64);\n\treturn new Uint8Array(await crypto.subtle.sign('Ed25519', key, src(msg)));\n}\n\n/** False on any failure (bad key, bad bytes); the caller maps it to SIGNATURE_INVALID. */\nexport async function verifyBox(\n\tmetaBytes: Uint8Array,\n\tdataEnc: Uint8Array,\n\tsig: Uint8Array,\n\tsigPubB64: string\n): Promise<boolean> {\n\ttry {\n\t\tawait requireCurves();\n\t\tconst msg = concat(utf8.encode(DOMAIN_BOX), await sha256(metaBytes), await sha256(dataEnc));\n\t\treturn await crypto.subtle.verify('Ed25519', await importSigPub(sigPubB64), src(sig), src(msg));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** Sign a manifest with the admin key, over the exact payload bytes. */\nexport async function signManifest(\n\tmanifest: GroupManifest,\n\tadminSigPrivB64: string\n): Promise<SignedManifest> {\n\tawait requireCurves();\n\tconst payload = utf8.encode(JSON.stringify(manifest));\n\tconst key = await importSigPriv(adminSigPrivB64);\n\tconst msg = concat(utf8.encode(DOMAIN_MANIFEST), payload);\n\tconst sig = new Uint8Array(await crypto.subtle.sign('Ed25519', key, src(msg)));\n\treturn { selfstoreManifest: 1, payload: toBase64(payload), sig: toBase64(sig) };\n}\n\n/**\n * Verify and parse a signed manifest against the pinned admin key (TOFU from\n * the invite). Rollback (seq) is enforced by the store, which persists the\n * high-water mark.\n */\nexport async function openManifest(\n\tsigned: SignedManifest,\n\tadminSigPubB64: string,\n\texpectedGroupB64?: string\n): Promise<GroupManifest> {\n\tawait requireCurves();\n\tconst bad = (why: string): SelfstoreError => new SelfstoreError('SIGNATURE_INVALID', why);\n\tif (!signed || signed.selfstoreManifest !== 1 || typeof signed.payload !== 'string') {\n\t\tthrow bad('Not a signed selfstore manifest.');\n\t}\n\tlet payload: Uint8Array;\n\tlet ok: boolean;\n\ttry {\n\t\tpayload = fromBase64(signed.payload);\n\t\tconst msg = concat(utf8.encode(DOMAIN_MANIFEST), payload);\n\t\tok = await crypto.subtle.verify(\n\t\t\t'Ed25519',\n\t\t\tawait importSigPub(adminSigPubB64),\n\t\t\tsrc(fromBase64(signed.sig ?? '')),\n\t\t\tsrc(msg)\n\t\t);\n\t} catch {\n\t\tthrow bad('Malformed manifest signature or keys.');\n\t}\n\tif (!ok) throw bad('Manifest signature invalid for the pinned admin key.');\n\tconst m = JSON.parse(new TextDecoder().decode(payload)) as GroupManifest;\n\t// Reject malformed member keys here, not later at import time.\n\tconst is32ByteKey = (b64: string): boolean => {\n\t\ttry {\n\t\t\treturn fromBase64(b64).length === CURVE_PUB_BYTES;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t};\n\tconst shapeOk =\n\t\tm &&\n\t\tm.v === 1 &&\n\t\ttypeof m.group === 'string' &&\n\t\tNumber.isInteger(m.seq) &&\n\t\tm.seq >= 0 &&\n\t\tm.admin === adminSigPubB64 &&\n\t\tArray.isArray(m.members) &&\n\t\tm.members.length <= MAX_RECIPIENTS &&\n\t\tm.members.every(\n\t\t\t(mem) =>\n\t\t\t\tmem &&\n\t\t\t\ttypeof mem.id === 'string' &&\n\t\t\t\tmem.id.length > 0 &&\n\t\t\t\tis32ByteKey(mem.sig) &&\n\t\t\t\tis32ByteKey(mem.enc)\n\t\t);\n\tif (!shapeOk) throw bad('Manifest shape invalid or admin key mismatch.');\n\t// A member id resolves an author to a person; duplicates make that ambiguous.\n\tif (new Set(m.members.map((mem) => mem.id)).size !== m.members.length) {\n\t\tthrow bad('Manifest has duplicate member ids.');\n\t}\n\t// An admin who reuses one key across groups must not get a manifest for\n\t// group Y accepted where X is meant.\n\tif (expectedGroupB64 !== undefined && m.group !== expectedGroupB64) {\n\t\tthrow bad('Manifest is for a different group than expected.');\n\t}\n\treturn m;\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { connect3, connect2, isSupported, openExisting, connect as connect$1 } from './chunk-TKWU52LK.js';
|
|
2
|
+
import { makeMachine, withDeadline, toStoreError } from './chunk-W22V5CRM.js';
|
|
3
|
+
import { connect } from './chunk-J5MFXJU6.js';
|
|
4
|
+
import { restore } from './chunk-MGDXR3RB.js';
|
|
5
|
+
import { SelfstoreError, isSelfstoreError } from './chunk-3OBJOMQ2.js';
|
|
5
6
|
|
|
6
7
|
// src/flows/connect.ts
|
|
7
8
|
var DEFAULT_DEADLINE_MS = 3e4;
|
|
@@ -69,16 +70,16 @@ function connectFlow(store, targets, options = {}) {
|
|
|
69
70
|
const sub = spec[variant];
|
|
70
71
|
if (sub == null) return null;
|
|
71
72
|
if (typeof sub === "function") return sub;
|
|
72
|
-
return variant === "open" ? () => openExisting({ kv: host.kv }) : () =>
|
|
73
|
+
return variant === "open" ? () => openExisting({ kv: host.kv }) : () => connect$1({ kv: host.kv, fileName: host.backupName });
|
|
73
74
|
}
|
|
74
|
-
return () =>
|
|
75
|
+
return () => connect$1({ kv: host.kv, fileName: host.backupName });
|
|
75
76
|
}
|
|
76
77
|
if (kind === "s3") {
|
|
77
78
|
const config2 = spec;
|
|
78
|
-
return () =>
|
|
79
|
+
return () => connect3({ kv: host.kv, config: config2 });
|
|
79
80
|
}
|
|
80
81
|
const config = spec;
|
|
81
|
-
return () =>
|
|
82
|
+
return () => connect2({ kv: host.kv, config });
|
|
82
83
|
}
|
|
83
84
|
function degradeToManual(kind) {
|
|
84
85
|
const gen = ++generation;
|
|
@@ -204,7 +205,7 @@ function connectFlow(store, targets, options = {}) {
|
|
|
204
205
|
if (busy || step !== "form") return;
|
|
205
206
|
const gen = ++generation;
|
|
206
207
|
m.set({ step: "authorizing", busy: true });
|
|
207
|
-
void withDeadline(
|
|
208
|
+
void withDeadline(connect2({ kv: host.kv, config }), deadlineMs, "The WebDAV server").then(async (t) => {
|
|
208
209
|
if (gen !== generation) return;
|
|
209
210
|
if (!t) {
|
|
210
211
|
fail(
|
|
@@ -226,7 +227,7 @@ function connectFlow(store, targets, options = {}) {
|
|
|
226
227
|
if (busy || step !== "form") return;
|
|
227
228
|
const gen = ++generation;
|
|
228
229
|
m.set({ step: "authorizing", busy: true });
|
|
229
|
-
void withDeadline(
|
|
230
|
+
void withDeadline(connect3({ kv: host.kv, config }), deadlineMs, "The S3 endpoint").then(async (t) => {
|
|
230
231
|
if (gen !== generation) return;
|
|
231
232
|
if (!t) {
|
|
232
233
|
fail(
|
|
@@ -468,5 +469,5 @@ function joinFlow(link, engine, options = {}) {
|
|
|
468
469
|
}
|
|
469
470
|
|
|
470
471
|
export { connectFlow, joinFlow, shareFlow };
|
|
471
|
-
//# sourceMappingURL=chunk-
|
|
472
|
-
//# sourceMappingURL=chunk-
|
|
472
|
+
//# sourceMappingURL=chunk-PNX7AJYO.js.map
|
|
473
|
+
//# sourceMappingURL=chunk-PNX7AJYO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/flows/connect.ts","../src/flows/share.ts","../src/flows/join.ts"],"names":["connect","config","DEFAULT_DEADLINE_MS"],"mappings":"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","file":"chunk-PNX7AJYO.js","sourcesContent":["// connectFlow: the \"where does my data live\" journey as a headless state\n// machine. It owns ordering and failure rules that took a series of\n// production hotfixes to get right, each covered by a test:\n//\n// choose -> (form) -> authorizing -> (password) -> (conflict) -> connected\n// \\-> error\n//\n// One popup per gesture (re-entry ignored while a leg is in flight), and a\n// cancelled popup is not an error - back to 'choose', silently. An encrypted\n// backup's password is proven by a trial read while the store is untouched,\n// so a wrong password can never half-connect (deferUnlock opts out: adopt\n// locked, unlock where the host chooses). overwrite() is the forgotten-\n// password escape: local wiped first, tiny blank write. Merge is the default\n// reconciliation; the destructive choices hide behind 'conflict', which only\n// appears when the app declared local data worth asking about. Network legs\n// run under a deadline; human steps never do. A cancelled journey stays\n// dead - late resolutions are discarded (generation counter).\n\nimport type { LocalStore, StoreError } from '../persistence/store';\nimport type { BackupTarget } from '../persistence/target';\nimport type { KV } from '../persistence/cache';\nimport { restore } from '../selfstore/fluent';\nimport { SelfstoreError, isSelfstoreError } from '../selfstore/errors';\nimport { connect as driveConnect, type DriveAuth } from '../persistence/targets/drive';\nimport {\n\tconnect as fileConnect,\n\tisSupported as fileIsSupported,\n\topenExisting as fileOpenExisting\n} from '../persistence/targets/file';\nimport { connect as webdavConnect, type WebdavConfig } from '../persistence/targets/webdav';\nimport { connect as s3Connect, type S3Config } from '../persistence/targets/s3';\nimport { makeMachine, toStoreError, withDeadline, type FlowStore } from './machine';\n\nexport type ConnectKind = 'drive' | 'file' | 'webdav' | 's3';\n\n/** Produce a connected BackupTarget, or null when the user cancelled the\n * gesture (consent refused, picker closed). Custom connectors slot custom\n * targets - or test fakes - into the same journey. */\nexport type Connector = () => Promise<BackupTarget | null>;\n\n/** Which destinations the flow offers, and how to open each one. The offer\n * renders in this OBJECT's insertion order: the host decides which\n * destination leads by how it writes the object, not by a ranking here. */\nexport interface ConnectTargets {\n\t/** Google Drive: the auth strategy (e.g. gisDriveAuth), or a custom connector. */\n\tdrive?: DriveAuth | Connector;\n\t/** Local file via the browser's picker (true), or a custom connector. On\n\t * browsers without the File System Access API the flow degrades to the\n\t * manual download mode by itself. The object form offers TWO gestures on\n\t * the same destination: `create` (save picker: start or overwrite a backup\n\t * file) and `open` (open picker: adopt an EXISTING backup file - it then\n\t * goes through the same inspect/password/resolution journey). */\n\tfile?: true | Connector | { create?: true | Connector; open?: true | Connector };\n\t/** WebDAV: true renders a 'form' step and expects submitWebdav(config);\n\t * a fixed WebdavConfig skips the form; or a custom connector. */\n\twebdav?: true | WebdavConfig | Connector;\n\t/** S3-compatible bucket (Amazon S3, R2, B2, MinIO): true renders a 'form'\n\t * step and expects submitS3(config); a fixed S3Config skips the form; or a\n\t * custom connector. Offer it alongside `webdav` and the widget groups both\n\t * under one \"your server\" entry with a WebDAV/S3 toggle. */\n\ts3?: true | S3Config | Connector;\n}\n\n/** What the flows need from the store. The simple store exposes this as\n * `store.flowHost`; an advanced-store app builds it by hand. */\nexport interface FlowHost {\n\tengine: LocalStore;\n\tkv: KV;\n\t/** Backup file name on the destination (the simple store uses `app.zip`). */\n\tbackupName: string;\n}\n\n/** What every flow and widget accepts as \"the store\": the simple facade, which\n * carries its ports on `flowHost`, or a hand-built host. */\nexport type StoreLike = FlowHost | { flowHost: FlowHost };\n\nexport interface ConnectFlowOptions {\n\t/** Declare when this device holds data worth a question: only then does an\n\t * existing backup raise the 'conflict' step with the destructive choices.\n\t * Default: never - the flow applies defaultResolution. */\n\thasLocalData?: () => boolean;\n\t/** How to reconcile with a destination that already holds a backup when the\n\t * conflict step is not raised. Default 'merge' - the only choice that\n\t * loses nothing on either side. 'resume' adopts the backup (the\n\t * destination wins; this device's working copy is replaced), 'replace'\n\t * overwrites the backup with this device. An encrypted backup still asks\n\t * for its password first, whatever the resolution; an empty destination\n\t * is not concerned (this device's data simply becomes its content). */\n\tdefaultResolution?: ConnectResolution;\n\t/** Skip the password step on an encrypted backup: adopt it AS is (resume)\n\t * and complete with the store locked - nothing readable, nothing\n\t * clobbered - for the host to unlock on its own surface (engine.unlock)\n\t * after the connect. Adoption is forced whatever defaultResolution says:\n\t * without the proven key a merge is impossible and a replace would\n\t * destroy a backup no one proved they own. Hosts that let a device\n\t * holding real local data connect should keep the password-first\n\t * journey - adoption replaces the working copy. */\n\tdeferUnlock?: boolean;\n\t/**\n\t * A secret the host already holds (an app passphrase, a derived key), used\n\t * to encrypt the backup when this journey creates or adopts one that is NOT\n\t * already encrypted - an empty destination, or a plaintext file.\n\t *\n\t * Two things need it. A store built with `requireEncryption` refuses a\n\t * passwordless attach outright (ENCRYPTION_REQUIRED), so without this the\n\t * connect journey cannot complete at all. And even without that setting, a\n\t * fresh backup is better born encrypted than written in clear and protected\n\t * on a second write, which would leave cleartext on the destination in\n\t * between.\n\t *\n\t * Never used against a destination whose backup is already encrypted: that\n\t * one is proven through the password step (or adopted locked under\n\t * `deferUnlock`), so a host secret that happens to differ can neither fail\n\t * the attach nor overwrite what it cannot read. Resolved lazily, so the\n\t * secret is only read when a connect actually needs it. Must satisfy the\n\t * store's password policy.\n\t */\n\tpassword?: string | (() => string | Promise<string>);\n\t/** Deadline for each network leg (inspect, trial-read, attach), ms. */\n\tdeadlineMs?: number;\n}\n\nexport type ConnectStep =\n\t'choose' | 'form' | 'authorizing' | 'password' | 'conflict' | 'connected' | 'error';\n\n/** How to reconcile with a destination that already holds a backup. */\nexport type ConnectResolution = 'merge' | 'resume' | 'replace';\n\n/** What connecting did. 'merged': both sides folded. 'started': empty\n * destination now holds this device's data. 'resumed': the backup won,\n * this device adopted it. 'replaced': this device won, the backup was\n * overwritten. 'manual': degraded download-on-demand file mode. */\nexport type ConnectFlowOutcome = 'merged' | 'started' | 'resumed' | 'replaced' | 'manual';\n\nexport interface ConnectSnapshot {\n\tstep: ConnectStep;\n\t/** The destinations to offer, in the order given. */\n\tkinds: readonly ConnectKind[];\n\t/** The destination being connected (null while choosing). */\n\tkind: ConnectKind | null;\n\t/** Set when step === 'connected'. */\n\toutcome: ConnectFlowOutcome | null;\n\t/** Known after inspection: the destination already holds a backup. */\n\thasBackup: boolean;\n\t/** ...and that backup is encrypted. */\n\tencrypted: boolean;\n\t/** The last submitPassword() was wrong (stay on 'password', say so). */\n\tpasswordError: boolean;\n\t/** An async leg is in flight (render a spinner, disable the actions). */\n\tbusy: boolean;\n\t/** Set when step === 'error': show `labelKey`, log `message`. */\n\terror: StoreError | null;\n}\n\nexport interface ConnectFlow extends FlowStore<ConnectSnapshot> {\n\t/** Pick a destination. Call it inside the user's click: the consent popup /\n\t * file picker opens synchronously from the gesture. Ignored while a leg is\n\t * already in flight (one popup per gesture). For a `file` target declared\n\t * with the object form, `variant` picks the gesture: 'create' (default,\n\t * save picker) or 'open' (adopt an existing backup file). */\n\tchoose(kind: ConnectKind, variant?: 'create' | 'open'): void;\n\t/** 'form' step (webdav: true): submit the server config. */\n\tsubmitWebdav(config: WebdavConfig): void;\n\t/** 'form' step (s3: true): submit the bucket config. */\n\tsubmitS3(config: S3Config): void;\n\t/** 'password' step: prove the backup's password. Wrong password sets\n\t * passwordError and stays here; nothing is attached either way. */\n\tsubmitPassword(password: string): void;\n\t/** 'password' step escape hatch: give up on a forgotten password and start a\n\t * fresh backup over the protected one. The encrypted backup is overwritten\n\t * by this device's data (possibly empty) and lost for good - the only way\n\t * out when the password cannot be recovered. */\n\toverwrite(): void;\n\t/** 'conflict' step: pick the reconciliation. */\n\tresolveConflict(how: ConnectResolution): void;\n\t/** Abandon the journey in progress: back to 'choose'. A late resolution of\n\t * the abandoned leg is discarded. */\n\tcancel(): void;\n\t/** 'error' step: back to 'choose' to try again. */\n\tretry(): void;\n}\n\nconst DEFAULT_DEADLINE_MS = 30_000;\n\n/** A resolution's attach plan: which strategy runs, which outcome it names. */\nfunction planFor(how: ConnectResolution): {\n\tstrategy: 'merge' | 'replace-local' | 'replace-remote';\n\toutcome: ConnectFlowOutcome;\n} {\n\tif (how === 'resume') return { strategy: 'replace-local', outcome: 'resumed' };\n\tif (how === 'replace') return { strategy: 'replace-remote', outcome: 'replaced' };\n\treturn { strategy: 'merge', outcome: 'merged' };\n}\n\nexport function connectFlow(\n\tstore: StoreLike,\n\ttargets: ConnectTargets,\n\toptions: ConnectFlowOptions = {}\n): ConnectFlow {\n\tconst host = 'flowHost' in store ? store.flowHost : store;\n\tconst deadlineMs = options.deadlineMs ?? DEFAULT_DEADLINE_MS;\n\tconst kinds = (Object.keys(targets) as ConnectKind[]).filter(\n\t\t(k) => (k === 'drive' || k === 'file' || k === 'webdav' || k === 's3') && targets[k] != null\n\t);\n\n\tconst m = makeMachine<ConnectSnapshot>({\n\t\tstep: 'choose',\n\t\tkinds,\n\t\tkind: null,\n\t\toutcome: null,\n\t\thasBackup: false,\n\t\tencrypted: false,\n\t\tpasswordError: false,\n\t\tbusy: false,\n\t\terror: null\n\t});\n\n\t// The journey's working set. `generation` invalidates in-flight legs on\n\t// cancel(): whoever resolves late compares its captured generation and\n\t// drops its result instead of resurrecting an abandoned journey.\n\tlet generation = 0;\n\tlet target: BackupTarget | null = null;\n\tlet password: string | null = null;\n\t// Set at inspection: the destination already holds an ENCRYPTED backup, so\n\t// its key is the one that matters and the host secret must stay out of it.\n\tlet remoteEncrypted = false;\n\n\tconst backToChoose = (): void => {\n\t\tgeneration++;\n\t\ttarget = null;\n\t\tpassword = null;\n\t\tremoteEncrypted = false;\n\t\tm.set({\n\t\t\tstep: 'choose',\n\t\t\tkind: null,\n\t\t\toutcome: null,\n\t\t\thasBackup: false,\n\t\t\tencrypted: false,\n\t\t\tpasswordError: false,\n\t\t\tbusy: false,\n\t\t\terror: null\n\t\t});\n\t};\n\n\tconst fail = (e: unknown): void => {\n\t\tpassword = null;\n\t\tm.set({ step: 'error', busy: false, error: toStoreError(e) });\n\t};\n\n\t/** The host's own secret, resolved on demand (see options.password). */\n\tconst hostSecret = async (): Promise<string | null> => {\n\t\tconst supplied = options.password;\n\t\tif (supplied === undefined) return null;\n\t\treturn typeof supplied === 'function' ? await supplied() : supplied;\n\t};\n\n\tfunction connectorFor(\n\t\tkind: ConnectKind,\n\t\tvariant: 'create' | 'open' = 'create'\n\t): Connector | null {\n\t\tconst spec = targets[kind];\n\t\tif (spec == null) return null;\n\t\tif (typeof spec === 'function') return spec;\n\t\tif (kind === 'drive') {\n\t\t\tconst auth = spec as DriveAuth;\n\t\t\treturn () => driveConnect({ auth, kv: host.kv, fileName: host.backupName });\n\t\t}\n\t\tif (kind === 'file') {\n\t\t\t// Object form: each gesture has its own spec ('open' has no built-in\n\t\t\t// meaning for other kinds, so it resolves here only).\n\t\t\tif (typeof spec === 'object' && !('url' in spec)) {\n\t\t\t\tconst sub = (spec as { create?: true | Connector; open?: true | Connector })[variant];\n\t\t\t\tif (sub == null) return null;\n\t\t\t\tif (typeof sub === 'function') return sub;\n\t\t\t\treturn variant === 'open'\n\t\t\t\t\t? () => fileOpenExisting({ kv: host.kv })\n\t\t\t\t\t: () => fileConnect({ kv: host.kv, fileName: host.backupName });\n\t\t\t}\n\t\t\treturn () => fileConnect({ kv: host.kv, fileName: host.backupName });\n\t\t}\n\t\tif (kind === 's3') {\n\t\t\tconst config = spec as S3Config; // 's3: true' goes through the form step\n\t\t\treturn () => s3Connect({ kv: host.kv, config });\n\t\t}\n\t\tconst config = spec as WebdavConfig; // 'webdav: true' goes through the form step\n\t\treturn () => webdavConnect({ kv: host.kv, config });\n\t}\n\n\t/** No picker on this browser: download-on-demand instead of a dead button. */\n\tfunction degradeToManual(kind: ConnectKind): void {\n\t\tconst gen = ++generation;\n\t\tm.set({ step: 'authorizing', kind, busy: true, error: null });\n\t\tvoid host.engine\n\t\t\t.setManualFile()\n\t\t\t.then(() => {\n\t\t\t\tif (gen !== generation) return;\n\t\t\t\tm.set({ step: 'connected', outcome: 'manual', busy: false });\n\t\t\t})\n\t\t\t.catch((e) => {\n\t\t\t\tif (gen !== generation) return;\n\t\t\t\tfail(e);\n\t\t\t});\n\t}\n\n\t/** After the target is in hand: inspect, then route to password / conflict /\n\t * attach. Everything here is network - deadline-bounded, generation-checked. */\n\tasync function inspectAndRoute(gen: number, t: BackupTarget): Promise<void> {\n\t\tconst info = await withDeadline(host.engine.inspectTarget(t), deadlineMs, 'The destination');\n\t\tif (gen !== generation) return;\n\t\ttarget = t;\n\t\tremoteEncrypted = info.encrypted;\n\t\tm.set({ hasBackup: info.hasBackup, encrypted: info.encrypted });\n\t\tif (!info.hasBackup) {\n\t\t\t// Empty destination: this device's data becomes its content. Nothing\n\t\t\t// to ask, nothing to lose.\n\t\t\tawait attach(gen, 'replace-remote', 'started');\n\t\t\treturn;\n\t\t}\n\t\tif (info.app !== null && info.app !== host.engine.app) {\n\t\t\t// Another app's backup: say so NOW, before the password step. Asking\n\t\t\t// first taught the user their password \"does not work\" on a file that\n\t\t\t// was never this app's to open - and deferUnlock went further and\n\t\t\t// silently adopted the foreign file as this app's home. The header\n\t\t\t// names its app in cleartext precisely so a wrong pick can be named\n\t\t\t// for what it is; a header that does not say accuses no one.\n\t\t\tm.set({\n\t\t\t\tstep: 'error',\n\t\t\t\tbusy: false,\n\t\t\t\terror: toStoreError(\n\t\t\t\t\tnew SelfstoreError(\n\t\t\t\t\t\t'FOREIGN_BACKUP',\n\t\t\t\t\t\t`This backup was written by \"${info.app}\", not \"${host.engine.app}\". Open it in its own application.`\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (info.encrypted) {\n\t\t\tif (options.deferUnlock) {\n\t\t\t\t// The host owns the unlock surface: adopt the backup as it stands.\n\t\t\t\t// A null password on an encrypted file lands the store locked -\n\t\t\t\t// nothing readable, nothing clobbered - until engine.unlock()\n\t\t\t\t// proves the password wherever the host asks for it. The conflict\n\t\t\t\t// step is moot here: without the key, merge cannot read the remote\n\t\t\t\t// and replace would destroy a backup no one proved they own.\n\t\t\t\tawait attach(gen, 'replace-local', 'resumed');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Ask before touching anything. The password gates every resolution,\n\t\t\t// including 'replace': overwriting an encrypted backup demands proof\n\t\t\t// of ownership, or a typo away from someone's data.\n\t\t\tm.set({ step: 'password', busy: false, passwordError: false });\n\t\t\treturn;\n\t\t}\n\t\trouteAfterUnlock(gen);\n\t}\n\n\t/** Password proven (or none needed): either ask the conflict question, or\n\t * apply the default resolution - 'merge' unless the host chose otherwise,\n\t * the only default that loses nothing on either side. */\n\tfunction routeAfterUnlock(gen: number): void {\n\t\tif (gen !== generation) return;\n\t\tif (options.hasLocalData?.() === true) {\n\t\t\tm.set({ step: 'conflict', busy: false });\n\t\t\treturn;\n\t\t}\n\t\tconst plan = planFor(options.defaultResolution ?? 'merge');\n\t\tvoid attach(gen, plan.strategy, plan.outcome);\n\t}\n\n\tasync function attach(\n\t\tgen: number,\n\t\tstrategy: 'merge' | 'replace-local' | 'replace-remote',\n\t\toutcome: ConnectFlowOutcome,\n\t\twipe = false\n\t): Promise<void> {\n\t\tif (gen !== generation || !target) return;\n\t\tm.set({ busy: true });\n\t\ttry {\n\t\t\t// A backup that is already encrypted carries its own key: it was proven\n\t\t\t// at the password step, or deliberately left locked. Everywhere else -\n\t\t\t// an empty destination, a plaintext one - the host secret (when it\n\t\t\t// offers one) makes the backup encrypted from its very first write.\n\t\t\tconst secret = password ?? (remoteEncrypted ? null : await hostSecret());\n\t\t\tif (gen !== generation) return;\n\t\t\tawait withDeadline(\n\t\t\t\thost.engine.attachTarget(target, { password: secret, strategy, wipe }),\n\t\t\t\tdeadlineMs,\n\t\t\t\t'The destination'\n\t\t\t);\n\t\t\tif (gen !== generation) return;\n\t\t\tpassword = null;\n\t\t\tm.set({ step: 'connected', outcome, busy: false, error: null });\n\t\t} catch (e) {\n\t\t\tif (gen !== generation) return;\n\t\t\tfail(e);\n\t\t}\n\t}\n\n\treturn {\n\t\tget snapshot() {\n\t\t\treturn m.snapshot;\n\t\t},\n\t\tsubscribe: m.subscribe,\n\n\t\tchoose(kind: ConnectKind, variant: 'create' | 'open' = 'create'): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || (step !== 'choose' && step !== 'error')) return; // one popup per gesture\n\t\t\tconst connector = connectorFor(kind, variant);\n\t\t\tif (!connector) return;\n\t\t\tif (\n\t\t\t\t(kind === 'webdav' && targets.webdav === true) ||\n\t\t\t\t(kind === 's3' && targets.s3 === true)\n\t\t\t) {\n\t\t\t\tm.set({ step: 'form', kind, error: null });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Degraded manual mode only makes sense for CREATING a backup through\n\t\t\t// the built-in save picker: adopting an existing file needs the real\n\t\t\t// picker, and a custom connector owns its own fallback.\n\t\t\tconst builtinCreate =\n\t\t\t\ttargets.file === true ||\n\t\t\t\t(typeof targets.file === 'object' &&\n\t\t\t\t\t(targets.file as { create?: unknown }).create !== undefined &&\n\t\t\t\t\ttypeof (targets.file as { create?: unknown }).create !== 'function');\n\t\t\tconst canDegrade = kind === 'file' && variant === 'create' && builtinCreate;\n\t\t\tif (canDegrade && !fileIsSupported()) {\n\t\t\t\tdegradeToManual(kind);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst gen = ++generation;\n\t\t\tm.set({ step: 'authorizing', kind, busy: true, error: null });\n\t\t\t// The connector runs the human gesture (popup, picker): no deadline on\n\t\t\t// people. The network legs after it are bounded in inspectAndRoute.\n\t\t\tvoid connector()\n\t\t\t\t.then(async (t) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (!t) {\n\t\t\t\t\t\t// The picker was there, and refused: this browser has no file\n\t\t\t\t\t\t// mode, we just could not know before asking. Same landing as\n\t\t\t\t\t\t// a browser without the API - the offer must not send the\n\t\t\t\t\t\t// practitioner back to a button that will refuse again.\n\t\t\t\t\t\tif (canDegrade && !fileIsSupported()) {\n\t\t\t\t\t\t\tdegradeToManual(kind);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Drive/file/custom answer null for a cancelled popup or picker:\n\t\t\t\t\t\t// not an error, no message. A FIXED webdav/s3 config answering\n\t\t\t\t\t\t// null means the server did not: that one is a retryable error.\n\t\t\t\t\t\tif (kind === 'webdav' || kind === 's3') {\n\t\t\t\t\t\t\tfail(\n\t\t\t\t\t\t\t\tnew SelfstoreError(\n\t\t\t\t\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t\t\t\t\t'The server did not answer (address, credentials or CORS).'\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbackToChoose();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait inspectAndRoute(gen, t);\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tfail(e);\n\t\t\t\t});\n\t\t},\n\n\t\tsubmitWebdav(config: WebdavConfig): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'form') return;\n\t\t\tconst gen = ++generation;\n\t\t\tm.set({ step: 'authorizing', busy: true });\n\t\t\tvoid withDeadline(webdavConnect({ kv: host.kv, config }), deadlineMs, 'The WebDAV server')\n\t\t\t\t.then(async (t) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (!t) {\n\t\t\t\t\t\t// webdavConnect answers null when the server does not: with an\n\t\t\t\t\t\t// explicit config this is a wrong-address error, not a cancel.\n\t\t\t\t\t\tfail(\n\t\t\t\t\t\t\tnew SelfstoreError(\n\t\t\t\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t\t\t\t'The WebDAV server did not answer (URL, credentials or CORS).'\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait inspectAndRoute(gen, t);\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tfail(e);\n\t\t\t\t});\n\t\t},\n\n\t\tsubmitS3(config: S3Config): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'form') return;\n\t\t\tconst gen = ++generation;\n\t\t\tm.set({ step: 'authorizing', busy: true });\n\t\t\tvoid withDeadline(s3Connect({ kv: host.kv, config }), deadlineMs, 'The S3 endpoint')\n\t\t\t\t.then(async (t) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (!t) {\n\t\t\t\t\t\t// s3Connect answers null when the endpoint does not: with an\n\t\t\t\t\t\t// explicit config this is a wrong-config error, not a cancel.\n\t\t\t\t\t\tfail(\n\t\t\t\t\t\t\tnew SelfstoreError(\n\t\t\t\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t\t\t\t'The S3 endpoint did not answer (endpoint, credentials or CORS).'\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait inspectAndRoute(gen, t);\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tfail(e);\n\t\t\t\t});\n\t\t},\n\n\t\tsubmitPassword(pw: string): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'password' || !target) return;\n\t\t\tconst gen = generation;\n\t\t\tm.set({ busy: true, passwordError: false });\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\t// PROVE the password against the real backup while the store is\n\t\t\t\t\t// still untouched: download and trial-read. A wrong password is a\n\t\t\t\t\t// retype, never a locked store or a gate.\n\t\t\t\t\tconst blob = await withDeadline(target!.load(), deadlineMs, 'The destination');\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (!blob) {\n\t\t\t\t\t\tthrow new SelfstoreError('TARGET_UNAVAILABLE', 'The backup could not be downloaded.');\n\t\t\t\t\t}\n\t\t\t\t\tawait restore(blob).withPassword(pw).read();\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tpassword = pw;\n\t\t\t\t\tm.set({ busy: false });\n\t\t\t\t\trouteAfterUnlock(gen);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (isSelfstoreError(e) && e.code === 'DECRYPT_FAILED') {\n\t\t\t\t\t\tm.set({ busy: false, passwordError: true }); // stay, say so, retype\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tfail(e);\n\t\t\t\t}\n\t\t\t})();\n\t\t},\n\n\t\toverwrite(): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'password' || !target) return;\n\t\t\t// The password is forgotten: stop proving it and START fresh over the\n\t\t\t// protected backup. wipe:true empties local first (fresh sync meta), so\n\t\t\t// this writes a blank new backup - never this device's existing data -\n\t\t\t// and the owner is never stuck behind a lost secret. A blank write is\n\t\t\t// also tiny, so it cannot time out the way pushing a large local store\n\t\t\t// would.\n\t\t\tpassword = null;\n\t\t\tvoid attach(generation, 'replace-remote', 'replaced', true);\n\t\t},\n\n\t\tresolveConflict(how: ConnectResolution): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'conflict') return;\n\t\t\tconst plan = planFor(how);\n\t\t\tvoid attach(generation, plan.strategy, plan.outcome);\n\t\t},\n\n\t\tcancel(): void {\n\t\t\tif (m.snapshot.step === 'connected') return; // done is done\n\t\t\tbackToChoose();\n\t\t},\n\n\t\tretry(): void {\n\t\t\tif (m.snapshot.step !== 'error') return;\n\t\t\tbackToChoose();\n\t\t}\n\t};\n}\n","// shareFlow: the \"who can see this\" panel as a headless machine over an\n// injected ShareEngine - how links travel (Drive public link, relay,\n// mailbox) is the app's business. The flow owns what every such panel gets\n// wrong first: a transient listing failure never blanks it (last-known\n// links stay, flagged stale - a member who saw an empty panel once will\n// revoke something in panic); one operation at a time, so a double-click\n// cannot create two links; removals leave the snapshot only after the\n// engine confirmed them, never optimistically; removing yourself is refused\n// up front (leaving is its own journey, not a row action). Every leg runs\n// under a deadline and reports the stable { code, labelKey, message } shape.\n\nimport type { StoreError } from '../persistence/store';\nimport { makeMachine, toStoreError, withDeadline, type FlowStore } from './machine';\n\nexport type ShareLevel = 'read' | 'write';\n\nexport interface ShareLinkInfo {\n\t/** Engine-scoped stable id (revoke keys on it). */\n\tid: string;\n\t/** The invitation URL to hand out. */\n\turl: string;\n\tlevel: ShareLevel;\n}\n\nexport interface ShareMemberInfo {\n\t/** Engine-scoped stable id (removeMember keys on it). */\n\tid: string;\n\tlabel?: string;\n\t/** This row is the local user. */\n\tself?: boolean;\n\t/** This row owns the share (the app may render a badge, the flow does not care). */\n\towner?: boolean;\n}\n\n/** The app-side port the flow drives. Implementations wrap whatever transport\n * the app shares through; every method may throw (SelfstoreError preferred,\n * anything is normalized). */\nexport interface ShareEngine {\n\t/** The current truth: active links and members. */\n\tlist(): Promise<{ links: ShareLinkInfo[]; members: ShareMemberInfo[] }>;\n\tcreateLink(opts: { level: ShareLevel }): Promise<ShareLinkInfo>;\n\trevokeLink(id: string): Promise<void>;\n\t/** Optional: engines without member management simply omit it. */\n\tremoveMember?(id: string): Promise<void>;\n\t/** Optional: END the whole share in one gesture - every link dead, every\n\t * member out. Engines whose transport has such a move (an invitation to\n\t * kill, a file to re-privatize) expose it; the widget renders the action\n\t * only then. */\n\trevokeAll?(): Promise<void>;\n}\n\nexport type ShareBusy = 'refresh' | 'create' | 'revoke' | 'remove' | 'revoke-all' | null;\n\nexport interface ShareSnapshot {\n\tlinks: readonly ShareLinkInfo[];\n\tmembers: readonly ShareMemberInfo[];\n\t/** The operation in flight, or null. */\n\tbusy: ShareBusy;\n\t/** The last refresh failed: the lists shown are the last-known good ones. */\n\tstale: boolean;\n\t/** The last operation's problem (the lists are never cleared by an error). */\n\terror: StoreError | null;\n\t/** True once the engine offers removeMember (render the row action at all). */\n\tcanRemoveMembers: boolean;\n\t/** True once the engine offers revokeAll (render the end-the-share action). */\n\tcanRevokeAll: boolean;\n}\n\nexport interface ShareFlow extends FlowStore<ShareSnapshot> {\n\t/** Re-list from the engine. Failure keeps the last-known lists (stale). */\n\trefresh(): Promise<void>;\n\t/** Create an invitation link. Resolves to it, or null when refused (an\n\t * operation was already in flight). */\n\tcreateLink(opts: { level: ShareLevel }): Promise<ShareLinkInfo | null>;\n\t/** Revoke a link. The link leaves the snapshot only once the engine\n\t * confirmed. Resolves to whether it did. */\n\trevokeLink(id: string): Promise<boolean>;\n\t/** Remove a member (never yourself - refused up front). Resolves to whether\n\t * the engine confirmed. */\n\tremoveMember(id: string): Promise<boolean>;\n\t/** End the whole share: every link and member leaves the snapshot only\n\t * once the engine confirmed. Resolves to whether it did. */\n\trevokeAll(): Promise<boolean>;\n}\n\nconst DEFAULT_DEADLINE_MS = 30_000;\n\nexport function shareFlow(engine: ShareEngine, options: { deadlineMs?: number } = {}): ShareFlow {\n\tconst deadlineMs = options.deadlineMs ?? DEFAULT_DEADLINE_MS;\n\n\tconst m = makeMachine<ShareSnapshot>({\n\t\tlinks: [],\n\t\tmembers: [],\n\t\tbusy: 'refresh',\n\t\tstale: false,\n\t\terror: null,\n\t\tcanRemoveMembers: typeof engine.removeMember === 'function',\n\t\tcanRevokeAll: typeof engine.revokeAll === 'function'\n\t});\n\n\t/** Serialize the operations: one at a time, the others answer \"refused\". */\n\tfunction begin(op: Exclude<ShareBusy, null>): boolean {\n\t\tif (m.snapshot.busy !== null && !(op === 'refresh' && m.snapshot.busy === 'refresh')) {\n\t\t\treturn false;\n\t\t}\n\t\tm.set({ busy: op });\n\t\treturn true;\n\t}\n\n\tasync function doRefresh(): Promise<void> {\n\t\ttry {\n\t\t\tconst { links, members } = await withDeadline(engine.list(), deadlineMs, 'The share listing');\n\t\t\tm.set({ links, members, busy: null, stale: false, error: null });\n\t\t} catch (e) {\n\t\t\t// Keep the last-known lists: a hiccup must never paint the share as\n\t\t\t// gone. Just say the view may be behind.\n\t\t\tm.set({ busy: null, stale: true, error: toStoreError(e) });\n\t\t}\n\t}\n\n\tconst flow: ShareFlow = {\n\t\tget snapshot() {\n\t\t\treturn m.snapshot;\n\t\t},\n\t\tsubscribe: m.subscribe,\n\n\t\tasync refresh(): Promise<void> {\n\t\t\tif (m.snapshot.busy !== null && m.snapshot.busy !== 'refresh') return;\n\t\t\tm.set({ busy: 'refresh' });\n\t\t\tawait doRefresh();\n\t\t},\n\n\t\tasync createLink(opts): Promise<ShareLinkInfo | null> {\n\t\t\tif (!begin('create')) return null;\n\t\t\ttry {\n\t\t\t\tconst link = await withDeadline(engine.createLink(opts), deadlineMs, 'Creating the link');\n\t\t\t\tm.set({ links: [...m.snapshot.links, link], busy: null, error: null });\n\t\t\t\treturn link;\n\t\t\t} catch (e) {\n\t\t\t\tm.set({ busy: null, error: toStoreError(e) });\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\n\t\tasync revokeLink(id: string): Promise<boolean> {\n\t\t\tif (!begin('revoke')) return false;\n\t\t\ttry {\n\t\t\t\tawait withDeadline(engine.revokeLink(id), deadlineMs, 'Revoking the link');\n\t\t\t\t// Confirmed: NOW it leaves the snapshot.\n\t\t\t\tm.set({ links: m.snapshot.links.filter((l) => l.id !== id), busy: null, error: null });\n\t\t\t\treturn true;\n\t\t\t} catch (e) {\n\t\t\t\tm.set({ busy: null, error: toStoreError(e) });\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\tasync removeMember(id: string): Promise<boolean> {\n\t\t\tconst remove = engine.removeMember?.bind(engine);\n\t\t\tif (!remove) {\n\t\t\t\tthrow new TypeError('shareFlow: this engine does not manage members (no removeMember).');\n\t\t\t}\n\t\t\tconst row = m.snapshot.members.find((mb) => mb.id === id);\n\t\t\tif (row?.self) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t'shareFlow: refusing to remove yourself - leaving a share is its own journey, not a row action.'\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!begin('remove')) return false;\n\t\t\ttry {\n\t\t\t\tawait withDeadline(remove(id), deadlineMs, 'Removing the member');\n\t\t\t\tm.set({\n\t\t\t\t\tmembers: m.snapshot.members.filter((mb) => mb.id !== id),\n\t\t\t\t\tbusy: null,\n\t\t\t\t\terror: null\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t} catch (e) {\n\t\t\t\tm.set({ busy: null, error: toStoreError(e) });\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\tasync revokeAll(): Promise<boolean> {\n\t\t\tconst revoke = engine.revokeAll?.bind(engine);\n\t\t\tif (!revoke) {\n\t\t\t\tthrow new TypeError('shareFlow: this engine does not end the share (no revokeAll).');\n\t\t\t}\n\t\t\tif (!begin('revoke-all')) return false;\n\t\t\ttry {\n\t\t\t\tawait withDeadline(revoke(), deadlineMs, 'Ending the share');\n\t\t\t\t// Confirmed: the share is over, every link and member with it.\n\t\t\t\tm.set({ links: [], members: [], busy: null, error: null });\n\t\t\t\treturn true;\n\t\t\t} catch (e) {\n\t\t\t\tm.set({ busy: null, error: toStoreError(e) });\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t};\n\n\t// The panel opens on the truth: list right away (failures land as stale).\n\tvoid doRefresh();\n\n\treturn flow;\n}\n","// joinFlow: opening an invitation link, as a headless machine over an\n// injected JoinEngine. Preview first, join on an explicit yes. The flow\n// holds the link itself, so a re-render, a login roundtrip or an account\n// switch cannot lose the invitation out from under the user. Joining is\n// single-flight. Mismatch (\"this device already follows another share\") and\n// no-invite (\"spent, or not for this account\") are outcomes with their own\n// steps, not generic errors - each has a different way out. Switching\n// accounts re-previews under the new account. A cancelled or superseded leg\n// cannot resurrect the flow, and every network leg runs under a deadline.\n\nimport type { StoreError } from '../persistence/store';\nimport { makeMachine, toStoreError, withDeadline, type FlowStore } from './machine';\nimport type { ShareLevel } from './share';\n\n/** What the user is about to join - enough to render an honest question. */\nexport interface JoinPreview {\n\t/** The share's display name, when the link carries one. */\n\tlabel?: string;\n\t/** Who shared it (a name, an email - whatever the engine knows). */\n\tfrom?: string;\n\tlevel?: ShareLevel;\n}\n\n/** How joining ended, other than plain failure:\n * 'joined' - this device now follows the share.\n * 'mismatch' - this device already follows a DIFFERENT share: joining a\n * second one is refused (leave the first, or use another\n * device/profile).\n * 'no-invite' - the invitation is spent, expired, or aimed at another\n * account (switching accounts may be the fix). */\nexport type JoinOutcome = 'joined' | 'mismatch' | 'no-invite';\n\n/** The app-side port: how a link is read and honoured on this transport. */\nexport interface JoinEngine {\n\t/** Read-only look at the invitation. Must change NOTHING. */\n\tpreview(link: string): Promise<JoinPreview>;\n\t/** Consume the invitation and wire the share. Resolve null when the user\n\t * backed out of a popup the engine had to open (an account chooser, a\n\t * consent screen): the flow returns to 'ready' silently - backing out of\n\t * a human gesture is not an error, here as everywhere in these flows. */\n\tjoin(link: string): Promise<JoinOutcome | null>;\n\t/** Optional: re-run the account chooser (the invite may belong to another\n\t * account). The flow re-previews after it. */\n\tswitchAccount?(): Promise<void>;\n}\n\nexport type JoinStep =\n\t'previewing' | 'ready' | 'joining' | 'joined' | 'mismatch' | 'no-invite' | 'error';\n\nexport interface JoinSnapshot {\n\t/** The invitation this flow was opened with - held here so the UI can\n\t * always find it again. */\n\tlink: string;\n\tstep: JoinStep;\n\t/** Set once previewed (kept through errors, so retry re-renders context). */\n\tpreview: JoinPreview | null;\n\t/** The engine offers an account switch. */\n\tcanSwitchAccount: boolean;\n\tbusy: boolean;\n\t/** Set when step === 'error': show `labelKey`, log `message`. */\n\terror: StoreError | null;\n}\n\nexport interface JoinFlow extends FlowStore<JoinSnapshot> {\n\t/** Say yes: consume the invitation. Only from 'ready'. */\n\taccept(): void;\n\t/** Re-run the account chooser, then preview again under the new account.\n\t * Available from 'ready', 'no-invite' and 'error' when the engine offers it. */\n\tswitchAccount(): void;\n\t/** From 'error': preview again and resume the journey. */\n\tretry(): void;\n}\n\nconst DEFAULT_DEADLINE_MS = 30_000;\n\nexport function joinFlow(\n\tlink: string,\n\tengine: JoinEngine,\n\toptions: { deadlineMs?: number } = {}\n): JoinFlow {\n\tconst deadlineMs = options.deadlineMs ?? DEFAULT_DEADLINE_MS;\n\n\tconst m = makeMachine<JoinSnapshot>({\n\t\tlink,\n\t\tstep: 'previewing',\n\t\tpreview: null,\n\t\tcanSwitchAccount: typeof engine.switchAccount === 'function',\n\t\tbusy: true,\n\t\terror: null\n\t});\n\n\tlet generation = 0;\n\n\tfunction preview(): void {\n\t\tconst gen = ++generation;\n\t\tm.set({ step: 'previewing', busy: true, error: null });\n\t\tvoid withDeadline(engine.preview(link), deadlineMs, 'The invitation')\n\t\t\t.then((p) => {\n\t\t\t\tif (gen !== generation) return;\n\t\t\t\tm.set({ step: 'ready', preview: p, busy: false });\n\t\t\t})\n\t\t\t.catch((e) => {\n\t\t\t\tif (gen !== generation) return;\n\t\t\t\tm.set({ step: 'error', busy: false, error: toStoreError(e) });\n\t\t\t});\n\t}\n\n\tpreview();\n\n\treturn {\n\t\tget snapshot() {\n\t\t\treturn m.snapshot;\n\t\t},\n\t\tsubscribe: m.subscribe,\n\n\t\taccept(): void {\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || step !== 'ready') return; // single-flight: one join per yes\n\t\t\tconst gen = ++generation;\n\t\t\tm.set({ step: 'joining', busy: true, error: null });\n\t\t\tvoid withDeadline(engine.join(link), deadlineMs, 'Joining')\n\t\t\t\t.then((outcome) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tif (outcome === null) {\n\t\t\t\t\t\t// The user backed out of the engine's popup: the question is\n\t\t\t\t\t\t// still live, the preview still good - just ask again.\n\t\t\t\t\t\tm.set({ step: 'ready', busy: false });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tm.set({ step: outcome, busy: false });\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tm.set({ step: 'error', busy: false, error: toStoreError(e) });\n\t\t\t\t});\n\t\t},\n\n\t\tswitchAccount(): void {\n\t\t\tconst switcher = engine.switchAccount?.bind(engine);\n\t\t\tif (!switcher) return;\n\t\t\tconst { step, busy } = m.snapshot;\n\t\t\tif (busy || (step !== 'ready' && step !== 'no-invite' && step !== 'error')) return;\n\t\t\tconst gen = ++generation;\n\t\t\tm.set({ busy: true, error: null });\n\t\t\tvoid switcher()\n\t\t\t\t.then(() => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tpreview(); // the other account may hold the right invite: look again\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tif (gen !== generation) return;\n\t\t\t\t\tm.set({ step: 'error', busy: false, error: toStoreError(e) });\n\t\t\t\t});\n\t\t},\n\n\t\tretry(): void {\n\t\t\tif (m.snapshot.step !== 'error') return;\n\t\t\tpreview();\n\t\t}\n\t};\n}\n"]}
|