@e280/mammoth 0.1.0-5 → 0.1.0-6
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 +2 -2
- package/package.json +2 -2
- package/s/browser/opfs-bucket.ts +0 -6
- package/s/core/consts.ts +9 -0
- package/s/core/mammoth.ts +36 -54
- package/s/core/memory-bucket.ts +0 -4
- package/s/core/types.ts +15 -2
- package/s/core/utils/is-expired.ts +2 -1
- package/s/core/utils/manifest.ts +89 -0
- package/s/node/disk-bucket.ts +0 -5
- package/s/test.ts +4 -3
- package/x/browser/opfs-bucket.d.ts +0 -1
- package/x/browser/opfs-bucket.js +0 -5
- package/x/browser/opfs-bucket.js.map +1 -1
- package/x/core/consts.d.ts +5 -0
- package/x/core/consts.js +7 -0
- package/x/core/consts.js.map +1 -0
- package/x/core/mammoth.d.ts +3 -3
- package/x/core/mammoth.js +34 -51
- package/x/core/mammoth.js.map +1 -1
- package/x/core/memory-bucket.d.ts +0 -1
- package/x/core/memory-bucket.js +0 -3
- package/x/core/memory-bucket.js.map +1 -1
- package/x/core/types.d.ts +11 -2
- package/x/core/utils/is-expired.js +2 -1
- package/x/core/utils/is-expired.js.map +1 -1
- package/x/core/utils/manifest.d.ts +18 -0
- package/x/core/utils/manifest.js +69 -0
- package/x/core/utils/manifest.js.map +1 -0
- package/x/node/disk-bucket.d.ts +0 -1
- package/x/node/disk-bucket.js +0 -4
- package/x/node/disk-bucket.js.map +1 -1
- package/x/test.js +4 -3
- package/x/test.js.map +1 -1
package/README.md
CHANGED
|
@@ -74,9 +74,9 @@ const mammoth = new Mammoth()
|
|
|
74
74
|
```ts
|
|
75
75
|
const exists = await mammoth.has(hash)
|
|
76
76
|
```
|
|
77
|
-
- **get file
|
|
77
|
+
- **get file info,** including size in bytes, added timestamp, and bucket id.
|
|
78
78
|
```ts
|
|
79
|
-
const size = await mammoth.
|
|
79
|
+
const {size, added, id} = await mammoth.info(hash)
|
|
80
80
|
```
|
|
81
81
|
- **get stats,** for the whole datalake.
|
|
82
82
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/mammoth",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-6",
|
|
4
4
|
"description": "big file storage",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@e280/kv": "^0.1.5",
|
|
27
|
-
"@e280/stz": "^0.3.
|
|
27
|
+
"@e280/stz": "^0.3.5",
|
|
28
28
|
"@noble/hashes": "^2.2.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
package/s/browser/opfs-bucket.ts
CHANGED
|
@@ -20,12 +20,6 @@ export class OpfsBucket implements Bucket {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
async size(id: Id) {
|
|
24
|
-
const handle = await this.#directory.getFileHandle(id)
|
|
25
|
-
const file = await handle.getFile()
|
|
26
|
-
return file.size
|
|
27
|
-
}
|
|
28
|
-
|
|
29
23
|
async delete(id: Id) {
|
|
30
24
|
try {
|
|
31
25
|
await this.#directory.removeEntry(id)
|
package/s/core/consts.ts
ADDED
package/s/core/mammoth.ts
CHANGED
|
@@ -1,100 +1,82 @@
|
|
|
1
1
|
|
|
2
2
|
import {Kv} from "@e280/kv"
|
|
3
|
-
import {
|
|
3
|
+
import {lane, queue} from "@e280/stz"
|
|
4
4
|
|
|
5
|
+
import {consts} from "./consts.js"
|
|
6
|
+
import {Hash, Bucket} from "./types.js"
|
|
7
|
+
import {Manifest} from "./utils/manifest.js"
|
|
5
8
|
import {randomId} from "./utils/random-id.js"
|
|
6
|
-
import {notFound} from "./utils/not-found.js"
|
|
7
9
|
import {MemoryBucket} from "./memory-bucket.js"
|
|
8
|
-
import {isExpired} from "./utils/is-expired.js"
|
|
9
10
|
import {saveAndHash} from "./utils/save-and-hash.js"
|
|
10
|
-
import {Hash, Bucket, Id, Stats, Wip} from "./types.js"
|
|
11
11
|
|
|
12
12
|
/** file storage datalake, content-addressed with blake3 hashes. */
|
|
13
13
|
export class Mammoth {
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#bucket // file blobstore
|
|
14
|
+
#bucket
|
|
15
|
+
#manifest
|
|
16
|
+
#wholesome = lane(consts.max_jobs)
|
|
18
17
|
|
|
19
18
|
constructor(bucket: Bucket = new MemoryBucket(), kv = new Kv()) {
|
|
20
|
-
this.#ids = kv.scope<string>("ids")
|
|
21
|
-
this.#wip = kv.scope<Wip>("wip")
|
|
22
|
-
this.#stats = kv.store<Stats>("stats")
|
|
23
19
|
this.#bucket = bucket
|
|
20
|
+
this.#manifest = new Manifest(kv)
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
async has(hash: Hash) {
|
|
27
|
-
return this.#
|
|
24
|
+
return this.#manifest.hasHash(hash)
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
async
|
|
31
|
-
|
|
32
|
-
return this.#bucket.size(id)
|
|
27
|
+
async info(hash: Hash) {
|
|
28
|
+
return this.#manifest.needInfo(hash)
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
async read(hash: Hash) {
|
|
36
|
-
const id =
|
|
32
|
+
const {id} = await this.#manifest.needInfo(hash)
|
|
37
33
|
return this.#bucket.read(id)
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
async delete(hash: Hash) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
})
|
|
50
|
-
}
|
|
37
|
+
await this.#wholesome(async() => {
|
|
38
|
+
const info = await this.#manifest.getInfo(hash)
|
|
39
|
+
if (info) {
|
|
40
|
+
await this.#manifest.deleteInfo(hash)
|
|
41
|
+
await this.#bucket.delete(info.id)
|
|
42
|
+
await this.#manifest.statsRemoveFile(info.size)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
async write(readable: ReadableStream<Uint8Array>): Promise<Hash> {
|
|
54
48
|
const id = randomId()
|
|
55
49
|
|
|
56
|
-
await this.#
|
|
50
|
+
await this.#manifest.addWip(id)
|
|
57
51
|
const {hash, size} = await saveAndHash(this.#bucket, id, readable)
|
|
58
|
-
await this.#wip.del(id)
|
|
59
52
|
|
|
60
|
-
await this.#
|
|
53
|
+
await this.#wholesome(async() => {
|
|
54
|
+
if (await this.#manifest.hasHash(hash)) {
|
|
55
|
+
await this.#bucket.delete(id) // forget this new file (we already have it)
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
await this.#manifest.saveInfo(hash, {id, size, added: Date.now()})
|
|
59
|
+
await this.#manifest.statsAddFile(size)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
await this.#manifest.deleteWip(id)
|
|
61
64
|
void this.#selfClean().catch(() => {})
|
|
62
65
|
return hash
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
async* hashes() {
|
|
66
|
-
yield* this.#
|
|
69
|
+
yield* this.#manifest.hashes()
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
async stats() {
|
|
70
|
-
return
|
|
73
|
+
return this.#manifest.getStats()
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
#updateStats = queue(async(fn: (stats: Stats) => void) => {
|
|
74
|
-
const stats = await this.stats()
|
|
75
|
-
fn(stats)
|
|
76
|
-
await this.#stats.set(stats)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
#finalizeWrite = queue(async(hash: Hash, id: Id, size: number) => {
|
|
80
|
-
if (await this.#ids.has(hash)) {
|
|
81
|
-
await this.#bucket.delete(id) // forget this new file (we already have it)
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
await this.#ids.set(hash, id)
|
|
85
|
-
await this.#updateStats(stats => {
|
|
86
|
-
stats.count++
|
|
87
|
-
stats.size += size
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
|
|
92
76
|
#selfClean = queue(async() => {
|
|
93
|
-
const expiredIds =
|
|
94
|
-
.filter(([,wip]) => isExpired(wip))
|
|
95
|
-
.map(([id]) => id)
|
|
77
|
+
const expiredIds = await this.#manifest.getExpiredIds()
|
|
96
78
|
await Promise.all(expiredIds.map(id => this.#bucket.delete(id)))
|
|
97
|
-
await this.#
|
|
79
|
+
await this.#manifest.deleteWip(...expiredIds)
|
|
98
80
|
})
|
|
99
81
|
}
|
|
100
82
|
|
package/s/core/memory-bucket.ts
CHANGED
package/s/core/types.ts
CHANGED
|
@@ -5,18 +5,31 @@ export type Id = string
|
|
|
5
5
|
/** file blob store. */
|
|
6
6
|
export type Bucket = {
|
|
7
7
|
has(id: Id): Promise<boolean>
|
|
8
|
-
size(id: Id): Promise<number>
|
|
9
8
|
delete(id: Id): Promise<void>
|
|
10
9
|
read(id: Id): Promise<Blob>
|
|
11
10
|
write(id: Id, readable: ReadableStream<Uint8Array>): Promise<void>
|
|
12
11
|
}
|
|
13
12
|
|
|
13
|
+
/** metadata for a single file. */
|
|
14
|
+
export type Info = {
|
|
15
|
+
|
|
16
|
+
/** bucket id for this file's data. */
|
|
17
|
+
id: Id
|
|
18
|
+
|
|
19
|
+
/** file size in bytes. */
|
|
20
|
+
size: number
|
|
21
|
+
|
|
22
|
+
/** when this file was added to the datalake. */
|
|
23
|
+
added: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** statistics for the whole datalake. */
|
|
14
27
|
export type Stats = {
|
|
15
28
|
|
|
16
29
|
/** total number of bytes in the whole datalake. */
|
|
17
30
|
size: number
|
|
18
31
|
|
|
19
|
-
/** total number of
|
|
32
|
+
/** total number of files in the datalake. */
|
|
20
33
|
count: number
|
|
21
34
|
}
|
|
22
35
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
import {time} from "@e280/stz"
|
|
3
3
|
import {Wip} from "../types.js"
|
|
4
|
+
import {consts} from "../consts.js"
|
|
4
5
|
|
|
5
6
|
export function isExpired({created}: Wip) {
|
|
6
7
|
const since = Date.now() - created
|
|
7
|
-
return since > time.days(
|
|
8
|
+
return since > time.days(consts.expiry_time)
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
|
|
2
|
+
import {Kv} from "@e280/kv"
|
|
3
|
+
import {collect, got} from "@e280/stz"
|
|
4
|
+
import {consts} from "../consts.js"
|
|
5
|
+
import {notFound} from "./not-found.js"
|
|
6
|
+
import {isExpired} from "./is-expired.js"
|
|
7
|
+
import {Hash, Id, Info, Stats, Wip} from "../types.js"
|
|
8
|
+
|
|
9
|
+
export class Manifest {
|
|
10
|
+
|
|
11
|
+
/** associates file hashes with bucket ids */
|
|
12
|
+
#info
|
|
13
|
+
|
|
14
|
+
/** temporary record of writes in-progress */
|
|
15
|
+
#wip
|
|
16
|
+
|
|
17
|
+
/** statistics about the whole datalake */
|
|
18
|
+
#stats
|
|
19
|
+
|
|
20
|
+
constructor(kv = new Kv()) {
|
|
21
|
+
this.#info = kv.scope<Info>("info")
|
|
22
|
+
this.#wip = kv.scope<Wip>("wip")
|
|
23
|
+
this.#stats = kv.store<Stats>("stats")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async* hashes() {
|
|
27
|
+
yield* this.#info.keys()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async hasHash(hash: Hash) {
|
|
31
|
+
return this.#info.has(hash)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async saveInfo(hash: Hash, info: Info) {
|
|
35
|
+
await this.#info.set(hash, info)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getInfo(hash: Hash) {
|
|
39
|
+
return await this.#info.get(hash)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async needInfo(hash: Hash) {
|
|
43
|
+
return got(await this.getInfo(hash), notFound(hash))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async deleteInfo(hash: Hash) {
|
|
47
|
+
await this.#info.del(hash)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async addWip(id: Id) {
|
|
51
|
+
await this.#wip.set(id, {created: Date.now()})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async deleteWip(...ids: Id[]) {
|
|
55
|
+
await this.#wip.del(...ids)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async statsAddFile(size: number) {
|
|
59
|
+
await this.#updateStats(stats => {
|
|
60
|
+
stats.count += 1
|
|
61
|
+
stats.size += size
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async statsRemoveFile(size: number) {
|
|
66
|
+
await this.#updateStats(stats => {
|
|
67
|
+
stats.count -= 1
|
|
68
|
+
stats.size -= size
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getExpiredIds() {
|
|
73
|
+
const limit = consts.self_clean_limit
|
|
74
|
+
return (await collect(this.#wip.entries({limit})))
|
|
75
|
+
.filter(([,wip]) => isExpired(wip))
|
|
76
|
+
.map(([id]) => id)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getStats() {
|
|
80
|
+
return structuredClone((await this.#stats.get()) ?? {count: 0, size: 0})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async #updateStats(fn: (stats: Stats) => void) {
|
|
84
|
+
const stats = await this.getStats()
|
|
85
|
+
fn(stats)
|
|
86
|
+
await this.#stats.set(stats)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
package/s/node/disk-bucket.ts
CHANGED
package/s/test.ts
CHANGED
|
@@ -50,7 +50,7 @@ await science.run({
|
|
|
50
50
|
".write empty file": test(async() => {
|
|
51
51
|
const {mammoth} = setup()
|
|
52
52
|
const hash = await mammoth.write(new Blob().stream())
|
|
53
|
-
expect(await mammoth.
|
|
53
|
+
expect((await mammoth.info(hash)).size).is(0)
|
|
54
54
|
expect((await mammoth.read(hash)).size).is(0)
|
|
55
55
|
}),
|
|
56
56
|
|
|
@@ -84,8 +84,9 @@ await science.run({
|
|
|
84
84
|
|
|
85
85
|
".size": test(async() => {
|
|
86
86
|
const {mammoth} = setup()
|
|
87
|
-
const
|
|
88
|
-
|
|
87
|
+
const b = blob()
|
|
88
|
+
const hash = await mammoth.write(b.stream())
|
|
89
|
+
expect((await mammoth.info(hash)).size).is(b.size)
|
|
89
90
|
}),
|
|
90
91
|
|
|
91
92
|
".delete": test(async() => {
|
|
@@ -3,7 +3,6 @@ export declare class OpfsBucket implements Bucket {
|
|
|
3
3
|
#private;
|
|
4
4
|
constructor(directory: FileSystemDirectoryHandle);
|
|
5
5
|
has(id: Id): Promise<boolean>;
|
|
6
|
-
size(id: Id): Promise<number>;
|
|
7
6
|
delete(id: Id): Promise<void>;
|
|
8
7
|
read(id: Id): Promise<File>;
|
|
9
8
|
write(id: Id, readable: ReadableStream<Uint8Array>): Promise<void>;
|
package/x/browser/opfs-bucket.js
CHANGED
|
@@ -15,11 +15,6 @@ export class OpfsBucket {
|
|
|
15
15
|
throw error;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
async size(id) {
|
|
19
|
-
const handle = await this.#directory.getFileHandle(id);
|
|
20
|
-
const file = await handle.getFile();
|
|
21
|
-
return file.size;
|
|
22
|
-
}
|
|
23
18
|
async delete(id) {
|
|
24
19
|
try {
|
|
25
20
|
await this.#directory.removeEntry(id);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opfs-bucket.js","sourceRoot":"","sources":["../../s/browser/opfs-bucket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,UAAU,EAAC,MAAM,yBAAyB,CAAA;AAElD,MAAM,OAAO,UAAU;IACtB,UAAU,CAAA;IAEV,YAAY,SAAoC;QAC/C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;YACvC,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YACnC,MAAM,KAAK,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"opfs-bucket.js","sourceRoot":"","sources":["../../s/browser/opfs-bucket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,UAAU,EAAC,MAAM,yBAAyB,CAAA;AAElD,MAAM,OAAO,UAAU;IACtB,UAAU,CAAA;IAEV,YAAY,SAAoC;QAC/C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;YACvC,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YACnC,MAAM,KAAK,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAM;QAClB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QACtC,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;gBACrB,MAAM,KAAK,CAAA;QACb,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAM;QAChB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QACtD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,EAAM,EAAE,QAAoC;QACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,EAAE,EAAC,MAAM,EAAE,IAAI,EAAC,CAAC,CAAA;QACtE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAA;QAC9C,MAAM,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAChC,CAAC;CACD"}
|
package/x/core/consts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../s/core/consts.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAE9B,MAAM,CAAC,MAAM,MAAM,GAAG;IACrB,QAAQ,EAAE,EAAE;IACZ,gBAAgB,EAAE,EAAE;IACpB,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;CACzB,CAAA"}
|
package/x/core/mammoth.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Kv } from "@e280/kv";
|
|
2
|
-
import { Hash, Bucket
|
|
2
|
+
import { Hash, Bucket } from "./types.js";
|
|
3
3
|
/** file storage datalake, content-addressed with blake3 hashes. */
|
|
4
4
|
export declare class Mammoth {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(bucket?: Bucket, kv?: Kv<any>);
|
|
7
7
|
has(hash: Hash): Promise<boolean>;
|
|
8
|
-
|
|
8
|
+
info(hash: Hash): Promise<import("./types.js").Info>;
|
|
9
9
|
read(hash: Hash): Promise<Blob>;
|
|
10
10
|
delete(hash: Hash): Promise<void>;
|
|
11
11
|
write(readable: ReadableStream<Uint8Array>): Promise<Hash>;
|
|
12
12
|
hashes(): AsyncGenerator<string, void, unknown>;
|
|
13
|
-
stats(): Promise<Stats>;
|
|
13
|
+
stats(): Promise<import("./types.js").Stats>;
|
|
14
14
|
}
|
package/x/core/mammoth.js
CHANGED
|
@@ -1,83 +1,66 @@
|
|
|
1
1
|
import { Kv } from "@e280/kv";
|
|
2
|
-
import {
|
|
2
|
+
import { lane, queue } from "@e280/stz";
|
|
3
|
+
import { consts } from "./consts.js";
|
|
4
|
+
import { Manifest } from "./utils/manifest.js";
|
|
3
5
|
import { randomId } from "./utils/random-id.js";
|
|
4
|
-
import { notFound } from "./utils/not-found.js";
|
|
5
6
|
import { MemoryBucket } from "./memory-bucket.js";
|
|
6
|
-
import { isExpired } from "./utils/is-expired.js";
|
|
7
7
|
import { saveAndHash } from "./utils/save-and-hash.js";
|
|
8
8
|
/** file storage datalake, content-addressed with blake3 hashes. */
|
|
9
9
|
export class Mammoth {
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#bucket; // file blobstore
|
|
10
|
+
#bucket;
|
|
11
|
+
#manifest;
|
|
12
|
+
#wholesome = lane(consts.max_jobs);
|
|
14
13
|
constructor(bucket = new MemoryBucket(), kv = new Kv()) {
|
|
15
|
-
this.#ids = kv.scope("ids");
|
|
16
|
-
this.#wip = kv.scope("wip");
|
|
17
|
-
this.#stats = kv.store("stats");
|
|
18
14
|
this.#bucket = bucket;
|
|
15
|
+
this.#manifest = new Manifest(kv);
|
|
19
16
|
}
|
|
20
17
|
async has(hash) {
|
|
21
|
-
return this.#
|
|
18
|
+
return this.#manifest.hasHash(hash);
|
|
22
19
|
}
|
|
23
|
-
async
|
|
24
|
-
|
|
25
|
-
return this.#bucket.size(id);
|
|
20
|
+
async info(hash) {
|
|
21
|
+
return this.#manifest.needInfo(hash);
|
|
26
22
|
}
|
|
27
23
|
async read(hash) {
|
|
28
|
-
const id =
|
|
24
|
+
const { id } = await this.#manifest.needInfo(hash);
|
|
29
25
|
return this.#bucket.read(id);
|
|
30
26
|
}
|
|
31
27
|
async delete(hash) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
}
|
|
28
|
+
await this.#wholesome(async () => {
|
|
29
|
+
const info = await this.#manifest.getInfo(hash);
|
|
30
|
+
if (info) {
|
|
31
|
+
await this.#manifest.deleteInfo(hash);
|
|
32
|
+
await this.#bucket.delete(info.id);
|
|
33
|
+
await this.#manifest.statsRemoveFile(info.size);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
42
36
|
}
|
|
43
37
|
async write(readable) {
|
|
44
38
|
const id = randomId();
|
|
45
|
-
await this.#
|
|
39
|
+
await this.#manifest.addWip(id);
|
|
46
40
|
const { hash, size } = await saveAndHash(this.#bucket, id, readable);
|
|
47
|
-
await this.#
|
|
48
|
-
|
|
41
|
+
await this.#wholesome(async () => {
|
|
42
|
+
if (await this.#manifest.hasHash(hash)) {
|
|
43
|
+
await this.#bucket.delete(id); // forget this new file (we already have it)
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
await this.#manifest.saveInfo(hash, { id, size, added: Date.now() });
|
|
47
|
+
await this.#manifest.statsAddFile(size);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
await this.#manifest.deleteWip(id);
|
|
49
51
|
void this.#selfClean().catch(() => { });
|
|
50
52
|
return hash;
|
|
51
53
|
}
|
|
52
54
|
async *hashes() {
|
|
53
|
-
yield* this.#
|
|
55
|
+
yield* this.#manifest.hashes();
|
|
54
56
|
}
|
|
55
57
|
async stats() {
|
|
56
|
-
return
|
|
58
|
+
return this.#manifest.getStats();
|
|
57
59
|
}
|
|
58
|
-
#updateStats = queue(async (fn) => {
|
|
59
|
-
const stats = await this.stats();
|
|
60
|
-
fn(stats);
|
|
61
|
-
await this.#stats.set(stats);
|
|
62
|
-
});
|
|
63
|
-
#finalizeWrite = queue(async (hash, id, size) => {
|
|
64
|
-
if (await this.#ids.has(hash)) {
|
|
65
|
-
await this.#bucket.delete(id); // forget this new file (we already have it)
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
await this.#ids.set(hash, id);
|
|
69
|
-
await this.#updateStats(stats => {
|
|
70
|
-
stats.count++;
|
|
71
|
-
stats.size += size;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
60
|
#selfClean = queue(async () => {
|
|
76
|
-
const expiredIds =
|
|
77
|
-
.filter(([, wip]) => isExpired(wip))
|
|
78
|
-
.map(([id]) => id);
|
|
61
|
+
const expiredIds = await this.#manifest.getExpiredIds();
|
|
79
62
|
await Promise.all(expiredIds.map(id => this.#bucket.delete(id)));
|
|
80
|
-
await this.#
|
|
63
|
+
await this.#manifest.deleteWip(...expiredIds);
|
|
81
64
|
});
|
|
82
65
|
}
|
|
83
66
|
//# sourceMappingURL=mammoth.js.map
|
package/x/core/mammoth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mammoth.js","sourceRoot":"","sources":["../../s/core/mammoth.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,EAAE,EAAC,MAAM,UAAU,CAAA;AAC3B,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"mammoth.js","sourceRoot":"","sources":["../../s/core/mammoth.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,6 @@ import { Bucket, Id } from "./types.js";
|
|
|
2
2
|
export declare class MemoryBucket implements Bucket {
|
|
3
3
|
#private;
|
|
4
4
|
has(id: Id): Promise<boolean>;
|
|
5
|
-
size(id: Id): Promise<number>;
|
|
6
5
|
delete(id: Id): Promise<void>;
|
|
7
6
|
read(id: Id): Promise<Blob>;
|
|
8
7
|
write(id: Id, readable: ReadableStream<Uint8Array>): Promise<void>;
|
package/x/core/memory-bucket.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-bucket.js","sourceRoot":"","sources":["../../s/core/memory-bucket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAEzC,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAE1C,MAAM,OAAO,YAAY;IACxB,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAA;IAEpC,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"memory-bucket.js","sourceRoot":"","sources":["../../s/core/memory-bucket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAEzC,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAE1C,MAAM,OAAO,YAAY;IACxB,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAA;IAEpC,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAM;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACrB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAM;QAChB,OAAO,IAAI,IAAI,CACd,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAA4B,CAAC,EACnD,EAAC,IAAI,EAAE,0BAA0B,EAAC,CAClC,CAAA;IACF,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,EAAM,EAAE,QAAoC;QACvD,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;QACvB,MAAM,KAAK,GAAiB,EAAE,CAAA;QAE9B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACjB,IAAI,KAAK,EAAE;gBAAE,MAAM,GAAG,EAAE,CAAA;QACzB,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAC3B,CAAC;CACD"}
|
package/x/core/types.d.ts
CHANGED
|
@@ -3,15 +3,24 @@ export type Id = string;
|
|
|
3
3
|
/** file blob store. */
|
|
4
4
|
export type Bucket = {
|
|
5
5
|
has(id: Id): Promise<boolean>;
|
|
6
|
-
size(id: Id): Promise<number>;
|
|
7
6
|
delete(id: Id): Promise<void>;
|
|
8
7
|
read(id: Id): Promise<Blob>;
|
|
9
8
|
write(id: Id, readable: ReadableStream<Uint8Array>): Promise<void>;
|
|
10
9
|
};
|
|
10
|
+
/** metadata for a single file. */
|
|
11
|
+
export type Info = {
|
|
12
|
+
/** bucket id for this file's data. */
|
|
13
|
+
id: Id;
|
|
14
|
+
/** file size in bytes. */
|
|
15
|
+
size: number;
|
|
16
|
+
/** when this file was added to the datalake. */
|
|
17
|
+
added: number;
|
|
18
|
+
};
|
|
19
|
+
/** statistics for the whole datalake. */
|
|
11
20
|
export type Stats = {
|
|
12
21
|
/** total number of bytes in the whole datalake. */
|
|
13
22
|
size: number;
|
|
14
|
-
/** total number of
|
|
23
|
+
/** total number of files in the datalake. */
|
|
15
24
|
count: number;
|
|
16
25
|
};
|
|
17
26
|
export type Wip = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { time } from "@e280/stz";
|
|
2
|
+
import { consts } from "../consts.js";
|
|
2
3
|
export function isExpired({ created }) {
|
|
3
4
|
const since = Date.now() - created;
|
|
4
|
-
return since > time.days(
|
|
5
|
+
return since > time.days(consts.expiry_time);
|
|
5
6
|
}
|
|
6
7
|
//# sourceMappingURL=is-expired.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-expired.js","sourceRoot":"","sources":["../../../s/core/utils/is-expired.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"is-expired.js","sourceRoot":"","sources":["../../../s/core/utils/is-expired.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAE9B,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAA;AAEnC,MAAM,UAAU,SAAS,CAAC,EAAC,OAAO,EAAM;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;IAClC,OAAO,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;AAC7C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Kv } from "@e280/kv";
|
|
2
|
+
import { Hash, Id, Info, Stats } from "../types.js";
|
|
3
|
+
export declare class Manifest {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(kv?: Kv<any>);
|
|
6
|
+
hashes(): AsyncGenerator<string, void, unknown>;
|
|
7
|
+
hasHash(hash: Hash): Promise<boolean>;
|
|
8
|
+
saveInfo(hash: Hash, info: Info): Promise<void>;
|
|
9
|
+
getInfo(hash: Hash): Promise<Info | undefined>;
|
|
10
|
+
needInfo(hash: Hash): Promise<Info>;
|
|
11
|
+
deleteInfo(hash: Hash): Promise<void>;
|
|
12
|
+
addWip(id: Id): Promise<void>;
|
|
13
|
+
deleteWip(...ids: Id[]): Promise<void>;
|
|
14
|
+
statsAddFile(size: number): Promise<void>;
|
|
15
|
+
statsRemoveFile(size: number): Promise<void>;
|
|
16
|
+
getExpiredIds(): Promise<string[]>;
|
|
17
|
+
getStats(): Promise<Stats>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Kv } from "@e280/kv";
|
|
2
|
+
import { collect, got } from "@e280/stz";
|
|
3
|
+
import { consts } from "../consts.js";
|
|
4
|
+
import { notFound } from "./not-found.js";
|
|
5
|
+
import { isExpired } from "./is-expired.js";
|
|
6
|
+
export class Manifest {
|
|
7
|
+
/** associates file hashes with bucket ids */
|
|
8
|
+
#info;
|
|
9
|
+
/** temporary record of writes in-progress */
|
|
10
|
+
#wip;
|
|
11
|
+
/** statistics about the whole datalake */
|
|
12
|
+
#stats;
|
|
13
|
+
constructor(kv = new Kv()) {
|
|
14
|
+
this.#info = kv.scope("info");
|
|
15
|
+
this.#wip = kv.scope("wip");
|
|
16
|
+
this.#stats = kv.store("stats");
|
|
17
|
+
}
|
|
18
|
+
async *hashes() {
|
|
19
|
+
yield* this.#info.keys();
|
|
20
|
+
}
|
|
21
|
+
async hasHash(hash) {
|
|
22
|
+
return this.#info.has(hash);
|
|
23
|
+
}
|
|
24
|
+
async saveInfo(hash, info) {
|
|
25
|
+
await this.#info.set(hash, info);
|
|
26
|
+
}
|
|
27
|
+
async getInfo(hash) {
|
|
28
|
+
return await this.#info.get(hash);
|
|
29
|
+
}
|
|
30
|
+
async needInfo(hash) {
|
|
31
|
+
return got(await this.getInfo(hash), notFound(hash));
|
|
32
|
+
}
|
|
33
|
+
async deleteInfo(hash) {
|
|
34
|
+
await this.#info.del(hash);
|
|
35
|
+
}
|
|
36
|
+
async addWip(id) {
|
|
37
|
+
await this.#wip.set(id, { created: Date.now() });
|
|
38
|
+
}
|
|
39
|
+
async deleteWip(...ids) {
|
|
40
|
+
await this.#wip.del(...ids);
|
|
41
|
+
}
|
|
42
|
+
async statsAddFile(size) {
|
|
43
|
+
await this.#updateStats(stats => {
|
|
44
|
+
stats.count += 1;
|
|
45
|
+
stats.size += size;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async statsRemoveFile(size) {
|
|
49
|
+
await this.#updateStats(stats => {
|
|
50
|
+
stats.count -= 1;
|
|
51
|
+
stats.size -= size;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async getExpiredIds() {
|
|
55
|
+
const limit = consts.self_clean_limit;
|
|
56
|
+
return (await collect(this.#wip.entries({ limit })))
|
|
57
|
+
.filter(([, wip]) => isExpired(wip))
|
|
58
|
+
.map(([id]) => id);
|
|
59
|
+
}
|
|
60
|
+
async getStats() {
|
|
61
|
+
return structuredClone((await this.#stats.get()) ?? { count: 0, size: 0 });
|
|
62
|
+
}
|
|
63
|
+
async #updateStats(fn) {
|
|
64
|
+
const stats = await this.getStats();
|
|
65
|
+
fn(stats);
|
|
66
|
+
await this.#stats.set(stats);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../s/core/utils/manifest.ts"],"names":[],"mappings":"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"}
|
package/x/node/disk-bucket.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export declare class DiskBucket implements Bucket {
|
|
|
3
3
|
#private;
|
|
4
4
|
constructor(directory: string);
|
|
5
5
|
has(id: Id): Promise<boolean>;
|
|
6
|
-
size(id: Id): Promise<number>;
|
|
7
6
|
delete(id: Id): Promise<void>;
|
|
8
7
|
read(id: Id): Promise<Blob>;
|
|
9
8
|
write(id: Id, readable: ReadableStream<Uint8Array>): Promise<void>;
|
package/x/node/disk-bucket.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disk-bucket.js","sourceRoot":"","sources":["../../s/node/disk-bucket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAA;AACpC,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAC,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAC,iBAAiB,EAAE,UAAU,EAAC,MAAM,SAAS,CAAA;AAGrD,OAAO,EAAC,UAAU,EAAC,MAAM,yBAAyB,CAAA;AAElD,MAAM,OAAO,UAAU;IACtB,UAAU,CAAA;IAEV,YAAY,SAAiB;QAC5B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;YAC1B,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YACnC,MAAM,KAAK,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"disk-bucket.js","sourceRoot":"","sources":["../../s/node/disk-bucket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAA;AACpC,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAC,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAC,iBAAiB,EAAE,UAAU,EAAC,MAAM,SAAS,CAAA;AAGrD,OAAO,EAAC,UAAU,EAAC,MAAM,yBAAyB,CAAA;AAElD,MAAM,OAAO,UAAU;IACtB,UAAU,CAAA;IAEV,YAAY,SAAiB;QAC5B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAM;QACf,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;YAC1B,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YACnC,MAAM,KAAK,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAM;QAClB,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7B,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;gBACrB,MAAM,KAAK,CAAA;QACb,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAM;QAChB,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;IAClC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,EAAM,EAAE,QAAoC;QACvD,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAA;QAC/C,MAAM,QAAQ,CACb,QAAQ,CAAC,OAAO,CAAC,QAAe,CAAC,EACjC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CACjC,CAAA;IACF,CAAC;IAED,KAAK,CAAC,EAAM;QACX,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IACjC,CAAC;CACD"}
|
package/x/test.js
CHANGED
|
@@ -42,7 +42,7 @@ await science.run({
|
|
|
42
42
|
".write empty file": test(async () => {
|
|
43
43
|
const { mammoth } = setup();
|
|
44
44
|
const hash = await mammoth.write(new Blob().stream());
|
|
45
|
-
expect(await mammoth.
|
|
45
|
+
expect((await mammoth.info(hash)).size).is(0);
|
|
46
46
|
expect((await mammoth.read(hash)).size).is(0);
|
|
47
47
|
}),
|
|
48
48
|
".write distinct files": test(async () => {
|
|
@@ -72,8 +72,9 @@ await science.run({
|
|
|
72
72
|
}),
|
|
73
73
|
".size": test(async () => {
|
|
74
74
|
const { mammoth } = setup();
|
|
75
|
-
const
|
|
76
|
-
|
|
75
|
+
const b = blob();
|
|
76
|
+
const hash = await mammoth.write(b.stream());
|
|
77
|
+
expect((await mammoth.info(hash)).size).is(b.size);
|
|
77
78
|
}),
|
|
78
79
|
".delete": test(async () => {
|
|
79
80
|
const { mammoth } = setup();
|
package/x/test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.js","sourceRoot":"","sources":["../s/test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../s/test.ts"],"names":[],"mappings":"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"}
|