@casfa/storage-s3 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 +1 -38
- package/README.zh-CN.md +1 -26
- package/dist/index.d.ts +4 -39
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -68
- package/dist/index.js.map +10 -1
- package/dist/s3-storage.d.ts +27 -0
- package/dist/s3-storage.d.ts.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -30,28 +30,6 @@ await storage.put('node:abcd1234...', data);
|
|
|
30
30
|
|
|
31
31
|
// Retrieve data
|
|
32
32
|
const data = await storage.get('node:abcd1234...');
|
|
33
|
-
|
|
34
|
-
// Check existence
|
|
35
|
-
const exists = await storage.has('node:abcd1234...');
|
|
36
|
-
|
|
37
|
-
// Delete
|
|
38
|
-
const deleted = await storage.delete('node:abcd1234...');
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### With LRU Cache
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
import { createS3StorageWithCache } from '@casfa/storage-s3';
|
|
45
|
-
|
|
46
|
-
const storage = createS3StorageWithCache({
|
|
47
|
-
bucket: 'my-cas-bucket',
|
|
48
|
-
region: 'us-east-1',
|
|
49
|
-
cacheSize: 1000, // Max items in cache
|
|
50
|
-
cacheMaxAge: 300000, // 5 minutes TTL
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Cache reduces S3 API calls for repeated reads
|
|
54
|
-
const data = await storage.get('node:abcd1234...');
|
|
55
33
|
```
|
|
56
34
|
|
|
57
35
|
### With Custom S3 Client
|
|
@@ -95,18 +73,6 @@ interface S3StorageConfig {
|
|
|
95
73
|
}
|
|
96
74
|
```
|
|
97
75
|
|
|
98
|
-
### Cache Options
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
interface S3StorageWithCacheConfig extends S3StorageConfig {
|
|
102
|
-
// Max items in LRU cache (default: 1000)
|
|
103
|
-
cacheSize?: number;
|
|
104
|
-
|
|
105
|
-
// Cache TTL in milliseconds (default: 60000)
|
|
106
|
-
cacheMaxAge?: number;
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
76
|
## S3 Key Structure
|
|
111
77
|
|
|
112
78
|
Objects are stored with sharded prefixes for better S3 performance:
|
|
@@ -121,8 +87,7 @@ Where `ab` and `cd` are the first 4 characters of the hash, providing good distr
|
|
|
121
87
|
|
|
122
88
|
### Functions
|
|
123
89
|
|
|
124
|
-
- `createS3Storage(config)` - Create S3 storage
|
|
125
|
-
- `createS3StorageWithCache(config)` - Create S3 storage with LRU cache
|
|
90
|
+
- `createS3Storage(config)` - Create S3 storage
|
|
126
91
|
|
|
127
92
|
### StorageProvider Interface
|
|
128
93
|
|
|
@@ -130,8 +95,6 @@ Where `ab` and `cd` are the first 4 characters of the hash, providing good distr
|
|
|
130
95
|
interface StorageProvider {
|
|
131
96
|
get(key: string): Promise<Uint8Array | null>;
|
|
132
97
|
put(key: string, data: Uint8Array): Promise<void>;
|
|
133
|
-
has(key: string): Promise<boolean>;
|
|
134
|
-
delete(key: string): Promise<boolean>;
|
|
135
98
|
}
|
|
136
99
|
```
|
|
137
100
|
|
package/README.zh-CN.md
CHANGED
|
@@ -30,28 +30,6 @@ await storage.put('node:abcd1234...', data);
|
|
|
30
30
|
|
|
31
31
|
// 检索数据
|
|
32
32
|
const data = await storage.get('node:abcd1234...');
|
|
33
|
-
|
|
34
|
-
// 检查是否存在
|
|
35
|
-
const exists = await storage.has('node:abcd1234...');
|
|
36
|
-
|
|
37
|
-
// 删除
|
|
38
|
-
const deleted = await storage.delete('node:abcd1234...');
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 带 LRU 缓存
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
import { createS3StorageWithCache } from '@casfa/storage-s3';
|
|
45
|
-
|
|
46
|
-
const storage = createS3StorageWithCache({
|
|
47
|
-
bucket: 'my-cas-bucket',
|
|
48
|
-
region: 'us-east-1',
|
|
49
|
-
cacheSize: 1000, // 缓存最大条目数
|
|
50
|
-
cacheMaxAge: 300000, // 5 分钟 TTL
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// 缓存减少 S3 API 调用,降低重复读取延迟
|
|
54
|
-
const data = await storage.get('node:abcd1234...');
|
|
55
33
|
```
|
|
56
34
|
|
|
57
35
|
### 使用自定义 S3 客户端
|
|
@@ -121,8 +99,7 @@ interface S3StorageWithCacheConfig extends S3StorageConfig {
|
|
|
121
99
|
|
|
122
100
|
### 函数
|
|
123
101
|
|
|
124
|
-
- `createS3Storage(config)` -
|
|
125
|
-
- `createS3StorageWithCache(config)` - 创建带 LRU 缓存的 S3 存储
|
|
102
|
+
- `createS3Storage(config)` - 创建 S3 存储
|
|
126
103
|
|
|
127
104
|
### StorageProvider 接口
|
|
128
105
|
|
|
@@ -130,8 +107,6 @@ interface S3StorageWithCacheConfig extends S3StorageConfig {
|
|
|
130
107
|
interface StorageProvider {
|
|
131
108
|
get(key: string): Promise<Uint8Array | null>;
|
|
132
109
|
put(key: string, data: Uint8Array): Promise<void>;
|
|
133
|
-
has(key: string): Promise<boolean>;
|
|
134
|
-
delete(key: string): Promise<boolean>;
|
|
135
110
|
}
|
|
136
111
|
```
|
|
137
112
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,42 +1,7 @@
|
|
|
1
|
-
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
import { StorageProvider } from '@casfa/storage-core';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* CAS Storage S3
|
|
6
3
|
*
|
|
7
|
-
*
|
|
8
|
-
* - LRU cache for key existence checks
|
|
9
|
-
* - S3 backend storage
|
|
4
|
+
* S3 storage provider for CAS.
|
|
10
5
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* S3 Storage configuration
|
|
14
|
-
*/
|
|
15
|
-
type S3StorageConfig = {
|
|
16
|
-
/** S3 bucket name */
|
|
17
|
-
bucket: string;
|
|
18
|
-
/** Optional S3 client (for testing or custom config) */
|
|
19
|
-
client?: S3Client;
|
|
20
|
-
/** LRU cache size for key existence (default: 10000) */
|
|
21
|
-
cacheSize?: number;
|
|
22
|
-
/** Key prefix in S3 (default: "cas/sha256/") */
|
|
23
|
-
prefix?: string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Create an S3-backed storage provider
|
|
27
|
-
*/
|
|
28
|
-
declare const createS3Storage: (config: S3StorageConfig) => StorageProvider;
|
|
29
|
-
/**
|
|
30
|
-
* Create S3 storage with cache control methods (for testing)
|
|
31
|
-
*/
|
|
32
|
-
declare const createS3StorageWithCache: (config: S3StorageConfig) => {
|
|
33
|
-
clearCache: () => void;
|
|
34
|
-
getCacheStats: () => {
|
|
35
|
-
size: number;
|
|
36
|
-
};
|
|
37
|
-
has: (key: string) => Promise<boolean>;
|
|
38
|
-
get: (key: string) => Promise<Uint8Array | null>;
|
|
39
|
-
put: (key: string, value: Uint8Array) => Promise<void>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export { type S3StorageConfig, createS3Storage, createS3StorageWithCache };
|
|
6
|
+
export { createS3Storage, type S3StorageConfig } from "./s3-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
|
@@ -5,49 +5,22 @@ import {
|
|
|
5
5
|
PutObjectCommand,
|
|
6
6
|
S3Client
|
|
7
7
|
} from "@aws-sdk/client-s3";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from "@casfa/storage-core";
|
|
8
|
+
var toStoragePath = (key, prefix) => {
|
|
9
|
+
const subdir = key.slice(0, 2);
|
|
10
|
+
return `${prefix}${subdir}/${key}`;
|
|
11
|
+
};
|
|
13
12
|
var createS3Storage = (config) => {
|
|
14
|
-
const client = config.client ?? new S3Client({});
|
|
13
|
+
const client = config.client ?? new S3Client(config.region ? { region: config.region } : {});
|
|
15
14
|
const bucket = config.bucket;
|
|
16
|
-
const prefix = config.prefix ?? "cas/
|
|
17
|
-
const existsCache = createLRUCache(config.cacheSize ?? DEFAULT_CACHE_SIZE);
|
|
15
|
+
const prefix = config.prefix ?? "cas/v1/";
|
|
18
16
|
const toS3Key = (casKey) => toStoragePath(casKey, prefix);
|
|
19
|
-
const has = async (key) => {
|
|
20
|
-
const cached = existsCache.get(key);
|
|
21
|
-
if (cached !== void 0) {
|
|
22
|
-
return cached;
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
await client.send(
|
|
26
|
-
new HeadObjectCommand({
|
|
27
|
-
Bucket: bucket,
|
|
28
|
-
Key: toS3Key(key)
|
|
29
|
-
})
|
|
30
|
-
);
|
|
31
|
-
existsCache.set(key, true);
|
|
32
|
-
return true;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
const err = error;
|
|
35
|
-
if (err.name === "NotFound" || err.$metadata?.httpStatusCode === 404) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
17
|
const get = async (key) => {
|
|
42
18
|
try {
|
|
43
|
-
const result = await client.send(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
48
|
-
);
|
|
19
|
+
const result = await client.send(new GetObjectCommand({
|
|
20
|
+
Bucket: bucket,
|
|
21
|
+
Key: toS3Key(key)
|
|
22
|
+
}));
|
|
49
23
|
const bytes = await result.Body.transformToByteArray();
|
|
50
|
-
existsCache.set(key, true);
|
|
51
24
|
return new Uint8Array(bytes);
|
|
52
25
|
} catch (error) {
|
|
53
26
|
const err = error;
|
|
@@ -58,40 +31,30 @@ var createS3Storage = (config) => {
|
|
|
58
31
|
}
|
|
59
32
|
};
|
|
60
33
|
const put = async (key, value) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
34
|
+
const s3Key = toS3Key(key);
|
|
35
|
+
try {
|
|
36
|
+
await client.send(new HeadObjectCommand({
|
|
37
|
+
Bucket: bucket,
|
|
38
|
+
Key: s3Key
|
|
39
|
+
}));
|
|
66
40
|
return;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const err = error;
|
|
43
|
+
if (err.name !== "NotFound" && err.$metadata?.httpStatusCode !== 404) {
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
67
46
|
}
|
|
68
|
-
await client.send(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
})
|
|
75
|
-
);
|
|
76
|
-
existsCache.set(key, true);
|
|
77
|
-
};
|
|
78
|
-
return { has, get, put };
|
|
79
|
-
};
|
|
80
|
-
var createS3StorageWithCache = (config) => {
|
|
81
|
-
const client = config.client ?? new S3Client({});
|
|
82
|
-
const _bucket = config.bucket;
|
|
83
|
-
const prefix = config.prefix ?? "cas/sha256/";
|
|
84
|
-
const existsCache = createLRUCache(config.cacheSize ?? DEFAULT_CACHE_SIZE);
|
|
85
|
-
const _toS3Key = (casKey) => toStoragePath(casKey, prefix);
|
|
86
|
-
const storage = createS3Storage({ ...config, client });
|
|
87
|
-
return {
|
|
88
|
-
...storage,
|
|
89
|
-
clearCache: () => existsCache.clear(),
|
|
90
|
-
getCacheStats: () => ({ size: existsCache.size() })
|
|
47
|
+
await client.send(new PutObjectCommand({
|
|
48
|
+
Bucket: bucket,
|
|
49
|
+
Key: s3Key,
|
|
50
|
+
Body: value,
|
|
51
|
+
ContentType: "application/octet-stream"
|
|
52
|
+
}));
|
|
91
53
|
};
|
|
54
|
+
return { get, put };
|
|
92
55
|
};
|
|
93
56
|
export {
|
|
94
|
-
createS3Storage
|
|
95
|
-
createS3StorageWithCache
|
|
57
|
+
createS3Storage
|
|
96
58
|
};
|
|
97
|
-
|
|
59
|
+
|
|
60
|
+
//# debugId=FBB9BF9E1762965D64756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/s3-storage.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * S3 Storage Provider for CAS\n *\n * Implements StorageProvider with:\n * - S3 backend storage\n * - Internal HeadObject check in put() to avoid redundant uploads\n */\n\nimport {\n GetObjectCommand,\n HeadObjectCommand,\n PutObjectCommand,\n S3Client,\n} from \"@aws-sdk/client-s3\";\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 * S3 Storage configuration\n */\nexport type S3StorageConfig = {\n /** S3 bucket name */\n bucket: string;\n /** AWS region for the S3 bucket (e.g. \"us-west-2\") */\n region?: string;\n /** Optional S3 client (for testing or custom config) */\n client?: S3Client;\n /** Key prefix in S3 (default: \"cas/v1/\") */\n prefix?: string;\n};\n\n/**\n * Create an S3-backed storage provider\n */\nexport const createS3Storage = (config: S3StorageConfig): StorageProvider => {\n const client = config.client ?? new S3Client(config.region ? { region: config.region } : {});\n const bucket = config.bucket;\n const prefix = config.prefix ?? \"cas/v1/\";\n\n const toS3Key = (casKey: string): string => toStoragePath(casKey, prefix);\n\n const get = async (key: string): Promise<Uint8Array | null> => {\n try {\n const result = await client.send(\n new GetObjectCommand({\n Bucket: bucket,\n Key: toS3Key(key),\n })\n );\n\n const bytes = await result.Body!.transformToByteArray();\n return new Uint8Array(bytes);\n } catch (error: unknown) {\n const err = error as { name?: string; $metadata?: { httpStatusCode?: number } };\n if (err.name === \"NoSuchKey\" || err.$metadata?.httpStatusCode === 404) {\n return null;\n }\n throw error;\n }\n };\n\n const put = async (key: string, value: Uint8Array): Promise<void> => {\n const s3Key = toS3Key(key);\n\n // Internal optimization: HeadObject is cheaper than PutObject\n try {\n await client.send(\n new HeadObjectCommand({\n Bucket: bucket,\n Key: s3Key,\n })\n );\n return; // already exists\n } catch (error: unknown) {\n const err = error as { name?: string; $metadata?: { httpStatusCode?: number } };\n if (err.name !== \"NotFound\" && err.$metadata?.httpStatusCode !== 404) {\n throw error; // unexpected error\n }\n // not found — proceed to upload\n }\n\n // Upload to S3\n await client.send(\n new PutObjectCommand({\n Bucket: bucket,\n Key: s3Key,\n Body: value,\n ContentType: \"application/octet-stream\",\n })\n );\n };\n\n return { get, put };\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA,IAAM,gBAAgB,CAAC,KAAa,WAA2B;AAAA,EAC7D,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC;AAAA,EAC7B,OAAO,GAAG,SAAS,UAAU;AAAA;AAoBxB,IAAM,kBAAkB,CAAC,WAA6C;AAAA,EAC3E,MAAM,SAAS,OAAO,UAAU,IAAI,SAAS,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC,CAAC;AAAA,EAC3F,MAAM,SAAS,OAAO;AAAA,EACtB,MAAM,SAAS,OAAO,UAAU;AAAA,EAEhC,MAAM,UAAU,CAAC,WAA2B,cAAc,QAAQ,MAAM;AAAA,EAExE,MAAM,MAAM,OAAO,QAA4C;AAAA,IAC7D,IAAI;AAAA,MACF,MAAM,SAAS,MAAM,OAAO,KAC1B,IAAI,iBAAiB;AAAA,QACnB,QAAQ;AAAA,QACR,KAAK,QAAQ,GAAG;AAAA,MAClB,CAAC,CACH;AAAA,MAEA,MAAM,QAAQ,MAAM,OAAO,KAAM,qBAAqB;AAAA,MACtD,OAAO,IAAI,WAAW,KAAK;AAAA,MAC3B,OAAO,OAAgB;AAAA,MACvB,MAAM,MAAM;AAAA,MACZ,IAAI,IAAI,SAAS,eAAe,IAAI,WAAW,mBAAmB,KAAK;AAAA,QACrE,OAAO;AAAA,MACT;AAAA,MACA,MAAM;AAAA;AAAA;AAAA,EAIV,MAAM,MAAM,OAAO,KAAa,UAAqC;AAAA,IACnE,MAAM,QAAQ,QAAQ,GAAG;AAAA,IAGzB,IAAI;AAAA,MACF,MAAM,OAAO,KACX,IAAI,kBAAkB;AAAA,QACpB,QAAQ;AAAA,QACR,KAAK;AAAA,MACP,CAAC,CACH;AAAA,MACA;AAAA,MACA,OAAO,OAAgB;AAAA,MACvB,MAAM,MAAM;AAAA,MACZ,IAAI,IAAI,SAAS,cAAc,IAAI,WAAW,mBAAmB,KAAK;AAAA,QACpE,MAAM;AAAA,MACR;AAAA;AAAA,IAKF,MAAM,OAAO,KACX,IAAI,iBAAiB;AAAA,MACnB,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC,CACH;AAAA;AAAA,EAGF,OAAO,EAAE,KAAK,IAAI;AAAA;",
|
|
8
|
+
"debugId": "FBB9BF9E1762965D64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S3 Storage Provider for CAS
|
|
3
|
+
*
|
|
4
|
+
* Implements StorageProvider with:
|
|
5
|
+
* - S3 backend storage
|
|
6
|
+
* - Internal HeadObject check in put() to avoid redundant uploads
|
|
7
|
+
*/
|
|
8
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
9
|
+
import type { StorageProvider } from "@casfa/storage-core";
|
|
10
|
+
/**
|
|
11
|
+
* S3 Storage configuration
|
|
12
|
+
*/
|
|
13
|
+
export type S3StorageConfig = {
|
|
14
|
+
/** S3 bucket name */
|
|
15
|
+
bucket: string;
|
|
16
|
+
/** AWS region for the S3 bucket (e.g. "us-west-2") */
|
|
17
|
+
region?: string;
|
|
18
|
+
/** Optional S3 client (for testing or custom config) */
|
|
19
|
+
client?: S3Client;
|
|
20
|
+
/** Key prefix in S3 (default: "cas/v1/") */
|
|
21
|
+
prefix?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Create an S3-backed storage provider
|
|
25
|
+
*/
|
|
26
|
+
export declare const createS3Storage: (config: S3StorageConfig) => StorageProvider;
|
|
27
|
+
//# sourceMappingURL=s3-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-storage.d.ts","sourceRoot":"","sources":["../src/s3-storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAIL,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAa3D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,eAAe,KAAG,eA2DzD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@casfa/storage-s3",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "S3 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": "
|
|
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 .",
|