@wovin/storage-fs 0.0.26 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- import type { Applog, CidString } from '@wovin/core/applog';
1
+ import { BlockStoreish, Applog, CidString } from '@wovin/core';
2
2
  import { CID } from 'multiformats/cid';
3
- export declare class StorageFs {
3
+
4
+ /**
5
+ * File-system based storage using LMDB.
6
+ * Implements BlockStoreish for use with wovin snapshot chain walking.
7
+ */
8
+ declare class StorageFs implements BlockStoreish {
4
9
  private root;
5
10
  private applogs;
6
11
  private threadIndex;
@@ -14,11 +19,16 @@ export declare class StorageFs {
14
19
  storeBlock(cid: CID | CidString, bytes: Uint8Array): Promise<void>;
15
20
  getBlock(cid: CID | CidString): Uint8Array | null;
16
21
  hasBlock(cid: CID | CidString): boolean;
22
+ /**
23
+ * Get a block by CID (BlockStoreish interface).
24
+ * Throws if block not found.
25
+ */
26
+ get(cid: CID): Promise<Uint8Array>;
17
27
  listThreads(): string[];
18
28
  deleteThread(threadId: string): Promise<void>;
19
29
  getThreadApplogCount(threadId: string): number;
20
30
  isApplogInThread(threadId: string, cid: CID | CidString): boolean;
21
31
  close(): void;
22
32
  }
23
- export { StorageFs as LmdbConnector };
24
- //# sourceMappingURL=index.d.ts.map
33
+
34
+ export { StorageFs as LmdbConnector, StorageFs };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE3D,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAItC,qBAAa,SAAS;IACrB,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAA8B;WAE/B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAsBnD,OAAO;IAcD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BxE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IActC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI;IAOnD,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAOlC,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxE,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI;IAMjD,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAOvC,WAAW,IAAI,MAAM,EAAE;IASjB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI9C,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAKjE,KAAK,IAAI,IAAI;CAGb;AAGD,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAItC;;;GAGG;AACH,qBAAa,SAAU,YAAW,aAAa;IAC9C,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAA8B;WAE/B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAmCnD,OAAO;IAcD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAsDxE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IActC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI;IAOnD,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAOlC,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxE,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI;IAMjD,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAKvC;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAUlC,WAAW,IAAI,MAAM,EAAE;IASjB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI9C,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,OAAO;IAKjE,KAAK,IAAI,IAAI;CAGb;AAGD,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,CAAA"}
package/dist/index.min.js CHANGED
@@ -1,2 +1,2 @@
1
- import{open as p}from"lmdb";import{Logger as e}from"besonders-logger";var{DEBUG:i,VERBOSE:u,ERROR:S}=e.setup(e.INFO),a=class g{root;applogs;threadIndex;blocks;static async init(t){let s=p({path:t,compression:!0}),r=s.openDB({name:"applogs"}),n=s.openDB({name:"thread_index",dupSort:!0}),o=s.openDB({name:"blocks"});return new g(s,r,n,o)}constructor(t,s,r,n){this.root=t,this.applogs=s,this.threadIndex=r,this.blocks=n}async storeApplogs(t,s){let r=0;return await this.root.transaction(()=>{for(let n of s){let o=n.cid;if(this.applogs.doesExist(o)){this.threadIndex.doesExist(t,o)||this.threadIndex.put(t,o);continue}this.applogs.put(o,JSON.stringify(n)),this.threadIndex.put(t,o),r++}}),i(`[StorageFs] Stored ${r} applogs in thread "${t}"`),r}getApplogs(t){let s=[],r=this.threadIndex.getValues(t);for(let n of r){let o=this.applogs.get(n);o&&s.push(JSON.parse(o))}return s}getApplogByCid(t){let s=typeof t=="string"?t:t.toString(),r=this.applogs.get(s);return r?JSON.parse(r):null}hasApplog(t){let s=typeof t=="string"?t:t.toString();return this.applogs.doesExist(s)}async storeBlock(t,s){let r=typeof t=="string"?t:t.toString();await this.blocks.put(r,s)}getBlock(t){let s=typeof t=="string"?t:t.toString();return this.blocks.get(s)??null}hasBlock(t){let s=typeof t=="string"?t:t.toString();return this.blocks.doesExist(s)}listThreads(){let t=new Set;for(let{key:s}of this.threadIndex.getRange({}))t.add(s);return Array.from(t)}async deleteThread(t){await this.root.transaction(()=>{let s=Array.from(this.threadIndex.getValues(t));for(let r of s)this.threadIndex.remove(t,r)}),i(`[StorageFs] Deleted thread "${t}"`)}getThreadApplogCount(t){return this.threadIndex.getValuesCount(t)}isApplogInThread(t,s){let r=typeof s=="string"?s:s.toString();return this.threadIndex.doesExist(t,r)}close(){this.root.close()}};export{a as LmdbConnector,a as StorageFs};
1
+ import{open as S}from"lmdb";import{Logger as l}from"besonders-logger";const{DEBUG:s,VERBOSE:y,ERROR:d}=l.setup(l.INFO);class c{root;applogs;threadIndex;blocks;static async init(t){s(`[StorageFs.init] ENTER - path=${t}`),s("[StorageFs.init] Opening LMDB root database");const o=S({path:t,compression:!0});s("[StorageFs.init] LMDB root database opened"),s("[StorageFs.init] Opening applogs DB");const r=o.openDB({name:"applogs"});s("[StorageFs.init] Applogs DB opened"),s("[StorageFs.init] Opening threadIndex DB");const e=o.openDB({name:"thread_index",dupSort:!0});s("[StorageFs.init] ThreadIndex DB opened"),s("[StorageFs.init] Opening blocks DB");const n=o.openDB({name:"blocks"});s("[StorageFs.init] Blocks DB opened"),s("[StorageFs.init] Creating StorageFs instance");const p=new c(o,r,e,n);return s("[StorageFs.init] EXIT - StorageFs instance created successfully"),p}constructor(t,o,r,e){this.root=t,this.applogs=o,this.threadIndex=r,this.blocks=e}async storeApplogs(t,o){const r=Date.now();s("[StorageFs.storeApplogs] ===== ENTER ====="),s(`[StorageFs.storeApplogs] threadId: ${t}`),s(`[StorageFs.storeApplogs] applogs.length: ${o.length}`);let e=0;s("[StorageFs.storeApplogs] About to start transaction");const n=Date.now();try{this.root.transactionSync(()=>{for(const g of o){const i=g.cid;if(this.applogs.doesExist(i)){this.threadIndex.doesExist(t,i)||this.threadIndex.put(t,i);continue}this.applogs.put(i,JSON.stringify(g)),this.threadIndex.put(t,i),e++}});const a=Date.now()-n;s(`[StorageFs.storeApplogs] Transaction completed in ${a}ms`)}catch(a){const g=Date.now()-n;throw d(`[StorageFs.storeApplogs] Transaction error after ${g}ms:`,a),a}const p=Date.now()-r;return s(`[StorageFs.storeApplogs] ===== SUCCESS in ${p}ms, stored ${e} applogs`),e}getApplogs(t){const o=[],r=this.threadIndex.getValues(t);for(const e of r){const n=this.applogs.get(e);n&&o.push(JSON.parse(n))}return o}getApplogByCid(t){const o=typeof t=="string"?t:t.toString(),r=this.applogs.get(o);return r?JSON.parse(r):null}hasApplog(t){const o=typeof t=="string"?t:t.toString();return this.applogs.doesExist(o)}async storeBlock(t,o){const r=typeof t=="string"?t:t.toString();await this.blocks.put(r,o)}getBlock(t){const o=typeof t=="string"?t:t.toString();return this.blocks.get(o)??null}hasBlock(t){const o=typeof t=="string"?t:t.toString();return this.blocks.doesExist(o)}get(t){const o=this.getBlock(t);return o?Promise.resolve(o):Promise.reject(new Error(`Block not found: ${t.toString()}`))}listThreads(){const t=new Set;for(const{key:o}of this.threadIndex.getRange({}))t.add(o);return Array.from(t)}async deleteThread(t){this.root.transactionSync(()=>{const o=Array.from(this.threadIndex.getValues(t));for(const r of o)this.threadIndex.remove(t,r)}),s(`[StorageFs] Deleted thread "${t}"`)}getThreadApplogCount(t){return this.threadIndex.getValuesCount(t)}isApplogInThread(t,o){const r=typeof o=="string"?o:o.toString();return this.threadIndex.doesExist(t,r)}close(){this.root.close()}}export{c as LmdbConnector,c as StorageFs};
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { open, RootDatabase, Database } from 'lmdb'\nimport type { Applog, CidString } from '@wovin/core/applog'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats/cid'\n\nconst { DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO)\n\nexport class StorageFs {\n\tprivate root: RootDatabase\n\tprivate applogs: Database<string, string> // cidString → Applog JSON\n\tprivate threadIndex: Database<string, string> // threadId → cidString (dupSort)\n\tprivate blocks: Database<Uint8Array, string> // cidString → bytes\n\n\tstatic async init(path: string): Promise<StorageFs> {\n\t\tconst root = open({\n\t\t\tpath,\n\t\t\tcompression: true,\n\t\t})\n\n\t\tconst applogs = root.openDB<string, string>({\n\t\t\tname: 'applogs',\n\t\t})\n\n\t\tconst threadIndex = root.openDB<string, string>({\n\t\t\tname: 'thread_index',\n\t\t\tdupSort: true,\n\t\t})\n\n\t\tconst blocks = root.openDB<Uint8Array, string>({\n\t\t\tname: 'blocks',\n\t\t})\n\n\t\treturn new StorageFs(root, applogs, threadIndex, blocks)\n\t}\n\n\tprivate constructor(\n\t\troot: RootDatabase,\n\t\tapplogs: Database<string, string>,\n\t\tthreadIndex: Database<string, string>,\n\t\tblocks: Database<Uint8Array, string>,\n\t) {\n\t\tthis.root = root\n\t\tthis.applogs = applogs\n\t\tthis.threadIndex = threadIndex\n\t\tthis.blocks = blocks\n\t}\n\n\t// === Applogs ===\n\n\tasync storeApplogs(threadId: string, applogs: Applog[]): Promise<number> {\n\t\tlet stored = 0\n\n\t\tawait this.root.transaction(() => {\n\t\t\tfor (const applog of applogs) {\n\t\t\t\tconst cidStr = applog.cid\n\n\t\t\t\t// Check if already stored (dedup by CID)\n\t\t\t\tif (this.applogs.doesExist(cidStr)) {\n\t\t\t\t\t// Applog exists, but still add to thread index if not already there\n\t\t\t\t\tif (!this.threadIndex.doesExist(threadId, cidStr)) {\n\t\t\t\t\t\tthis.threadIndex.put(threadId, cidStr)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Store applog\n\t\t\t\tthis.applogs.put(cidStr, JSON.stringify(applog))\n\n\t\t\t\t// Add to thread index\n\t\t\t\tthis.threadIndex.put(threadId, cidStr)\n\n\t\t\t\tstored++\n\t\t\t}\n\t\t})\n\n\t\tDEBUG(`[StorageFs] Stored ${stored} applogs in thread \"${threadId}\"`)\n\t\treturn stored\n\t}\n\n\tgetApplogs(threadId: string): Applog[] {\n\t\tconst applogs: Applog[] = []\n\t\tconst cidStrings = this.threadIndex.getValues(threadId)\n\n\t\tfor (const cidStr of cidStrings) {\n\t\t\tconst json = this.applogs.get(cidStr)\n\t\t\tif (json) {\n\t\t\t\tapplogs.push(JSON.parse(json))\n\t\t\t}\n\t\t}\n\n\t\treturn applogs\n\t}\n\n\tgetApplogByCid(cid: CID | CidString): Applog | null {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tconst json = this.applogs.get(cidStr)\n\t\tif (!json) return null\n\t\treturn JSON.parse(json)\n\t}\n\n\thasApplog(cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.applogs.doesExist(cidStr)\n\t}\n\n\t// === Blocks ===\n\n\tasync storeBlock(cid: CID | CidString, bytes: Uint8Array): Promise<void> {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tawait this.blocks.put(cidStr, bytes)\n\t}\n\n\tgetBlock(cid: CID | CidString): Uint8Array | null {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tconst bytes = this.blocks.get(cidStr)\n\t\treturn bytes ?? null\n\t}\n\n\thasBlock(cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.blocks.doesExist(cidStr)\n\t}\n\n\t// === Threads ===\n\n\tlistThreads(): string[] {\n\t\tconst threads = new Set<string>()\n\t\t// Iterate over all keys in thread_index\n\t\tfor (const { key } of this.threadIndex.getRange({})) {\n\t\t\tthreads.add(key)\n\t\t}\n\t\treturn Array.from(threads)\n\t}\n\n\tasync deleteThread(threadId: string): Promise<void> {\n\t\tawait this.root.transaction(() => {\n\t\t\t// Get all CIDs in this thread\n\t\t\tconst cidStrings = Array.from(this.threadIndex.getValues(threadId))\n\n\t\t\t// Remove all entries for this thread from index\n\t\t\tfor (const cidStr of cidStrings) {\n\t\t\t\tthis.threadIndex.remove(threadId, cidStr)\n\t\t\t}\n\n\t\t\t// Note: We don't delete the applogs themselves - they may be in other threads\n\t\t\t// Orphan cleanup could be a separate maintenance operation\n\t\t})\n\n\t\tDEBUG(`[StorageFs] Deleted thread \"${threadId}\"`)\n\t}\n\n\t// === Utilities ===\n\n\tgetThreadApplogCount(threadId: string): number {\n\t\treturn this.threadIndex.getValuesCount(threadId)\n\t}\n\n\tisApplogInThread(threadId: string, cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.threadIndex.doesExist(threadId, cidStr)\n\t}\n\n\tclose(): void {\n\t\tthis.root.close()\n\t}\n}\n\n// Re-export for backwards compatibility during transition\nexport { StorageFs as LmdbConnector }\n"],"mappings":"AAAA,OAAS,QAAAA,MAAoC,OAE7C,OAAS,UAAAC,MAAc,mBAGvB,GAAM,CAAE,MAAAC,EAAO,QAAAC,EAAS,MAAAC,CAAM,EAAIH,EAAO,MAAMA,EAAO,IAAI,EAE7CI,EAAN,MAAMC,CAAU,CACd,KACA,QACA,YACA,OAER,aAAa,KAAKC,EAAkC,CACnD,IAAMC,EAAOR,EAAK,CACjB,KAAAO,EACA,YAAa,EACd,CAAC,EAEKE,EAAUD,EAAK,OAAuB,CAC3C,KAAM,SACP,CAAC,EAEKE,EAAcF,EAAK,OAAuB,CAC/C,KAAM,eACN,QAAS,EACV,CAAC,EAEKG,EAASH,EAAK,OAA2B,CAC9C,KAAM,QACP,CAAC,EAED,OAAO,IAAIF,EAAUE,EAAMC,EAASC,EAAaC,CAAM,CACxD,CAEQ,YACPH,EACAC,EACAC,EACAC,EACC,CACD,KAAK,KAAOH,EACZ,KAAK,QAAUC,EACf,KAAK,YAAcC,EACnB,KAAK,OAASC,CACf,CAIA,MAAM,aAAaC,EAAkBH,EAAoC,CACxE,IAAII,EAAS,EAEb,aAAM,KAAK,KAAK,YAAY,IAAM,CACjC,QAAWC,KAAUL,EAAS,CAC7B,IAAMM,EAASD,EAAO,IAGtB,GAAI,KAAK,QAAQ,UAAUC,CAAM,EAAG,CAE9B,KAAK,YAAY,UAAUH,EAAUG,CAAM,GAC/C,KAAK,YAAY,IAAIH,EAAUG,CAAM,EAEtC,QACD,CAGA,KAAK,QAAQ,IAAIA,EAAQ,KAAK,UAAUD,CAAM,CAAC,EAG/C,KAAK,YAAY,IAAIF,EAAUG,CAAM,EAErCF,GACD,CACD,CAAC,EAEDX,EAAM,sBAAsBW,CAAM,uBAAuBD,CAAQ,GAAG,EAC7DC,CACR,CAEA,WAAWD,EAA4B,CACtC,IAAMH,EAAoB,CAAC,EACrBO,EAAa,KAAK,YAAY,UAAUJ,CAAQ,EAEtD,QAAWG,KAAUC,EAAY,CAChC,IAAMC,EAAO,KAAK,QAAQ,IAAIF,CAAM,EAChCE,GACHR,EAAQ,KAAK,KAAK,MAAMQ,CAAI,CAAC,CAE/B,CAEA,OAAOR,CACR,CAEA,eAAeS,EAAqC,CACnD,IAAMH,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EACtDD,EAAO,KAAK,QAAQ,IAAIF,CAAM,EACpC,OAAKE,EACE,KAAK,MAAMA,CAAI,EADJ,IAEnB,CAEA,UAAUC,EAA+B,CACxC,IAAMH,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAC5D,OAAO,KAAK,QAAQ,UAAUH,CAAM,CACrC,CAIA,MAAM,WAAWG,EAAsBC,EAAkC,CACxE,IAAMJ,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAC5D,MAAM,KAAK,OAAO,IAAIH,EAAQI,CAAK,CACpC,CAEA,SAASD,EAAyC,CACjD,IAAMH,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAE5D,OADc,KAAK,OAAO,IAAIH,CAAM,GACpB,IACjB,CAEA,SAASG,EAA+B,CACvC,IAAMH,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAC5D,OAAO,KAAK,OAAO,UAAUH,CAAM,CACpC,CAIA,aAAwB,CACvB,IAAMK,EAAU,IAAI,IAEpB,OAAW,CAAE,IAAAC,CAAI,IAAK,KAAK,YAAY,SAAS,CAAC,CAAC,EACjDD,EAAQ,IAAIC,CAAG,EAEhB,OAAO,MAAM,KAAKD,CAAO,CAC1B,CAEA,MAAM,aAAaR,EAAiC,CACnD,MAAM,KAAK,KAAK,YAAY,IAAM,CAEjC,IAAMI,EAAa,MAAM,KAAK,KAAK,YAAY,UAAUJ,CAAQ,CAAC,EAGlE,QAAWG,KAAUC,EACpB,KAAK,YAAY,OAAOJ,EAAUG,CAAM,CAK1C,CAAC,EAEDb,EAAM,+BAA+BU,CAAQ,GAAG,CACjD,CAIA,qBAAqBA,EAA0B,CAC9C,OAAO,KAAK,YAAY,eAAeA,CAAQ,CAChD,CAEA,iBAAiBA,EAAkBM,EAA+B,CACjE,IAAMH,EAAS,OAAOG,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAC5D,OAAO,KAAK,YAAY,UAAUN,EAAUG,CAAM,CACnD,CAEA,OAAc,CACb,KAAK,KAAK,MAAM,CACjB,CACD","names":["open","Logger","DEBUG","VERBOSE","ERROR","StorageFs","_StorageFs","path","root","applogs","threadIndex","blocks","threadId","stored","applog","cidStr","cidStrings","json","cid","bytes","threads","key"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { open, RootDatabase, Database } from 'lmdb'\nimport type { Applog, CidString, BlockStoreish } from '@wovin/core'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats/cid'\n\nconst { DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO)\n\n/**\n * File-system based storage using LMDB.\n * Implements BlockStoreish for use with wovin snapshot chain walking.\n */\nexport class StorageFs implements BlockStoreish {\n\tprivate root: RootDatabase\n\tprivate applogs: Database<string, string> // cidString → Applog JSON\n\tprivate threadIndex: Database<string, string> // threadId → cidString (dupSort)\n\tprivate blocks: Database<Uint8Array, string> // cidString → bytes\n\n\tstatic async init(path: string): Promise<StorageFs> {\n\t\tDEBUG(`[StorageFs.init] ENTER - path=${path}`)\n\n\t\tDEBUG(`[StorageFs.init] Opening LMDB root database`)\n\t\tconst root = open({\n\t\t\tpath,\n\t\t\tcompression: true,\n\t\t})\n\t\tDEBUG(`[StorageFs.init] LMDB root database opened`)\n\n\t\tDEBUG(`[StorageFs.init] Opening applogs DB`)\n\t\tconst applogs = root.openDB<string, string>({\n\t\t\tname: 'applogs',\n\t\t})\n\t\tDEBUG(`[StorageFs.init] Applogs DB opened`)\n\n\t\tDEBUG(`[StorageFs.init] Opening threadIndex DB`)\n\t\tconst threadIndex = root.openDB<string, string>({\n\t\t\tname: 'thread_index',\n\t\t\tdupSort: true,\n\t\t})\n\t\tDEBUG(`[StorageFs.init] ThreadIndex DB opened`)\n\n\t\tDEBUG(`[StorageFs.init] Opening blocks DB`)\n\t\tconst blocks = root.openDB<Uint8Array, string>({\n\t\t\tname: 'blocks',\n\t\t})\n\t\tDEBUG(`[StorageFs.init] Blocks DB opened`)\n\n\t\tDEBUG(`[StorageFs.init] Creating StorageFs instance`)\n\t\tconst instance = new StorageFs(root, applogs, threadIndex, blocks)\n\t\tDEBUG(`[StorageFs.init] EXIT - StorageFs instance created successfully`)\n\t\treturn instance\n\t}\n\n\tprivate constructor(\n\t\troot: RootDatabase,\n\t\tapplogs: Database<string, string>,\n\t\tthreadIndex: Database<string, string>,\n\t\tblocks: Database<Uint8Array, string>,\n\t) {\n\t\tthis.root = root\n\t\tthis.applogs = applogs\n\t\tthis.threadIndex = threadIndex\n\t\tthis.blocks = blocks\n\t}\n\n\t// === Applogs ===\n\n\tasync storeApplogs(threadId: string, applogs: Applog[]): Promise<number> {\n\t\tconst fnStart = Date.now()\n\t\tDEBUG(`[StorageFs.storeApplogs] ===== ENTER =====`)\n\t\tDEBUG(`[StorageFs.storeApplogs] threadId: ${threadId}`)\n\t\tDEBUG(`[StorageFs.storeApplogs] applogs.length: ${applogs.length}`)\n\t\tlet stored = 0\n\n\t\tDEBUG(`[StorageFs.storeApplogs] About to start transaction`)\n\t\tconst txStart = Date.now()\n\n\t\ttry {\n\t\t\t// CRITICAL FIX: Use transactionSync instead of transaction\n\t\t\t// Async transactions (transaction method) are NOT supported in Deno's NAPI\n\t\t\t// Reference: https://github.com/kriszyp/lmdb-js#usage\n\t\t\t// \"Deno and Bun's support for NAPI is not very stable yet, and currently\n\t\t\t// asynchronous transactions (transaction method) are not supported\"\n\n\t\t\t// NOTE: No logging inside transaction - LMDB transactions must be fast and synchronous\n\t\t\tthis.root.transactionSync(() => {\n\t\t\t\tfor (const applog of applogs) {\n\t\t\t\t\tconst cidStr = applog.cid\n\n\t\t\t\t\t// Check if already stored (dedup by CID)\n\t\t\t\t\tif (this.applogs.doesExist(cidStr)) {\n\t\t\t\t\t\t// Applog exists, but still add to thread index if not already there\n\t\t\t\t\t\tif (!this.threadIndex.doesExist(threadId, cidStr)) {\n\t\t\t\t\t\t\tthis.threadIndex.put(threadId, cidStr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Store applog\n\t\t\t\t\tthis.applogs.put(cidStr, JSON.stringify(applog))\n\n\t\t\t\t\t// Add to thread index\n\t\t\t\t\tthis.threadIndex.put(threadId, cidStr)\n\n\t\t\t\t\tstored++\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tconst txDuration = Date.now() - txStart\n\t\t\tDEBUG(`[StorageFs.storeApplogs] Transaction completed in ${txDuration}ms`)\n\t\t} catch (err) {\n\t\t\tconst txDuration = Date.now() - txStart\n\t\t\tERROR(`[StorageFs.storeApplogs] Transaction error after ${txDuration}ms:`, err)\n\t\t\tthrow err\n\t\t}\n\n\t\tconst fnDuration = Date.now() - fnStart\n\t\tDEBUG(`[StorageFs.storeApplogs] ===== SUCCESS in ${fnDuration}ms, stored ${stored} applogs`)\n\t\treturn stored\n\t}\n\n\tgetApplogs(threadId: string): Applog[] {\n\t\tconst applogs: Applog[] = []\n\t\tconst cidStrings = this.threadIndex.getValues(threadId)\n\n\t\tfor (const cidStr of cidStrings) {\n\t\t\tconst json = this.applogs.get(cidStr)\n\t\t\tif (json) {\n\t\t\t\tapplogs.push(JSON.parse(json))\n\t\t\t}\n\t\t}\n\n\t\treturn applogs\n\t}\n\n\tgetApplogByCid(cid: CID | CidString): Applog | null {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tconst json = this.applogs.get(cidStr)\n\t\tif (!json) return null\n\t\treturn JSON.parse(json)\n\t}\n\n\thasApplog(cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.applogs.doesExist(cidStr)\n\t}\n\n\t// === Blocks ===\n\n\tasync storeBlock(cid: CID | CidString, bytes: Uint8Array): Promise<void> {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tawait this.blocks.put(cidStr, bytes)\n\t}\n\n\tgetBlock(cid: CID | CidString): Uint8Array | null {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\tconst bytes = this.blocks.get(cidStr)\n\t\treturn bytes ?? null\n\t}\n\n\thasBlock(cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.blocks.doesExist(cidStr)\n\t}\n\n\t/**\n\t * Get a block by CID (BlockStoreish interface).\n\t * Throws if block not found.\n\t */\n\tget(cid: CID): Promise<Uint8Array> {\n\t\tconst bytes = this.getBlock(cid)\n\t\tif (!bytes) {\n\t\t\treturn Promise.reject(new Error(`Block not found: ${cid.toString()}`))\n\t\t}\n\t\treturn Promise.resolve(bytes)\n\t}\n\n\t// === Threads ===\n\n\tlistThreads(): string[] {\n\t\tconst threads = new Set<string>()\n\t\t// Iterate over all keys in thread_index\n\t\tfor (const { key } of this.threadIndex.getRange({})) {\n\t\t\tthreads.add(key)\n\t\t}\n\t\treturn Array.from(threads)\n\t}\n\n\tasync deleteThread(threadId: string): Promise<void> {\n\t\t// Use transactionSync for Deno compatibility (async transactions not supported in Deno NAPI)\n\t\tthis.root.transactionSync(() => {\n\t\t\t// Get all CIDs in this thread\n\t\t\tconst cidStrings = Array.from(this.threadIndex.getValues(threadId))\n\n\t\t\t// Remove all entries for this thread from index\n\t\t\tfor (const cidStr of cidStrings) {\n\t\t\t\tthis.threadIndex.remove(threadId, cidStr)\n\t\t\t}\n\n\t\t\t// Note: We don't delete the applogs themselves - they may be in other threads\n\t\t\t// Orphan cleanup could be a separate maintenance operation\n\t\t})\n\n\t\tDEBUG(`[StorageFs] Deleted thread \"${threadId}\"`)\n\t}\n\n\t// === Utilities ===\n\n\tgetThreadApplogCount(threadId: string): number {\n\t\treturn this.threadIndex.getValuesCount(threadId)\n\t}\n\n\tisApplogInThread(threadId: string, cid: CID | CidString): boolean {\n\t\tconst cidStr = typeof cid === 'string' ? cid : cid.toString()\n\t\treturn this.threadIndex.doesExist(threadId, cidStr)\n\t}\n\n\tclose(): void {\n\t\tthis.root.close()\n\t}\n}\n\n// Re-export for backwards compatibility during transition\nexport { StorageFs as LmdbConnector }\n"],"mappings":"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","names":["open","Logger","DEBUG","VERBOSE","ERROR","StorageFs","path","root","applogs","threadIndex","blocks","instance","threadId","fnStart","stored","txStart","applog","cidStr","txDuration","err","fnDuration","cidStrings","json","cid","bytes","threads","key"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wovin/storage-fs",
3
- "version": "0.0.26",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.min.js",
6
6
  "module": "./dist/index.min.js",
@@ -23,10 +23,10 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@ipld/car": "^5.2.6",
26
- "@wovin/core": "0.0.26",
27
26
  "besonders-logger": "1.0.1",
28
27
  "lmdb": "^3.0.0",
29
- "multiformats": "^13.0.1"
28
+ "multiformats": "^13.0.1",
29
+ "@wovin/core": "^0.1.1"
30
30
  },
31
31
  "devDependencies": {
32
32
  "concurrently": "^8.2.2",
@@ -36,6 +36,11 @@
36
36
  "typescript": "^5.8.3",
37
37
  "tsupconfig": "^0.0.0"
38
38
  },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://gitlab.com/wovin/wovin.git",
42
+ "directory": "packages/@wovin/storage-fs"
43
+ },
39
44
  "scripts": {
40
45
  "build": "rm -rf dist/ && concurrently \"pnpm build:code\" \"pnpm build:types\"",
41
46
  "build:code": "tsup --minify --external esbuild",