@casfa/storage-fs 0.1.0 → 0.3.0

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/README.md CHANGED
@@ -41,27 +41,6 @@ await storage.put('node:abcd1234...', data);
41
41
 
42
42
  // Retrieve data
43
43
  const data = await storage.get('node:abcd1234...');
44
-
45
- // Check existence
46
- const exists = await storage.has('node:abcd1234...');
47
-
48
- // Delete
49
- const deleted = await storage.delete('node:abcd1234...');
50
- ```
51
-
52
- ### With LRU Cache
53
-
54
- ```typescript
55
- import { createFsStorageWithCache } from '@casfa/storage-fs';
56
-
57
- const storage = createFsStorageWithCache({
58
- basePath: '/var/cas/data',
59
- cacheSize: 1000, // Max items in cache
60
- cacheMaxAge: 60000, // TTL in milliseconds
61
- });
62
-
63
- // Cache is automatically managed
64
- const data = await storage.get('node:abcd1234...'); // May hit cache
65
44
  ```
66
45
 
67
46
  ## Configuration
@@ -79,24 +58,11 @@ interface FsStorageConfig {
79
58
  }
80
59
  ```
81
60
 
82
- ### Cache Options
83
-
84
- ```typescript
85
- interface FsStorageWithCacheConfig extends FsStorageConfig {
86
- // Max items in LRU cache (default: 1000)
87
- cacheSize?: number;
88
-
89
- // Cache TTL in milliseconds (default: 60000)
90
- cacheMaxAge?: number;
91
- }
92
- ```
93
-
94
61
  ## API Reference
95
62
 
96
63
  ### Functions
97
64
 
98
- - `createFsStorage(config)` - Create storage without cache
99
- - `createFsStorageWithCache(config)` - Create storage with LRU cache
65
+ - `createFsStorage(config)` - Create file-system storage
100
66
 
101
67
  ### StorageProvider Interface
102
68
 
@@ -104,8 +70,6 @@ interface FsStorageWithCacheConfig extends FsStorageConfig {
104
70
  interface StorageProvider {
105
71
  get(key: string): Promise<Uint8Array | null>;
106
72
  put(key: string, data: Uint8Array): Promise<void>;
107
- has(key: string): Promise<boolean>;
108
- delete(key: string): Promise<boolean>;
109
73
  }
110
74
  ```
111
75
 
package/README.zh-CN.md CHANGED
@@ -41,27 +41,6 @@ await storage.put('node:abcd1234...', data);
41
41
 
42
42
  // 检索数据
43
43
  const data = await storage.get('node:abcd1234...');
44
-
45
- // 检查是否存在
46
- const exists = await storage.has('node:abcd1234...');
47
-
48
- // 删除
49
- const deleted = await storage.delete('node:abcd1234...');
50
- ```
51
-
52
- ### 带 LRU 缓存
53
-
54
- ```typescript
55
- import { createFsStorageWithCache } from '@casfa/storage-fs';
56
-
57
- const storage = createFsStorageWithCache({
58
- basePath: '/var/cas/data',
59
- cacheSize: 1000, // 缓存最大条目数
60
- cacheMaxAge: 60000, // TTL(毫秒)
61
- });
62
-
63
- // 缓存自动管理
64
- const data = await storage.get('node:abcd1234...'); // 可能命中缓存
65
44
  ```
66
45
 
67
46
  ## 配置
@@ -79,24 +58,11 @@ interface FsStorageConfig {
79
58
  }
80
59
  ```
81
60
 
82
- ### 缓存选项
83
-
84
- ```typescript
85
- interface FsStorageWithCacheConfig extends FsStorageConfig {
86
- // LRU 缓存最大条目数(默认: 1000)
87
- cacheSize?: number;
88
-
89
- // 缓存 TTL,单位毫秒(默认: 60000)
90
- cacheMaxAge?: number;
91
- }
92
- ```
93
-
94
61
  ## API 参考
95
62
 
96
63
  ### 函数
97
64
 
98
- - `createFsStorage(config)` - 创建不带缓存的存储
99
- - `createFsStorageWithCache(config)` - 创建带 LRU 缓存的存储
65
+ - `createFsStorage(config)` - 创建文件系统存储
100
66
 
101
67
  ### StorageProvider 接口
102
68
 
@@ -104,8 +70,6 @@ interface FsStorageWithCacheConfig extends FsStorageConfig {
104
70
  interface StorageProvider {
105
71
  get(key: string): Promise<Uint8Array | null>;
106
72
  put(key: string, data: Uint8Array): Promise<void>;
107
- has(key: string): Promise<boolean>;
108
- delete(key: string): Promise<boolean>;
109
73
  }
110
74
  ```
111
75
 
@@ -0,0 +1,23 @@
1
+ /**
2
+ * File System Storage Provider for CAS
3
+ *
4
+ * Implements StorageProvider with:
5
+ * - Local file system backend storage
6
+ * - Automatic directory creation
7
+ * - Internal existence check in put() to avoid redundant writes
8
+ */
9
+ import type { StorageProvider } from "@casfa/storage-core";
10
+ /**
11
+ * File System Storage configuration
12
+ */
13
+ export type FsStorageConfig = {
14
+ /** Base directory for storage */
15
+ basePath: string;
16
+ /** Key prefix in storage (default: "cas/v1/") */
17
+ prefix?: string;
18
+ };
19
+ /**
20
+ * Create a file system-backed storage provider
21
+ */
22
+ export declare const createFsStorage: (config: FsStorageConfig) => StorageProvider;
23
+ //# sourceMappingURL=fs-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-storage.d.ts","sourceRoot":"","sources":["../src/fs-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAa3D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,eAAe,KAAG,eA6CzD,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,40 +1,7 @@
1
- import { StorageProvider } from '@casfa/storage-core';
2
-
3
1
  /**
4
- * File System Storage Provider for CAS
2
+ * CAS File System Storage
5
3
  *
6
- * Implements StorageProvider with:
7
- * - LRU cache for key existence checks
8
- * - Local file system backend storage
9
- * - Automatic directory creation
4
+ * File system-backed storage provider for CAS.
10
5
  */
11
-
12
- /**
13
- * File System Storage configuration
14
- */
15
- type FsStorageConfig = {
16
- /** Base directory for storage */
17
- basePath: string;
18
- /** LRU cache size for key existence (default: 10000) */
19
- cacheSize?: number;
20
- /** Key prefix in storage (default: "cas/sha256/") */
21
- prefix?: string;
22
- };
23
- /**
24
- * Create a file system-backed storage provider
25
- */
26
- declare const createFsStorage: (config: FsStorageConfig) => StorageProvider;
27
- /**
28
- * Create file system storage with cache control methods (for testing)
29
- */
30
- declare const createFsStorageWithCache: (config: FsStorageConfig) => {
31
- clearCache: () => void;
32
- getCacheStats: () => {
33
- size: number;
34
- };
35
- has: (key: string) => Promise<boolean>;
36
- get: (key: string) => Promise<Uint8Array | null>;
37
- put: (key: string, value: Uint8Array) => Promise<void>;
38
- };
39
-
40
- export { type FsStorageConfig, createFsStorage, createFsStorageWithCache };
6
+ export { createFsStorage, type FsStorageConfig } from "./fs-storage.ts";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,39 +1,22 @@
1
1
  // src/fs-storage.ts
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
- import { dirname, join } from "path";
4
- import {
5
- createLRUCache,
6
- DEFAULT_CACHE_SIZE,
7
- toStoragePath
8
- } from "@casfa/storage-core";
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { stat } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
+ var toStoragePath = (key, prefix) => {
6
+ const subdir = key.slice(0, 2);
7
+ return `${prefix}${subdir}/${key}`;
8
+ };
9
9
  var createFsStorage = (config) => {
10
10
  const basePath = config.basePath;
11
- const prefix = config.prefix ?? "cas/sha256/";
12
- const existsCache = createLRUCache(config.cacheSize ?? DEFAULT_CACHE_SIZE);
13
- if (!existsSync(basePath)) {
14
- mkdirSync(basePath, { recursive: true });
15
- }
11
+ const prefix = config.prefix ?? "cas/v1/";
16
12
  const toFilePath = (casKey) => {
17
13
  const storagePath = toStoragePath(casKey, prefix);
18
14
  return join(basePath, storagePath);
19
15
  };
20
- const has = async (key) => {
21
- const cached = existsCache.get(key);
22
- if (cached !== void 0) {
23
- return cached;
24
- }
25
- const filePath = toFilePath(key);
26
- const exists = existsSync(filePath);
27
- if (exists) {
28
- existsCache.set(key, true);
29
- }
30
- return exists;
31
- };
32
16
  const get = async (key) => {
33
17
  const filePath = toFilePath(key);
34
18
  try {
35
19
  const buffer = readFileSync(filePath);
36
- existsCache.set(key, true);
37
20
  return new Uint8Array(buffer);
38
21
  } catch (error) {
39
22
  const err = error;
@@ -44,34 +27,19 @@ var createFsStorage = (config) => {
44
27
  }
45
28
  };
46
29
  const put = async (key, value) => {
47
- if (existsCache.get(key)) {
48
- return;
49
- }
50
- const exists = await has(key);
51
- if (exists) {
52
- return;
53
- }
54
30
  const filePath = toFilePath(key);
31
+ try {
32
+ await stat(filePath);
33
+ return;
34
+ } catch {}
55
35
  const dir = dirname(filePath);
56
- if (!existsSync(dir)) {
57
- mkdirSync(dir, { recursive: true });
58
- }
36
+ mkdirSync(dir, { recursive: true });
59
37
  writeFileSync(filePath, value);
60
- existsCache.set(key, true);
61
- };
62
- return { has, get, put };
63
- };
64
- var createFsStorageWithCache = (config) => {
65
- const existsCache = createLRUCache(config.cacheSize ?? DEFAULT_CACHE_SIZE);
66
- const storage = createFsStorage(config);
67
- return {
68
- ...storage,
69
- clearCache: () => existsCache.clear(),
70
- getCacheStats: () => ({ size: existsCache.size() })
71
38
  };
39
+ return { get, put };
72
40
  };
73
41
  export {
74
- createFsStorage,
75
- createFsStorageWithCache
42
+ createFsStorage
76
43
  };
77
- //# sourceMappingURL=index.js.map
44
+
45
+ //# debugId=21AA1842112D604764756E2164756E21
package/dist/index.js.map CHANGED
@@ -1 +1,10 @@
1
- {"version":3,"sources":["../src/fs-storage.ts"],"sourcesContent":["/**\n * File System Storage Provider for CAS\n *\n * Implements StorageProvider with:\n * - LRU cache for key existence checks\n * - Local file system backend storage\n * - Automatic directory creation\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n createLRUCache,\n DEFAULT_CACHE_SIZE,\n type StorageProvider,\n toStoragePath,\n} from \"@casfa/storage-core\";\n\n/**\n * File System Storage configuration\n */\nexport type FsStorageConfig = {\n /** Base directory for storage */\n basePath: string;\n /** LRU cache size for key existence (default: 10000) */\n cacheSize?: number;\n /** Key prefix in storage (default: \"cas/sha256/\") */\n prefix?: string;\n};\n\n/**\n * Create a file system-backed storage provider\n */\nexport const createFsStorage = (config: FsStorageConfig): StorageProvider => {\n const basePath = config.basePath;\n const prefix = config.prefix ?? \"cas/sha256/\";\n const existsCache = createLRUCache<string, boolean>(config.cacheSize ?? DEFAULT_CACHE_SIZE);\n\n // Ensure base directory exists\n if (!existsSync(basePath)) {\n mkdirSync(basePath, { recursive: true });\n }\n\n const toFilePath = (casKey: string): string => {\n const storagePath = toStoragePath(casKey, prefix);\n return join(basePath, storagePath);\n };\n\n const has = async (key: string): Promise<boolean> => {\n // Check cache first\n const cached = existsCache.get(key);\n if (cached !== undefined) {\n return cached;\n }\n\n // Check file system\n const filePath = toFilePath(key);\n const exists = existsSync(filePath);\n\n if (exists) {\n existsCache.set(key, true);\n }\n // Don't cache non-existence (it might be written later)\n\n return exists;\n };\n\n const get = async (key: string): Promise<Uint8Array | null> => {\n const filePath = toFilePath(key);\n\n try {\n const buffer = readFileSync(filePath);\n // Mark as existing in cache\n existsCache.set(key, true);\n return new Uint8Array(buffer);\n } catch (error: unknown) {\n const err = error as { code?: string };\n if (err.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n };\n\n const put = async (key: string, value: Uint8Array): Promise<void> => {\n // Check cache first (avoid redundant writes)\n if (existsCache.get(key)) {\n return;\n }\n\n // Check if already exists\n const exists = await has(key);\n if (exists) {\n return;\n }\n\n const filePath = toFilePath(key);\n const dir = dirname(filePath);\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write file\n writeFileSync(filePath, value);\n\n // Mark as existing\n existsCache.set(key, true);\n };\n\n return { has, get, put };\n};\n\n/**\n * Create file system storage with cache control methods (for testing)\n */\nexport const createFsStorageWithCache = (config: FsStorageConfig) => {\n const existsCache = createLRUCache<string, boolean>(config.cacheSize ?? DEFAULT_CACHE_SIZE);\n\n const storage = createFsStorage(config);\n\n return {\n ...storage,\n clearCache: () => existsCache.clear(),\n getCacheStats: () => ({ size: existsCache.size() }),\n };\n};\n"],"mappings":";AASA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,SAAS,YAAY;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AAiBA,IAAM,kBAAkB,CAAC,WAA6C;AAC3E,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,cAAc,eAAgC,OAAO,aAAa,kBAAkB;AAG1F,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,cAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EACzC;AAEA,QAAM,aAAa,CAAC,WAA2B;AAC7C,UAAM,cAAc,cAAc,QAAQ,MAAM;AAChD,WAAO,KAAK,UAAU,WAAW;AAAA,EACnC;AAEA,QAAM,MAAM,OAAO,QAAkC;AAEnD,UAAM,SAAS,YAAY,IAAI,GAAG;AAClC,QAAI,WAAW,QAAW;AACxB,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,WAAW,GAAG;AAC/B,UAAM,SAAS,WAAW,QAAQ;AAElC,QAAI,QAAQ;AACV,kBAAY,IAAI,KAAK,IAAI;AAAA,IAC3B;AAGA,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,OAAO,QAA4C;AAC7D,UAAM,WAAW,WAAW,GAAG;AAE/B,QAAI;AACF,YAAM,SAAS,aAAa,QAAQ;AAEpC,kBAAY,IAAI,KAAK,IAAI;AACzB,aAAO,IAAI,WAAW,MAAM;AAAA,IAC9B,SAAS,OAAgB;AACvB,YAAM,MAAM;AACZ,UAAI,IAAI,SAAS,UAAU;AACzB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,MAAM,OAAO,KAAa,UAAqC;AAEnE,QAAI,YAAY,IAAI,GAAG,GAAG;AACxB;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,QAAI,QAAQ;AACV;AAAA,IACF;AAEA,UAAM,WAAW,WAAW,GAAG;AAC/B,UAAM,MAAM,QAAQ,QAAQ;AAG5B,QAAI,CAAC,WAAW,GAAG,GAAG;AACpB,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAGA,kBAAc,UAAU,KAAK;AAG7B,gBAAY,IAAI,KAAK,IAAI;AAAA,EAC3B;AAEA,SAAO,EAAE,KAAK,KAAK,IAAI;AACzB;AAKO,IAAM,2BAA2B,CAAC,WAA4B;AACnE,QAAM,cAAc,eAAgC,OAAO,aAAa,kBAAkB;AAE1F,QAAM,UAAU,gBAAgB,MAAM;AAEtC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY,MAAM,YAAY,MAAM;AAAA,IACpC,eAAe,OAAO,EAAE,MAAM,YAAY,KAAK,EAAE;AAAA,EACnD;AACF;","names":[]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/fs-storage.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * File System Storage Provider for CAS\n *\n * Implements StorageProvider with:\n * - Local file system backend storage\n * - Automatic directory creation\n * - Internal existence check in put() to avoid redundant writes\n */\n\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { StorageProvider } from \"@casfa/storage-core\";\n\n/**\n * Create storage path from a CB32 storage key.\n * Uses first 2 chars as subdirectory for better distribution.\n *\n * Example: 240B5PHBGEC2A705WTKKMVRS30 -> cas/v1/24/240B5PHBGEC2A705WTKKMVRS30\n */\nconst toStoragePath = (key: string, prefix: string): string => {\n const subdir = key.slice(0, 2);\n return `${prefix}${subdir}/${key}`;\n};\n\n/**\n * File System Storage configuration\n */\nexport type FsStorageConfig = {\n /** Base directory for storage */\n basePath: string;\n /** Key prefix in storage (default: \"cas/v1/\") */\n prefix?: string;\n};\n\n/**\n * Create a file system-backed storage provider\n */\nexport const createFsStorage = (config: FsStorageConfig): StorageProvider => {\n const basePath = config.basePath;\n const prefix = config.prefix ?? \"cas/v1/\";\n\n const toFilePath = (casKey: string): string => {\n const storagePath = toStoragePath(casKey, prefix);\n return join(basePath, storagePath);\n };\n\n const get = async (key: string): Promise<Uint8Array | null> => {\n const filePath = toFilePath(key);\n\n try {\n const buffer = readFileSync(filePath);\n return new Uint8Array(buffer);\n } catch (error: unknown) {\n const err = error as { code?: string };\n if (err.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n };\n\n const put = async (key: string, value: Uint8Array): Promise<void> => {\n const filePath = toFilePath(key);\n\n // Internal optimization: stat is cheaper than write for existing files\n try {\n await stat(filePath);\n return; // already exists\n } catch {\n // doesn't exist, proceed to write\n }\n\n const dir = dirname(filePath);\n\n // Ensure directory exists\n mkdirSync(dir, { recursive: true });\n\n // Write file\n writeFileSync(filePath, value);\n };\n\n return { get, put };\n};\n"
6
+ ],
7
+ "mappings": ";AASA;AACA;AACA;AASA,IAAM,gBAAgB,CAAC,KAAa,WAA2B;AAAA,EAC7D,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC;AAAA,EAC7B,OAAO,GAAG,SAAS,UAAU;AAAA;AAgBxB,IAAM,kBAAkB,CAAC,WAA6C;AAAA,EAC3E,MAAM,WAAW,OAAO;AAAA,EACxB,MAAM,SAAS,OAAO,UAAU;AAAA,EAEhC,MAAM,aAAa,CAAC,WAA2B;AAAA,IAC7C,MAAM,cAAc,cAAc,QAAQ,MAAM;AAAA,IAChD,OAAO,KAAK,UAAU,WAAW;AAAA;AAAA,EAGnC,MAAM,MAAM,OAAO,QAA4C;AAAA,IAC7D,MAAM,WAAW,WAAW,GAAG;AAAA,IAE/B,IAAI;AAAA,MACF,MAAM,SAAS,aAAa,QAAQ;AAAA,MACpC,OAAO,IAAI,WAAW,MAAM;AAAA,MAC5B,OAAO,OAAgB;AAAA,MACvB,MAAM,MAAM;AAAA,MACZ,IAAI,IAAI,SAAS,UAAU;AAAA,QACzB,OAAO;AAAA,MACT;AAAA,MACA,MAAM;AAAA;AAAA;AAAA,EAIV,MAAM,MAAM,OAAO,KAAa,UAAqC;AAAA,IACnE,MAAM,WAAW,WAAW,GAAG;AAAA,IAG/B,IAAI;AAAA,MACF,MAAM,KAAK,QAAQ;AAAA,MACnB;AAAA,MACA,MAAM;AAAA,IAIR,MAAM,MAAM,QAAQ,QAAQ;AAAA,IAG5B,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IAGlC,cAAc,UAAU,KAAK;AAAA;AAAA,EAG/B,OAAO,EAAE,KAAK,IAAI;AAAA;",
8
+ "debugId": "21AA1842112D604764756E2164756E21",
9
+ "names": []
10
+ }
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@casfa/storage-fs",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "File system storage provider for CAS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
+ "bun": "./src/index.ts",
10
11
  "types": "./dist/index.d.ts",
11
12
  "import": "./dist/index.js"
12
13
  }
13
14
  },
14
15
  "scripts": {
15
- "build": "tsup",
16
- "dev": "tsup --watch",
16
+ "build": "bun ../../scripts/build-pkg.ts",
17
17
  "typecheck": "tsc --noEmit",
18
18
  "lint": "biome check .",
19
19
  "lint:fix": "biome check --write .",