@xyo-network/archivist-indexeddb 2.102.3 → 2.102.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -199,7 +199,11 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abst
199
199
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
200
200
  if (!primaryCursor?.value)
201
201
  return [];
202
- await primaryCursor?.advance(1);
202
+ try {
203
+ primaryCursor = await primaryCursor?.advance(1);
204
+ } catch {
205
+ return [];
206
+ }
203
207
  } else {
204
208
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
205
209
  if (!primaryCursor?.value)
@@ -211,7 +215,13 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abst
211
215
  const value = primaryCursor?.value;
212
216
  if (value) {
213
217
  result.push(value);
214
- primaryCursor = await primaryCursor?.advance(1);
218
+ try {
219
+ primaryCursor = await primaryCursor?.advance(1);
220
+ } catch {
221
+ if (primaryCursor === null) {
222
+ break;
223
+ }
224
+ }
215
225
  if (primaryCursor === null) {
216
226
  break;
217
227
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
@@ -173,7 +173,11 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
173
173
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
174
174
  if (!primaryCursor?.value)
175
175
  return [];
176
- await primaryCursor?.advance(1);
176
+ try {
177
+ primaryCursor = await primaryCursor?.advance(1);
178
+ } catch {
179
+ return [];
180
+ }
177
181
  } else {
178
182
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
179
183
  if (!primaryCursor?.value)
@@ -185,7 +189,13 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
185
189
  const value = primaryCursor?.value;
186
190
  if (value) {
187
191
  result.push(value);
188
- primaryCursor = await primaryCursor?.advance(1);
192
+ try {
193
+ primaryCursor = await primaryCursor?.advance(1);
194
+ } catch {
195
+ if (primaryCursor === null) {
196
+ break;
197
+ }
198
+ }
189
199
  if (primaryCursor === null) {
190
200
  break;
191
201
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":";;;;AAAA,SAASA,gBAAgB;AACzB,SAASC,cAAc;AAEvB,SAASC,yBAAyB;AAClC,SACEC,yBACAC,2BACAC,4BACAC,4BAGAC,0BACAC,8BAEK;AACP,SAASC,uBAAuB;AAChC,SAASC,sBAAsB;AAE/B,SAA4CC,cAAc;;;ACjBnD,IAAMC,2BAAqD;;;ACI3D,IAAMC,iCAAiE,GAAGC,wBAAAA;;;;;;;;;;;;;;AFuB1E,IAAMC,qBAAN,MAAMA,4BAGHC,kBAAAA;SAAAA;;;EACR,OAAyBC,gBAA0B;OAAI,MAAMA;IAAeC;;EAC5E,OAAyBC,sBAA8BD;EACvD,OAAgBE,gBAAgB;EAChC,OAAgBC,mBAAmB;EACnC,OAAgBC,mBAAmB;EACnC,OAAwBC,gBAAkC;IAAEC,KAAK;MAAEC,OAAO;IAAE;IAAGC,YAAY;IAAOC,QAAQ;EAAM;EAChH,OAAwBC,YAA8B;IAAEJ,KAAK;MAAEK,OAAO;IAAE;IAAGH,YAAY;IAAOC,QAAQ;EAAK;EAC3G,OAAwBG,cAAgC;IAAEN,KAAK;MAAEO,QAAQ;IAAE;IAAGL,YAAY;IAAOC,QAAQ;EAAM;;EAE/G,OAAgBK,gBAAgBC,uBAAuBlB,oBAAmBa,SAAS;;EAEnF,OAAgBM,oBAAoBD,uBAAuBlB,oBAAmBQ,aAAa;;EAE3F,OAAgBY,kBAAkBF,uBAAuBlB,oBAAmBe,WAAW;;;;;;;;EASvF,IAAIM,SAAS;AACX,WAAO,KAAKC,QAAQD,UAAU,KAAKC,QAAQC,QAAQvB,oBAAmBK;EACxE;;;;EAKA,IAAImB,YAAY;AACd,WAAO,KAAKF,QAAQE,aAAaxB,oBAAmBM;EACtD;EAEA,IAAamB,UAAU;AACrB,WAAO;MACLC;MACAC;MACAC;MACAC;MACAC;SACG,MAAML;;EAEb;;;;;EAMA,IAAIM,YAAY;AACd,WAAO,KAAKT,QAAQS,aAAa/B,oBAAmBO;EACtD;;;;EAKA,IAAYyB,UAAU;AACpB,WAAO;MAAChC,oBAAmBQ;MAAeR,oBAAmBa;MAAWb,oBAAmBe;SAAiB,KAAKO,QAAQW,SAASD,WAAW,CAAA;;EAC/I;EAEA,MAAyBE,aAAyC;AAEhE,UAAMC,WAAW,MAAM,KAAKC,MAAM,CAACC,OAAOA,GAAGC,OAAO,KAAKP,SAAS,CAAA;AAElE,WAAO,MAAMQ,QAAQC,IAAIL,SAASM,IAAI,CAACC,YAAYC,eAAeC,MAAMF,OAAAA,CAAAA,CAAAA;EAC1E;EAEA,MAAyBG,eAA8B;AACrD,UAAM,KAAKT,MAAM,CAACC,OAAOA,GAAGS,MAAM,KAAKf,SAAS,CAAA;EAClD;EAEA,MAAyBgB,cAAcC,QAAiC;AACtE,UAAMC,QAAQ,MAAMN,eAAeO,UAAU,MAAM,KAAKC,WAAWH,MAAAA,CAAAA;AACnE,UAAMI,iBAAiBH,MAAMI,QAAc,CAACC,SAAS;MAACA,KAAK,CAAA,EAAG5C;MAAO4C,KAAK,CAAA;KAAG;AAE7E,UAAMC,iBAAiB;SAAI,IAAIC,IAAIJ,cAAAA;;AACnC,WAAO,MAAM,KAAKhB,MAAM,OAAOC,OAAAA;AAE7B,YAAMoB,QAAQ,MAAMlB,QAAQC,IAC1Be,eAAed,IAAI,OAAOiB,SAAAA;AAExB,cAAMC,WACH,MAAMtB,GAAGuB,gBAAgB,KAAK7B,WAAW/B,oBAAmBiB,eAAeyC,IAAAA,KAC3E,MAAMrB,GAAGuB,gBAAgB,KAAK7B,WAAW/B,oBAAmBmB,mBAAmBuC,IAAAA;AAElF,YAAIC,UAAU;AAEZ,gBAAMtB,GAAGwB,OAAO,KAAK9B,WAAW4B,QAAAA;AAEhC,iBAAOD;QACT;MACF,CAAA,CAAA;AAEF,aAAOD,MAAMK,OAAOC,MAAAA,EAAQD,OAAO,CAACJ,SAASV,OAAOgB,SAASN,IAAAA,CAAAA;IAC/D,CAAA;EACF;;;;;;;;;EAUA,MAAgBO,2BACd5B,IACAN,WACAmC,WACAzD,KACgD;AAChD,UAAM0D,cAAc9B,GAAG8B,YAAYpC,WAAW,UAAA;AAC9C,UAAMqC,QAAQD,YAAYE,YAAYtC,SAAAA;AACtC,UAAMuC,QAAQF,MAAME,MAAMJ,SAAAA;AAC1B,UAAMK,SAAS,MAAMD,MAAME,WAAW/D,GAAAA;AACtC,QAAI8D,QAAQ;AACV,YAAME,cAAcF,OAAOG;AAE3B,UAAI,OAAOH,OAAOI,eAAe,UAAU;AACzC,cAAM,IAAIC,UAAU,6BAAA;MACtB;AAEA,aAAO;QAACL,OAAOI;QAAYF;;IAC7B;EACF;EAEA,MAAgBI,cACdxC,IACAN,WACA+C,QAAwB,OACxBC,QAAgB,IAChBC,QAC4B;AAC5B,UAAMb,cAAc9B,GAAG8B,YAAYpC,WAAW,UAAA;AAC9C,UAAMqC,QAAQD,YAAYE,YAAYtC,SAAAA;AACtC,UAAMlB,YAAYuD,MAAME,MAAMtE,oBAAmBiB,aAAa;AAC9D,QAAIgE,gBAAgFC;AACpF,QAAIF,QAAQ;AACV,YAAMG,aAAaC,SAAS,MAAMvE,UAAU2D,WAAWQ,MAAAA,GAAS,MAAM,sBAAA;AACtE,YAAMK,kBAAmBF,YAAYR,cAAc;AACnDM,sBAAgB,OAAOH,UAAU,SAC/BV,MAAMI,WAAWc,YAAYC,WAAWF,eAAAA,GAAkB,MAAA,IAC1DjB,MAAMI,WAAWc,YAAYE,WAAWH,eAAAA,GAAkB,MAAA;AAC5D,UAAI,CAACJ,eAAeP;AAAO,eAAO,CAAA;AAClC,YAAMO,eAAeQ,QAAQ,CAAA;IAC/B,OAAO;AACLR,sBAAgB,MAAMb,MAAMI,WAAW,MAAMM,UAAU,SAAS,SAAS,MAAA;AACzE,UAAI,CAACG,eAAeP;AAAO,eAAO,CAAA;IACpC;AAEA,QAAIgB,YAAYX;AAChB,UAAMY,SAA4B,CAAA;AAClC,WAAOD,WAAW;AAChB,YAAMhB,QAAQO,eAAeP;AAC7B,UAAIA,OAAO;AACTiB,eAAOC,KAAKlB,KAAAA;AACZO,wBAAgB,MAAMA,eAAeQ,QAAQ,CAAA;AAC7C,YAAIR,kBAAkB,MAAM;AAC1B;QACF;MACF;AACAS;IACF;AACA,WAAOC;EACT;EAEA,MAAyBxC,WAAWH,QAA8C;AAChF,UAAMb,WAAW,MAAM,KAAKC,MAAM,CAACC,OACjCE,QAAQC,IAAIQ,OAAOP,IAAI,CAACiB,SAAS,KAAKO,2BAA2B5B,IAAI,KAAKN,WAAW/B,oBAAmBiB,eAAeyC,IAAAA,CAAAA,CAAAA,CAAAA;AAEzH,UAAMmC,yBAAyB,MAAM,KAAKzD,MAAM,CAACC,OAC/CE,QAAQC,IAAIQ,OAAOP,IAAI,CAACiB,SAAS,KAAKO,2BAA2B5B,IAAI,KAAKN,WAAW/B,oBAAmBmB,mBAAmBuC,IAAAA,CAAAA,CAAAA,CAAAA;AAG7H,UAAMD,QAAQ,oBAAID,IAAAA;AAClB,UAAMsC,mBAAmB3D,SAAS2B,OAAOC,MAAAA,EAAQD,OAAO,CAAC,CAACiC,MAAMrD,OAAAA,MAAQ;AACtE,UAAIe,MAAMuC,IAAItD,QAAQhC,KAAK,GAAG;AAC5B,eAAO;MACT,OAAO;AACL+C,cAAMwC,IAAIvD,QAAQhC,KAAK;AACvB,eAAO;MACT;IACF,CAAA;AACA,UAAMwF,uBAAuBL,uBAAuB/B,OAAOC,MAAAA,EAAQD,OAAO,CAAC,CAACiC,MAAMrD,OAAAA,MAAQ;AACxF,UAAIe,MAAMuC,IAAItD,QAAQhC,KAAK,GAAG;AAC5B,eAAO;MACT,OAAO;AACL+C,cAAMwC,IAAIvD,QAAQhC,KAAK;AACvB,eAAO;MACT;IACF,CAAA;AACA;;MAEE;WAAIoF;WAAqBI;QAEtBC,KAAK,CAACC,GAAGC,MAAMD,EAAE,CAAA,IAAKC,EAAE,CAAA,CAAE,EAE1B5D,IAAI,CAAC,CAACsD,MAAMrD,OAAAA,MAAaA,OAAAA;;EAEhC;EAEA,MAAyB4D,cAAcnE,UAAiD;AACtF,UAAMc,QAAQ,MAAMN,eAAeO,UAAUf,QAAAA;AAE7C,UAAME,KAAK,MAAM,KAAKkE,iBAAgB;AACtC,QAAI;AAEF,YAAMC,WAAW,MAAMjE,QAAQC,IAC7BS,MAAMR,IAAI,OAAO,CAACC,SAAS5B,KAAAA,MAAM;AAC/B,cAAM6C,YAAY,MAAM,KAAKR,WAAW;UAACrC;SAAM,GAAG2F,MAAK;AACvD,YAAI9C,UAAU;AACZ;QACF;AAIA,cAAM+C,KAAKrE,GAAG8B,YAAY,KAAKpC,WAAW,WAAA;AAC1C,YAAI;AAEF,gBAAMqC,QAAQsC,GAAGrC,YAAY,KAAKtC,SAAS;AAG3C,gBAAM4E,kBAAkB,MAAMvC,MAAME,MAAMtE,oBAAmBiB,aAAa,EAAE2F,IAAI9F,KAAAA;AAEhF,cAAI,CAAC6F,iBAAiB;AAEpB,kBAAMvC,MAAMyC,IAAI;cAAE,GAAGnE;cAAS5B;YAAM,CAAA;UACtC;AAGA,iBAAO4B;QACT,UAAA;AAEE,gBAAMgE,GAAGI;QACX;MACF,CAAA,CAAA;AAEF,aAAON,SAAS1C,OAAOC,MAAAA;IACzB,UAAA;AACE1B,SAAG0E,MAAK;IACV;EACF;EAEA,MAAyBC,YAAYC,SAA4D;AAC/F,UAAM,EAAElC,OAAOC,QAAQF,MAAK,IAAKmC,WAAW,CAAC;AAC7C,WAAO,MAAM,KAAK7E,MAAM,OAAOC,OAAAA;AAC7B,aAAO,MAAM,KAAKwC,cAAcxC,IAAI,KAAKN,WAAW+C,OAAOC,SAAS,IAAIC,MAAAA;IAC1E,CAAA;EACF;EAEA,MAAyBkC,eAAe;AACtC,UAAM,MAAMA,aAAAA;AAGZ,UAAM,KAAK9E,MAAM,MAAA;IAAO,CAAA;AACxB,WAAO;EACT;;;;;EAMA,MAAcmE,mBAAwD;AACpE,UAAM,EAAElF,QAAQG,WAAWQ,SAASD,WAAWoF,OAAM,IAAK;AAC1D,UAAM9E,KAAK,MAAM+E,OAAqB/F,QAAQG,WAAW;MACvD6F,QAAQC,gBAAgBC,gBAAgBC,OAAK;AAC3CL,eAAOM,KAAK,mDAAmDH,cAAAA,OAAqBC,cAAAA,IAAkBC,KAAAA;MACxG;MACAE,SAASJ,gBAAgBC,gBAAgBC,OAAK;AAC5CL,eAAOM,KAAK,6CAA6CH,cAAAA,OAAqBC,cAAAA,IAAkBC,KAAAA;MAClG;MACAG,aAAAA;AACER,eAAOS,IAAI,gCAAA;MACb;MACAC,QAAQC,UAAUC,YAAYC,YAAY7D,aAAW;AAMnD,YAAI4D,eAAeC,YAAY;AAC7Bb,iBAAOS,IAAI,sCAAsCG,UAAAA,OAAiBC,UAAAA,EAAY;AAE9E,gBAAMC,eAAe9D,YAAY+D;AACjC,qBAAW3G,QAAQ0G,cAAc;AAC/B,gBAAI;AACFH,uBAASK,kBAAkB5G,IAAAA;YAC7B,QAAQ;AACN4F,qBAAOS,IAAI,8DAA8DrG,IAAAA,EAAM;YACjF;UACF;QACF;AAEA,cAAM6C,QAAQ0D,SAASM,kBAAkBrG,WAAW;;UAElDsG,eAAe;QACjB,CAAA;AAEAjE,cAAM7C,OAAOQ;AAEb,mBAAW,EAAEtB,KAAKE,YAAYC,OAAM,KAAMoB,SAAS;AACjD,gBAAMsG,YAAYC,OAAOC,KAAK/H,GAAAA;AAC9B,gBAAM+H,OAAOF,UAAUG,WAAW,IAAIH,UAAU,CAAA,IAAKA;AACrD,gBAAMpE,YAAYhD,uBAAuB;YAAET;YAAKG;UAAO,CAAA;AACvDwD,gBAAMsE,YAAYxE,WAAWsE,MAAM;YAAE7H;YAAYC;UAAO,CAAA;QAC1D;MACF;IACF,CAAA;AACA,WAAOyB;EACT;;;;;;EAOA,MAAcD,MAASuG,UAA0E;AAE/F,UAAMtG,KAAK,MAAM,KAAKkE,iBAAgB;AACtC,QAAI;AAEF,aAAO,MAAMoC,SAAStG,EAAAA;IACxB,UAAA;AAEEA,SAAG0E,MAAK;IACV;EACF;AACF;AA1Ua/G,qBAAAA,aAAAA;EADZ4I,gBAAAA;GACY5I,kBAAAA;","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
1
+ {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -199,7 +199,11 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abst
199
199
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
200
200
  if (!primaryCursor?.value)
201
201
  return [];
202
- await primaryCursor?.advance(1);
202
+ try {
203
+ primaryCursor = await primaryCursor?.advance(1);
204
+ } catch {
205
+ return [];
206
+ }
203
207
  } else {
204
208
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
205
209
  if (!primaryCursor?.value)
@@ -211,7 +215,13 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abst
211
215
  const value = primaryCursor?.value;
212
216
  if (value) {
213
217
  result.push(value);
214
- primaryCursor = await primaryCursor?.advance(1);
218
+ try {
219
+ primaryCursor = await primaryCursor?.advance(1);
220
+ } catch {
221
+ if (primaryCursor === null) {
222
+ break;
223
+ }
224
+ }
215
225
  if (primaryCursor === null) {
216
226
  break;
217
227
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
@@ -173,7 +173,11 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
173
173
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
174
174
  if (!primaryCursor?.value)
175
175
  return [];
176
- await primaryCursor?.advance(1);
176
+ try {
177
+ primaryCursor = await primaryCursor?.advance(1);
178
+ } catch {
179
+ return [];
180
+ }
177
181
  } else {
178
182
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
179
183
  if (!primaryCursor?.value)
@@ -185,7 +189,13 @@ var IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
185
189
  const value = primaryCursor?.value;
186
190
  if (value) {
187
191
  result.push(value);
188
- primaryCursor = await primaryCursor?.advance(1);
192
+ try {
193
+ primaryCursor = await primaryCursor?.advance(1);
194
+ } catch {
195
+ if (primaryCursor === null) {
196
+ break;
197
+ }
198
+ }
189
199
  if (primaryCursor === null) {
190
200
  break;
191
201
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
1
+ {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","defaultDbName","defaultDbVersion","defaultStoreName","dataHashIndex","key","$hash","multiEntry","unique","hashIndex","_hash","schemaIndex","schema","hashIndexName","buildStandardIndexName","dataHashIndexName","schemaIndexName","dbName","config","name","dbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","indexes","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","distinctHashes","Set","found","hash","existing","getKeyFromIndex","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","indexKeys","Object","keys","length","createIndex","callback","creatableModule"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cAkCJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
1
+ {"version":3,"file":"Archivist.d.ts","sourceRoot":"","sources":["../../src/Archivist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAKL,wBAAwB,EACxB,oBAAoB,EAIrB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAuB,YAAY,EAAU,MAAM,KAAK,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,qBACa,kBAAkB,CAC7B,OAAO,SAAS,wBAAwB,GAAG,wBAAwB,EACnE,UAAU,SAAS,wBAAwB,GAAG,wBAAwB,CACtE,SAAQ,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA2D;IAC3G,gBAAyB,mBAAmB,EAAE,MAAM,CAAiC;IACrF,MAAM,CAAC,QAAQ,CAAC,aAAa,eAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAI;IACpC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,cAAa;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAA4E;IACjH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA2E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA6E;IAEhH,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAuD;IAEpF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA2D;IAE5F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAyD;IAExF;;;;;;OAMG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,SAAS,WAEZ;IAED,IAAa,OAAO,aASnB;IAED;;;OAGG;IACH,IAAI,SAAS,WAEZ;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;cAEwB,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;cAOxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;cAI7B,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BvE;;;;;;;OAOG;cACa,0BAA0B,CACxC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;cAgBjC,aAAa,CAC3B,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,KAAK,GAAG,MAAc,EAC7B,KAAK,GAAE,MAAW,EAClB,MAAM,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC;cA4CJ,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAmCxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cA0C9D,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;cAOvE,YAAY;IAQrC;;;OAGG;YACW,gBAAgB;IAiD9B;;;;OAIG;YACW,KAAK;CAWpB"}
@@ -173,7 +173,11 @@ var _IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abs
173
173
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
174
174
  if (!(primaryCursor == null ? void 0 : primaryCursor.value))
175
175
  return [];
176
- await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
176
+ try {
177
+ primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
178
+ } catch {
179
+ return [];
180
+ }
177
181
  } else {
178
182
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
179
183
  if (!(primaryCursor == null ? void 0 : primaryCursor.value))
@@ -185,7 +189,13 @@ var _IndexedDbArchivist = class _IndexedDbArchivist extends import_archivist_abs
185
189
  const value = primaryCursor == null ? void 0 : primaryCursor.value;
186
190
  if (value) {
187
191
  result.push(value);
188
- primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
192
+ try {
193
+ primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
194
+ } catch {
195
+ if (primaryCursor === null) {
196
+ break;
197
+ }
198
+ }
189
199
  if (primaryCursor === null) {
190
200
  break;
191
201
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","dbName","config","name","defaultDbName","dbVersion","defaultDbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","defaultStoreName","indexes","dataHashIndex","hashIndex","schemaIndex","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","$hash","distinctHashes","Set","found","hash","existing","getKeyFromIndex","hashIndexName","dataHashIndexName","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","key","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","_hash","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","multiEntry","unique","indexKeys","Object","keys","length","buildStandardIndexName","createIndex","callback","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","schema","schemaIndexName","creatableModule"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["export * from './Archivist'\nexport * from './Config'\nexport * from './Params'\nexport * from './Schema'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","dbName","config","name","defaultDbName","dbVersion","defaultDbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","defaultStoreName","indexes","dataHashIndex","hashIndex","schemaIndex","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","$hash","distinctHashes","Set","found","hash","existing","getKeyFromIndex","hashIndexName","dataHashIndexName","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","key","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","_hash","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","multiEntry","unique","indexKeys","Object","keys","length","buildStandardIndexName","createIndex","callback","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","schema","schemaIndexName","creatableModule"]}
@@ -147,7 +147,11 @@ var _IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
147
147
  primaryCursor = await (order === "desc" ? store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), "prev") : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), "next"));
148
148
  if (!(primaryCursor == null ? void 0 : primaryCursor.value))
149
149
  return [];
150
- await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
150
+ try {
151
+ primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
152
+ } catch {
153
+ return [];
154
+ }
151
155
  } else {
152
156
  primaryCursor = await store.openCursor(null, order === "desc" ? "prev" : "next");
153
157
  if (!(primaryCursor == null ? void 0 : primaryCursor.value))
@@ -159,7 +163,13 @@ var _IndexedDbArchivist = class _IndexedDbArchivist extends AbstractArchivist {
159
163
  const value = primaryCursor == null ? void 0 : primaryCursor.value;
160
164
  if (value) {
161
165
  result.push(value);
162
- primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
166
+ try {
167
+ primaryCursor = await (primaryCursor == null ? void 0 : primaryCursor.advance(1));
168
+ } catch {
169
+ if (primaryCursor === null) {
170
+ break;
171
+ }
172
+ }
163
173
  if (primaryCursor === null) {
164
174
  break;
165
175
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n await primaryCursor?.advance(1) //advance to skip the offset value\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n primaryCursor = await primaryCursor?.advance(1)\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","dbName","config","name","defaultDbName","dbVersion","defaultDbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","defaultStoreName","indexes","dataHashIndex","hashIndex","schemaIndex","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","$hash","distinctHashes","Set","found","hash","existing","getKeyFromIndex","hashIndexName","dataHashIndexName","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","key","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","_hash","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","multiEntry","unique","indexKeys","Object","keys","length","buildStandardIndexName","createIndex","callback","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","schema","schemaIndexName","creatableModule"]}
1
+ {"version":3,"sources":["../../src/Archivist.ts","../../src/Schema.ts","../../src/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractArchivist } from '@xyo-network/archivist-abstract'\nimport {\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ArchivistModuleEventData,\n ArchivistNextOptions,\n ArchivistNextQuerySchema,\n buildStandardIndexName,\n IndexDescription,\n} from '@xyo-network/archivist-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload, PayloadWithMeta, Schema } from '@xyo-network/payload-model'\nimport { IDBPCursorWithValue, IDBPDatabase, openDB } from 'idb'\n\nimport { IndexedDbArchivistConfigSchema } from './Config'\nimport { IndexedDbArchivistParams } from './Params'\n\nexport interface PayloadStore {\n [s: string]: Payload\n}\n\n@creatableModule()\nexport class IndexedDbArchivist<\n TParams extends IndexedDbArchivistParams = IndexedDbArchivistParams,\n TEventData extends ArchivistModuleEventData = ArchivistModuleEventData,\n> extends AbstractArchivist<TParams, TEventData> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbArchivistConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbArchivistConfigSchema\n static readonly defaultDbName = 'archivist'\n static readonly defaultDbVersion = 1\n static readonly defaultStoreName = 'payloads'\n private static readonly dataHashIndex: IndexDescription = { key: { $hash: 1 }, multiEntry: false, unique: false }\n private static readonly hashIndex: IndexDescription = { key: { _hash: 1 }, multiEntry: false, unique: true }\n private static readonly schemaIndex: IndexDescription = { key: { schema: 1 }, multiEntry: false, unique: false }\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly hashIndexName = buildStandardIndexName(IndexedDbArchivist.hashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly dataHashIndexName = buildStandardIndexName(IndexedDbArchivist.dataHashIndex)\n // eslint-disable-next-line @typescript-eslint/member-ordering\n static readonly schemaIndexName = buildStandardIndexName(IndexedDbArchivist.schemaIndex)\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the module name (not guaranteed to be unique) and if module\n * name is not supplied, it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.name ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to 1.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n override get queries() {\n return [\n ArchivistNextQuerySchema,\n ArchivistAllQuerySchema,\n ArchivistClearQuerySchema,\n ArchivistDeleteQuerySchema,\n ArchivistInsertQuerySchema,\n ...super.queries,\n ]\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n /**\n * The indexes to create on the store\n */\n private get indexes() {\n return [IndexedDbArchivist.dataHashIndex, IndexedDbArchivist.hashIndex, IndexedDbArchivist.schemaIndex, ...(this.config?.storage?.indexes ?? [])]\n }\n\n protected override async allHandler(): Promise<PayloadWithMeta[]> {\n // Get all payloads from the store\n const payloads = await this.useDb((db) => db.getAll(this.storeName))\n // Remove any metadata before returning to the client\n return await Promise.all(payloads.map((payload) => PayloadBuilder.build(payload)))\n }\n\n protected override async clearHandler(): Promise<void> {\n await this.useDb((db) => db.clear(this.storeName))\n }\n\n protected override async deleteHandler(hashes: Hash[]): Promise<Hash[]> {\n const pairs = await PayloadBuilder.hashPairs(await this.getHandler(hashes))\n const hashesToDelete = pairs.flatMap<Hash>((pair) => [pair[0].$hash, pair[1]])\n // Remove any duplicates\n const distinctHashes = [...new Set(hashesToDelete)]\n return await this.useDb(async (db) => {\n // Only return hashes that were successfully deleted\n const found = await Promise.all(\n distinctHashes.map(async (hash) => {\n // Check if the hash exists\n const existing =\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.hashIndexName, hash)) ??\n (await db.getKeyFromIndex(this.storeName, IndexedDbArchivist.dataHashIndexName, hash))\n // If it does exist\n if (existing) {\n // Delete it\n await db.delete(this.storeName, existing)\n // Return the hash so it gets added to the list of deleted hashes\n return hash\n }\n }),\n )\n return found.filter(exists).filter((hash) => hashes.includes(hash))\n })\n }\n\n /**\n * Uses an index to get a payload by the index value, but returns the value with the primary key (from the root store)\n * @param db The db instance to use\n * @param storeName The name of the store to use\n * @param indexName The index to use\n * @param key The key to get from the index\n * @returns The primary key and the payload, or undefined if not found\n */\n protected async getFromIndexWithPrimaryKey(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n indexName: string,\n key: IDBValidKey,\n ): Promise<[number, PayloadWithMeta] | undefined> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const index = store.index(indexName)\n const cursor = await index.openCursor(key)\n if (cursor) {\n const singleValue = cursor.value\n // NOTE: It's known to be a number because we are using IndexedDB supplied auto-incrementing keys\n if (typeof cursor.primaryKey !== 'number') {\n throw new TypeError('primaryKey must be a number')\n }\n\n return [cursor.primaryKey, singleValue]\n }\n }\n\n protected async getFromOffset(\n db: IDBPDatabase<PayloadStore>,\n storeName: string,\n order: 'asc' | 'desc' = 'asc',\n limit: number = 10,\n offset?: Hash,\n ): Promise<PayloadWithMeta[]> {\n const transaction = db.transaction(storeName, 'readonly')\n const store = transaction.objectStore(storeName)\n const hashIndex = store.index(IndexedDbArchivist.hashIndexName)\n let primaryCursor: IDBPCursorWithValue<PayloadStore, [string]> | null | undefined = undefined\n if (offset) {\n const hashCursor = assertEx(await hashIndex.openCursor(offset), () => 'Failed to get cursor')\n const startPrimaryKey = (hashCursor?.primaryKey ?? 0) as number //we know the primary key is a number and starts at 1\n primaryCursor = await (order === 'desc' ?\n store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')\n : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))\n if (!primaryCursor?.value) return []\n try {\n primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value\n } catch {\n return []\n }\n } else {\n primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')\n if (!primaryCursor?.value) return []\n }\n\n let remaining = limit\n const result: PayloadWithMeta[] = []\n while (remaining) {\n const value = primaryCursor?.value\n if (value) {\n result.push(value)\n try {\n primaryCursor = await primaryCursor?.advance(1)\n } catch {\n if (primaryCursor === null) {\n break\n }\n }\n if (primaryCursor === null) {\n break\n }\n }\n remaining--\n }\n return result\n }\n\n protected override async getHandler(hashes: string[]): Promise<PayloadWithMeta[]> {\n const payloads = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.hashIndexName, hash))),\n )\n const payloadsFromDataHashes = await this.useDb((db) =>\n Promise.all(hashes.map((hash) => this.getFromIndexWithPrimaryKey(db, this.storeName, IndexedDbArchivist.dataHashIndexName, hash))),\n )\n //filter out duplicates\n const found = new Set<string>()\n const payloadsFromHash = payloads.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n const payloadsFromDataHash = payloadsFromDataHashes.filter(exists).filter(([_key, payload]) => {\n if (found.has(payload.$hash)) {\n return false\n } else {\n found.add(payload.$hash)\n return true\n }\n })\n return (\n // Merge what we found from the hash and data hash indexes\n [...payloadsFromHash, ...payloadsFromDataHash]\n // Sort in ascending order by primary key (for semi-predictable ordering in terms of insertion order)\n .sort((a, b) => a[0] - b[0])\n // Return just the payloads\n .map(([_key, payload]) => payload)\n )\n }\n\n protected override async insertHandler(payloads: Payload[]): Promise<PayloadWithMeta[]> {\n const pairs = await PayloadBuilder.hashPairs(payloads)\n\n const db = await this.getInitializedDb()\n try {\n // Only return the payloads that were successfully inserted\n const inserted = await Promise.all(\n pairs.map(async ([payload, _hash]) => {\n const existing = (await this.getHandler([_hash])).shift()\n if (existing) {\n return\n }\n // Perform each insert via a transaction to ensure it is atomic\n // with respect to checking for the pre-existence of the hash.\n // This is done to preserve iteration via insertion order.\n const tx = db.transaction(this.storeName, 'readwrite')\n try {\n // Get the object store\n const store = tx.objectStore(this.storeName)\n\n // Check if the hash already exists\n const existingTopHash = await store.index(IndexedDbArchivist.hashIndexName).get(_hash)\n // If it does not already exist\n if (!existingTopHash) {\n // Insert the payload\n await store.put({ ...payload, _hash })\n }\n\n // Return it so it gets added to the list of inserted payloads\n return payload\n } finally {\n // Close the transaction\n await tx.done\n }\n }),\n )\n return inserted.filter(exists)\n } finally {\n db.close()\n }\n }\n\n protected override async nextHandler(options?: ArchivistNextOptions): Promise<PayloadWithMeta[]> {\n const { limit, offset, order } = options ?? {}\n return await this.useDb(async (db) => {\n return await this.getFromOffset(db, this.storeName, order, limit ?? 10, offset)\n })\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: We could defer this creation to first access but we\n // want to fail fast here in case something is wrong\n await this.useDb(() => {})\n return true\n }\n\n /**\n * Returns that the desired DB/Store initialized to the correct version\n * @returns The initialized DB\n */\n private async getInitializedDb(): Promise<IDBPDatabase<PayloadStore>> {\n const { dbName, dbVersion, indexes, storeName, logger } = this\n const db = await openDB<PayloadStore>(dbName, dbVersion, {\n blocked(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocked from upgrading from ${currentVersion} to ${blockedVersion}`, event)\n },\n blocking(currentVersion, blockedVersion, event) {\n logger.warn(`IndexedDbArchivist: Blocking upgrade from ${currentVersion} to ${blockedVersion}`, event)\n },\n terminated() {\n logger.log('IndexedDbArchivist: Terminated')\n },\n upgrade(database, oldVersion, newVersion, transaction) {\n // NOTE: This is called whenever the DB is created/updated. We could simply ensure the desired end\n // state but, out of an abundance of caution, we will just delete (so we know where we are starting\n // from a known good point) and recreate the desired state. This prioritizes resilience over data\n // retention but we can revisit that tradeoff when it becomes limiting. Because distributed browser\n // state is extremely hard to debug, this seems like fair tradeoff for now.\n if (oldVersion !== newVersion) {\n logger.log(`IndexedDbArchivist: Upgrading from ${oldVersion} to ${newVersion}`)\n // Delete any existing databases that are not the current version\n const objectStores = transaction.objectStoreNames\n for (const name of objectStores) {\n try {\n database.deleteObjectStore(name)\n } catch {\n logger.log(`IndexedDbArchivist: Failed to delete existing object store ${name}`)\n }\n }\n }\n // Create the store\n const store = database.createObjectStore(storeName, {\n // If it isn't explicitly set, create a value by auto incrementing.\n autoIncrement: true,\n })\n // Name the store\n store.name = storeName\n // Create an index on the hash\n for (const { key, multiEntry, unique } of indexes) {\n const indexKeys = Object.keys(key)\n const keys = indexKeys.length === 1 ? indexKeys[0] : indexKeys\n const indexName = buildStandardIndexName({ key, unique })\n store.createIndex(indexName, keys, { multiEntry, unique })\n }\n },\n })\n return db\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async useDb<T>(callback: (db: IDBPDatabase<PayloadStore>) => Promise<T> | T): Promise<T> {\n // Get the initialized DB\n const db = await this.getInitializedDb()\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n}\n","export type IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\nexport const IndexedDbArchivistSchema: IndexedDbArchivistSchema = 'network.xyo.archivist.indexeddb'\n","import { ArchivistConfig, IndexDescription } from '@xyo-network/archivist-model'\n\nimport { IndexedDbArchivistSchema } from './Schema'\n\nexport type IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\nexport const IndexedDbArchivistConfigSchema: IndexedDbArchivistConfigSchema = `${IndexedDbArchivistSchema}.config`\n\nexport type IndexedDbArchivistConfig = ArchivistConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbArchivistConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main archivist config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n"],"mappings":"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","names":["assertEx","exists","AbstractArchivist","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","ArchivistNextQuerySchema","buildStandardIndexName","creatableModule","PayloadBuilder","openDB","IndexedDbArchivistSchema","IndexedDbArchivistConfigSchema","IndexedDbArchivistSchema","IndexedDbArchivist","AbstractArchivist","dbName","config","name","defaultDbName","dbVersion","defaultDbVersion","queries","ArchivistNextQuerySchema","ArchivistAllQuerySchema","ArchivistClearQuerySchema","ArchivistDeleteQuerySchema","ArchivistInsertQuerySchema","storeName","defaultStoreName","indexes","dataHashIndex","hashIndex","schemaIndex","storage","allHandler","payloads","useDb","db","getAll","Promise","all","map","payload","PayloadBuilder","build","clearHandler","clear","deleteHandler","hashes","pairs","hashPairs","getHandler","hashesToDelete","flatMap","pair","$hash","distinctHashes","Set","found","hash","existing","getKeyFromIndex","hashIndexName","dataHashIndexName","delete","filter","exists","includes","getFromIndexWithPrimaryKey","indexName","key","transaction","store","objectStore","index","cursor","openCursor","singleValue","value","primaryKey","TypeError","getFromOffset","order","limit","offset","primaryCursor","undefined","hashCursor","assertEx","startPrimaryKey","IDBKeyRange","upperBound","lowerBound","advance","remaining","result","push","payloadsFromDataHashes","payloadsFromHash","_key","has","add","payloadsFromDataHash","sort","a","b","insertHandler","getInitializedDb","inserted","_hash","shift","tx","existingTopHash","get","put","done","close","nextHandler","options","startHandler","logger","openDB","blocked","currentVersion","blockedVersion","event","warn","blocking","terminated","log","upgrade","database","oldVersion","newVersion","objectStores","objectStoreNames","deleteObjectStore","createObjectStore","autoIncrement","multiEntry","unique","indexKeys","Object","keys","length","buildStandardIndexName","createIndex","callback","configSchemas","IndexedDbArchivistConfigSchema","defaultConfigSchema","schema","schemaIndexName","creatableModule"]}
package/package.json CHANGED
@@ -10,22 +10,23 @@
10
10
  "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/issues"
11
11
  },
12
12
  "dependencies": {
13
+ "@xylabs/assert": "^3.3.3",
13
14
  "@xylabs/exists": "^3.3.3",
14
15
  "@xylabs/hex": "^3.3.3",
15
- "@xyo-network/archivist-abstract": "~2.102.3",
16
- "@xyo-network/archivist-model": "~2.102.3",
17
- "@xyo-network/module-model": "~2.102.3",
18
- "@xyo-network/payload-builder": "~2.102.3",
19
- "@xyo-network/payload-model": "~2.102.3",
16
+ "@xyo-network/archivist-abstract": "~2.102.4",
17
+ "@xyo-network/archivist-model": "~2.102.4",
18
+ "@xyo-network/module-model": "~2.102.4",
19
+ "@xyo-network/payload-builder": "~2.102.4",
20
+ "@xyo-network/payload-model": "~2.102.4",
20
21
  "idb": "^8.0.0"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@xylabs/object": "^3.3.3",
24
25
  "@xylabs/ts-scripts-yarn3": "^3.10.4",
25
26
  "@xylabs/tsconfig": "^3.10.4",
26
- "@xyo-network/account": "~2.102.3",
27
- "@xyo-network/id-payload-plugin": "~2.102.3",
28
- "@xyo-network/payload-wrapper": "~2.102.3",
27
+ "@xyo-network/account": "~2.102.4",
28
+ "@xyo-network/id-payload-plugin": "~2.102.4",
29
+ "@xyo-network/payload-wrapper": "~2.102.4",
29
30
  "fake-indexeddb": "^5.0.2",
30
31
  "typescript": "^5.4.5"
31
32
  },
@@ -68,6 +69,6 @@
68
69
  "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js.git"
69
70
  },
70
71
  "sideEffects": false,
71
- "version": "2.102.3",
72
+ "version": "2.102.4",
72
73
  "type": "module"
73
74
  }
package/src/Archivist.ts CHANGED
@@ -173,7 +173,11 @@ export class IndexedDbArchivist<
173
173
  store.openCursor(IDBKeyRange.upperBound(startPrimaryKey), 'prev')
174
174
  : store.openCursor(IDBKeyRange.lowerBound(startPrimaryKey), 'next'))
175
175
  if (!primaryCursor?.value) return []
176
- await primaryCursor?.advance(1) //advance to skip the offset value
176
+ try {
177
+ primaryCursor = await primaryCursor?.advance(1) //advance to skip the offset value
178
+ } catch {
179
+ return []
180
+ }
177
181
  } else {
178
182
  primaryCursor = await store.openCursor(null, order === 'desc' ? 'prev' : 'next')
179
183
  if (!primaryCursor?.value) return []
@@ -185,7 +189,13 @@ export class IndexedDbArchivist<
185
189
  const value = primaryCursor?.value
186
190
  if (value) {
187
191
  result.push(value)
188
- primaryCursor = await primaryCursor?.advance(1)
192
+ try {
193
+ primaryCursor = await primaryCursor?.advance(1)
194
+ } catch {
195
+ if (primaryCursor === null) {
196
+ break
197
+ }
198
+ }
189
199
  if (primaryCursor === null) {
190
200
  break
191
201
  }