@e280/quay 0.0.0-11 → 0.0.0-13
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 +59 -0
- package/package.json +2 -1
- package/s/cellar/cask.ts +13 -7
- package/s/cellar/cellar.test.ts +20 -18
- package/s/cellar/cellar.ts +3 -3
- package/s/cellar/forklift.ts +2 -2
- package/s/cellar/memory-forklift.ts +4 -3
- package/s/cellar/opfs-forklift.ts +4 -6
- package/s/dom/components/browser/style.css.ts +30 -30
- package/s/dom/components/dropzone/style.css.ts +11 -12
- package/s/dom/components/filter/component.ts +2 -2
- package/s/dom/components/searchbar/component.ts +5 -2
- package/s/dom/components/sort/component.ts +3 -3
- package/s/dom/theme.css.ts +28 -0
- package/s/dom/views/tree/style.css.ts +9 -9
- package/s/logic/aspects/codex/parts/hierarchy.ts +1 -0
- package/s/logic/group.ts +5 -3
- package/s/logic/presets/media/library.test.ts +41 -14
- package/s/logic/presets/media/library.ts +25 -17
- package/x/cellar/cask.d.ts +4 -4
- package/x/cellar/cask.js +13 -9
- package/x/cellar/cask.js.map +1 -1
- package/x/cellar/cellar.d.ts +1 -1
- package/x/cellar/cellar.js +3 -3
- package/x/cellar/cellar.js.map +1 -1
- package/x/cellar/cellar.test.js +19 -18
- package/x/cellar/cellar.test.js.map +1 -1
- package/x/cellar/forklift.d.ts +2 -2
- package/x/cellar/memory-forklift.d.ts +2 -2
- package/x/cellar/memory-forklift.js +3 -2
- package/x/cellar/memory-forklift.js.map +1 -1
- package/x/cellar/opfs-forklift.d.ts +2 -2
- package/x/cellar/opfs-forklift.js +3 -5
- package/x/cellar/opfs-forklift.js.map +1 -1
- package/x/demo/main.bundle.min.js +104 -71
- package/x/demo/main.bundle.min.js.map +2 -2
- package/x/dom/components/browser/style.css.js +30 -29
- package/x/dom/components/browser/style.css.js.map +1 -1
- package/x/dom/components/dropzone/style.css.js +11 -11
- package/x/dom/components/filter/component.js +2 -2
- package/x/dom/components/searchbar/component.js +5 -1
- package/x/dom/components/searchbar/component.js.map +1 -1
- package/x/dom/components/sort/component.js +3 -3
- package/x/dom/theme.css.js +28 -0
- package/x/dom/theme.css.js.map +1 -1
- package/x/dom/views/tree/style.css.js +9 -9
- package/x/index.html +2 -2
- package/x/logic/aspects/codex/parts/hierarchy.js +1 -0
- package/x/logic/aspects/codex/parts/hierarchy.js.map +1 -1
- package/x/logic/group.d.ts +3 -3
- package/x/logic/group.js +3 -2
- package/x/logic/group.js.map +1 -1
- package/x/logic/presets/media/library.d.ts +4 -40
- package/x/logic/presets/media/library.js +21 -16
- package/x/logic/presets/media/library.js.map +1 -1
- package/x/logic/presets/media/library.test.d.ts +3 -2
- package/x/logic/presets/media/library.test.js +34 -14
- package/x/logic/presets/media/library.test.js.map +1 -1
|
@@ -3,40 +3,67 @@ import {Txt} from "@e280/stz"
|
|
|
3
3
|
import {expect, Science, test} from "@e280/science"
|
|
4
4
|
|
|
5
5
|
import {MediaLibrary} from "./library.js"
|
|
6
|
+
import {Permissions} from "../../permissions.js"
|
|
6
7
|
|
|
7
8
|
delete (globalThis as any).localStorage
|
|
8
9
|
|
|
9
10
|
export default Science.suite({
|
|
10
|
-
"
|
|
11
|
+
"uploads files into cellar and index": test(async() => {
|
|
11
12
|
const group = new MediaLibrary()
|
|
12
|
-
|
|
13
|
+
await group.upload([file("hello.txt", "hello")], group.config.root)
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
+
const record = await recordByLabel(group, "hello.txt")
|
|
16
|
+
const item = group.findByHash(record.hash)!
|
|
15
17
|
|
|
18
|
+
expect(item.specimen.label).is("hello.txt")
|
|
16
19
|
expect(await group.cellar.has(record.hash)).is(true)
|
|
17
|
-
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
"upload respects upload permission": test(async() => {
|
|
23
|
+
const group = new MediaLibrary()
|
|
24
|
+
const file = new File([Txt.toBytes("hello")], "hello.txt", {type: "text/plain"})
|
|
25
|
+
group.config.permissions = () => Permissions.readOnly
|
|
26
|
+
|
|
27
|
+
expect(() => group.upload([file], group.config.root)).throws()
|
|
18
28
|
}),
|
|
19
29
|
|
|
20
30
|
"lists media records": test(async() => {
|
|
21
31
|
const store = new MediaLibrary()
|
|
22
|
-
|
|
23
|
-
const record = await store.importFile(file)
|
|
24
|
-
const records = []
|
|
25
|
-
for await (const record of store.records())
|
|
26
|
-
records.push(record)
|
|
32
|
+
await store.upload([file("image.png", "image", "image/png")], store.config.root)
|
|
27
33
|
|
|
28
|
-
expect(
|
|
34
|
+
expect(await recordByLabel(store, "image.png")).ok()
|
|
29
35
|
}),
|
|
30
36
|
|
|
31
|
-
"
|
|
37
|
+
"deletes media records and bytes": test(async() => {
|
|
32
38
|
const store = new MediaLibrary()
|
|
33
|
-
|
|
34
|
-
const record = await store.importFile(file)
|
|
39
|
+
await store.upload([file("delete.png", "delete-image", "image/png")], store.config.root)
|
|
35
40
|
|
|
36
|
-
await store.
|
|
41
|
+
const record = await recordByLabel(store, "delete.png")
|
|
42
|
+
const item = store.findByHash(record.hash)!
|
|
43
|
+
|
|
44
|
+
await store.delete(item)
|
|
37
45
|
|
|
38
46
|
expect(await store.cellar.has(record.hash)).is(false)
|
|
39
47
|
expect(store.findByHash(record.hash)).is(undefined)
|
|
40
48
|
}),
|
|
49
|
+
|
|
41
50
|
})
|
|
42
51
|
|
|
52
|
+
function file(name: string, text: string, type = "text/plain") {
|
|
53
|
+
return new File([Txt.toBytes(text)], name, {type})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function records(store: MediaLibrary) {
|
|
57
|
+
const records = []
|
|
58
|
+
for await (const record of store.records())
|
|
59
|
+
records.push(record)
|
|
60
|
+
return records
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function recordByLabel(store: MediaLibrary, label: string) {
|
|
64
|
+
const record = (await records(store)).find(r => r.label === label)
|
|
65
|
+
if (!record)
|
|
66
|
+
throw new Error(`expected record "${label}"`)
|
|
67
|
+
return record
|
|
68
|
+
}
|
|
69
|
+
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
import {Kv, StorageDriver} from "@e280/kv"
|
|
3
3
|
|
|
4
|
-
import {Cellar} from "../../../cellar/cellar.js"
|
|
5
|
-
import {MediaFormat} from "./schema.js"
|
|
6
4
|
import {MediaGroup} from "./group.js"
|
|
5
|
+
import {Cellar} from "../../../cellar/cellar.js"
|
|
6
|
+
import {MediaFormat, MediaSchema} from "./schema.js"
|
|
7
|
+
import {CodexItem} from "../../aspects/codex/parts/codex-item.js"
|
|
7
8
|
|
|
8
9
|
export type MediaRecord = {
|
|
9
10
|
hash: string
|
|
@@ -33,7 +34,11 @@ export class MediaLibrary extends MediaGroup {
|
|
|
33
34
|
super()
|
|
34
35
|
this.#index = mediaIndex("default")
|
|
35
36
|
this.on.upload.sub(({files, target}) => {
|
|
36
|
-
|
|
37
|
+
return this.#upload(files, target)
|
|
38
|
+
})
|
|
39
|
+
this.on.delete.sub(({items}) => {
|
|
40
|
+
const hashes = this.#hashes(items)
|
|
41
|
+
return this.#delete(hashes)
|
|
37
42
|
})
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -50,13 +55,12 @@ export class MediaLibrary extends MediaGroup {
|
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
async
|
|
54
|
-
|
|
58
|
+
async #upload(files: File[], parent: CodexItem<MediaSchema>) {
|
|
59
|
+
await Promise.all(files.map(file => this.#storeFile(file, parent)))
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
async
|
|
58
|
-
const
|
|
59
|
-
const cask = await this.cellar.save(bytes)
|
|
62
|
+
async #storeFile(file: File, parent: CodexItem<MediaSchema>) {
|
|
63
|
+
const cask = await this.cellar.save(file)
|
|
60
64
|
const existing = await this.#index.get(cask.hash)
|
|
61
65
|
const now = Date.now()
|
|
62
66
|
const record: MediaRecord = {
|
|
@@ -75,15 +79,18 @@ export class MediaLibrary extends MediaGroup {
|
|
|
75
79
|
return record
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
#hashes(items: CodexItem<MediaSchema>[]) {
|
|
83
|
+
return items
|
|
84
|
+
.map(item => item.isKind("file") ? item.specimen.hash : undefined)
|
|
85
|
+
.filter((hash): hash is string => !!hash)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async #delete(hashes: string[]) {
|
|
89
|
+
for (const hash of hashes) {
|
|
90
|
+
await this.#index.del(hash)
|
|
91
|
+
await this.cellar.delete(hash)
|
|
92
|
+
this.#revokePreview(hash)
|
|
85
93
|
}
|
|
86
|
-
this.#revokePreview(hash)
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
findByHash(hash: string) {
|
|
@@ -118,7 +125,7 @@ export class MediaLibrary extends MediaGroup {
|
|
|
118
125
|
|
|
119
126
|
async #loadPreview(record: MediaRecord) {
|
|
120
127
|
const cask = await this.cellar.load(record.hash)
|
|
121
|
-
const blob = new Blob([cask.
|
|
128
|
+
const blob = new Blob([cask.file], {type: record.mime || "image/*"})
|
|
122
129
|
return this.#setPreview(record.hash, URL.createObjectURL(blob))
|
|
123
130
|
}
|
|
124
131
|
|
|
@@ -160,3 +167,4 @@ function mediaIndex(scope: string) {
|
|
|
160
167
|
memoryIndexes.set(scope, index)
|
|
161
168
|
return index
|
|
162
169
|
}
|
|
170
|
+
|
package/x/cellar/cask.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** File with a hash label */
|
|
2
2
|
export declare class Cask {
|
|
3
3
|
hash: string;
|
|
4
|
-
|
|
5
|
-
static hash(
|
|
6
|
-
static make(
|
|
7
|
-
constructor(hash: string,
|
|
4
|
+
file: Blob;
|
|
5
|
+
static hash(file: Blob): Promise<string>;
|
|
6
|
+
static make(file: Blob): Promise<Cask>;
|
|
7
|
+
constructor(hash: string, file: Blob);
|
|
8
8
|
}
|
package/x/cellar/cask.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { Hex } from "@e280/stz";
|
|
2
|
+
import { blake3 } from "@noble/hashes/blake3.js";
|
|
2
3
|
/** File with a hash label */
|
|
3
4
|
export class Cask {
|
|
4
5
|
hash;
|
|
5
|
-
|
|
6
|
-
static async hash(
|
|
7
|
-
const
|
|
8
|
-
|
|
6
|
+
file;
|
|
7
|
+
static async hash(file) {
|
|
8
|
+
const hasher = blake3.create();
|
|
9
|
+
for await (const chunk of file.stream())
|
|
10
|
+
hasher.update(chunk);
|
|
11
|
+
const digest = hasher.digest();
|
|
12
|
+
return Hex.fromBytes(digest);
|
|
9
13
|
}
|
|
10
|
-
static async make(
|
|
11
|
-
const hash = await this.hash(
|
|
12
|
-
return new this(hash,
|
|
14
|
+
static async make(file) {
|
|
15
|
+
const hash = await this.hash(file);
|
|
16
|
+
return new this(hash, file);
|
|
13
17
|
}
|
|
14
|
-
constructor(hash,
|
|
18
|
+
constructor(hash, file) {
|
|
15
19
|
this.hash = hash;
|
|
16
|
-
this.
|
|
20
|
+
this.file = file;
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
23
|
//# sourceMappingURL=cask.js.map
|
package/x/cellar/cask.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cask.js","sourceRoot":"","sources":["../../s/cellar/cask.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"cask.js","sourceRoot":"","sources":["../../s/cellar/cask.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;AAC7B,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAA;AAE9C,6BAA6B;AAC7B,MAAM,OAAO,IAAI;IAgBG;IAAqB;IAfxC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAU;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAA;QAE9B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;YACtC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAErB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAA;QAC9B,OAAO,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAU;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC5B,CAAC;IAED,YAAmB,IAAY,EAAS,IAAU;QAA/B,SAAI,GAAJ,IAAI,CAAQ;QAAS,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;CACtD"}
|
package/x/cellar/cellar.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare class Cellar {
|
|
|
15
15
|
constructor(forklift?: Forklift);
|
|
16
16
|
list(): AsyncIterable<string>;
|
|
17
17
|
has(hash: string): Promise<boolean>;
|
|
18
|
-
save(
|
|
18
|
+
save(file: Blob): Promise<Cask>;
|
|
19
19
|
load(hash: string): Promise<Cask>;
|
|
20
20
|
delete(hash: string): Promise<void>;
|
|
21
21
|
clear(): Promise<void>;
|
package/x/cellar/cellar.js
CHANGED
|
@@ -24,10 +24,10 @@ export class Cellar {
|
|
|
24
24
|
async has(hash) {
|
|
25
25
|
return this.forklift.has(hash);
|
|
26
26
|
}
|
|
27
|
-
async save(
|
|
28
|
-
const cask = await Cask.make(
|
|
27
|
+
async save(file) {
|
|
28
|
+
const cask = await Cask.make(file);
|
|
29
29
|
if (!await this.forklift.has(cask.hash))
|
|
30
|
-
await this.forklift.save(cask.hash, cask.
|
|
30
|
+
await this.forklift.save(cask.hash, cask.file);
|
|
31
31
|
return cask;
|
|
32
32
|
}
|
|
33
33
|
async load(hash) {
|
package/x/cellar/cellar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cellar.js","sourceRoot":"","sources":["../../s/cellar/cellar.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAE9B,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAA;AAEnD;;;;;;;;GAQG;AACH,MAAM,OAAO,MAAM;IAKE;IAJpB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,QAAQ;QACnC,OAAO,IAAI,IAAI,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,CAAC;IAED,YAAoB,WAAqB,IAAI,cAAc,EAAE;QAAzC,aAAQ,GAAR,QAAQ,CAAiC;IAAG,CAAC;IAEjE,KAAK,CAAC,CAAC,IAAI;QACV,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cellar.js","sourceRoot":"","sources":["../../s/cellar/cellar.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAE9B,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAA;AAEnD;;;;;;;;GAQG;AACH,MAAM,OAAO,MAAM;IAKE;IAJpB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,QAAQ;QACnC,OAAO,IAAI,IAAI,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,CAAC;IAED,YAAoB,WAAqB,IAAI,cAAc,EAAE;QAAzC,aAAQ,GAAR,QAAQ,CAAiC;IAAG,CAAC;IAEjE,KAAK,CAAC,CAAC,IAAI;QACV,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAU;QACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YACtC,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/C,OAAO,IAAI,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,IAAI,UAAU,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;QACjH,OAAO,IAAI,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,KAAK,CAAC,KAAK;QACV,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;YACnC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;CACD"}
|
package/x/cellar/cellar.test.js
CHANGED
|
@@ -3,40 +3,41 @@ import { expect, Science, test } from "@e280/science";
|
|
|
3
3
|
import { Cask } from "./cask.js";
|
|
4
4
|
import { Cellar } from "./cellar.js";
|
|
5
5
|
import { MemoryForklift } from "./memory-forklift.js";
|
|
6
|
+
const blob = (text) => new Blob([Txt.toBytes(text)]);
|
|
6
7
|
export default Science.suite({
|
|
7
8
|
"save + load roundtrip": test(async () => {
|
|
8
9
|
const cellar = new Cellar();
|
|
9
10
|
const text = "hello world";
|
|
10
|
-
const
|
|
11
|
-
await cellar.save(
|
|
12
|
-
const hash = await Cask.hash(
|
|
11
|
+
const file = blob(text);
|
|
12
|
+
await cellar.save(file);
|
|
13
|
+
const hash = await Cask.hash(file);
|
|
13
14
|
expect(await cellar.has(hash)).is(true);
|
|
14
15
|
const loaded = await cellar.load(hash);
|
|
15
16
|
expect(loaded.hash).is(hash);
|
|
16
|
-
expect(
|
|
17
|
+
expect(await loaded.file.text()).is(text);
|
|
17
18
|
}),
|
|
18
19
|
"save is idempotent": test(async () => {
|
|
19
20
|
const cellar = new Cellar();
|
|
20
|
-
const
|
|
21
|
-
await cellar.save(
|
|
22
|
-
await cellar.save(
|
|
23
|
-
const hash = await Cask.hash(
|
|
21
|
+
const file = blob("foo bar");
|
|
22
|
+
await cellar.save(file);
|
|
23
|
+
await cellar.save(file); // again
|
|
24
|
+
const hash = await Cask.hash(file);
|
|
24
25
|
expect(await cellar.has(hash)).is(true);
|
|
25
26
|
}),
|
|
26
27
|
"throws on corruption": test(async () => {
|
|
27
28
|
const forklift = new MemoryForklift();
|
|
28
29
|
const cellar = new Cellar(forklift);
|
|
29
|
-
const good =
|
|
30
|
-
const bad =
|
|
30
|
+
const good = blob("valid data");
|
|
31
|
+
const bad = blob("corrupt data");
|
|
31
32
|
const hash = await Cask.hash(good);
|
|
32
33
|
await forklift.save(hash, bad);
|
|
33
34
|
await expect(async () => cellar.load(hash)).throwsAsync();
|
|
34
35
|
}),
|
|
35
36
|
"delete removes file": test(async () => {
|
|
36
37
|
const cellar = new Cellar();
|
|
37
|
-
const
|
|
38
|
-
await cellar.save(
|
|
39
|
-
const hash = await Cask.hash(
|
|
38
|
+
const file = blob("temporary data");
|
|
39
|
+
await cellar.save(file);
|
|
40
|
+
const hash = await Cask.hash(file);
|
|
40
41
|
expect(await cellar.has(hash)).is(true);
|
|
41
42
|
await cellar.delete(hash);
|
|
42
43
|
expect(await cellar.has(hash)).is(false);
|
|
@@ -50,21 +51,21 @@ export default Science.suite({
|
|
|
50
51
|
const cellar = new Cellar();
|
|
51
52
|
const texts = ["a", "b", "c"];
|
|
52
53
|
for (const t of texts)
|
|
53
|
-
await cellar.save(
|
|
54
|
+
await cellar.save(blob(t));
|
|
54
55
|
const hashes = [];
|
|
55
56
|
for await (const hash of cellar.list())
|
|
56
57
|
hashes.push(hash);
|
|
57
58
|
expect(hashes.length).is(3);
|
|
58
59
|
for (const t of texts) {
|
|
59
|
-
const h = await Cask.hash(
|
|
60
|
+
const h = await Cask.hash(blob(t));
|
|
60
61
|
expect(hashes.includes(h)).is(true);
|
|
61
62
|
}
|
|
62
63
|
}),
|
|
63
64
|
"clear removes all entries": test(async () => {
|
|
64
65
|
const cellar = new Cellar();
|
|
65
|
-
await cellar.save(
|
|
66
|
-
await cellar.save(
|
|
67
|
-
await cellar.save(
|
|
66
|
+
await cellar.save(blob("one"));
|
|
67
|
+
await cellar.save(blob("two"));
|
|
68
|
+
await cellar.save(blob("three"));
|
|
68
69
|
let count = 0;
|
|
69
70
|
for await (const _ of cellar.list())
|
|
70
71
|
count++;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cellar.test.js","sourceRoot":"","sources":["../../s/cellar/cellar.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;AAC7B,OAAO,EAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAC,MAAM,eAAe,CAAA;AAEnD,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAA;AAClC,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAA;AAEnD,eAAe,OAAO,CAAC,KAAK,CAAC;IAC5B,uBAAuB,EAAE,IAAI,CAAC,KAAK,IAAG,EAAE;QACvC,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;QAC3B,MAAM,IAAI,GAAG,aAAa,CAAA;QAC1B,MAAM,
|
|
1
|
+
{"version":3,"file":"cellar.test.js","sourceRoot":"","sources":["../../s/cellar/cellar.test.ts"],"names":[],"mappings":"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"}
|
package/x/cellar/forklift.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type Forklift = {
|
|
2
2
|
list(): AsyncIterable<string>;
|
|
3
3
|
has(label: string): Promise<boolean>;
|
|
4
|
-
save(label: string,
|
|
5
|
-
load(label: string): Promise<
|
|
4
|
+
save(label: string, file: Blob): Promise<void>;
|
|
5
|
+
load(label: string): Promise<Blob>;
|
|
6
6
|
delete(label: string): Promise<void>;
|
|
7
7
|
};
|
|
@@ -3,7 +3,7 @@ export declare class MemoryForklift implements Forklift {
|
|
|
3
3
|
#private;
|
|
4
4
|
list(): AsyncIterable<string>;
|
|
5
5
|
has(label: string): Promise<boolean>;
|
|
6
|
-
save(label: string,
|
|
7
|
-
load(label: string): Promise<
|
|
6
|
+
save(label: string, file: Blob): Promise<void>;
|
|
7
|
+
load(label: string): Promise<Blob>;
|
|
8
8
|
delete(label: string): Promise<void>;
|
|
9
9
|
}
|
|
@@ -8,11 +8,12 @@ export class MemoryForklift {
|
|
|
8
8
|
async has(label) {
|
|
9
9
|
return this.#map.has(label);
|
|
10
10
|
}
|
|
11
|
-
async save(label,
|
|
11
|
+
async save(label, file) {
|
|
12
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
12
13
|
this.#map.set(label, bytes);
|
|
13
14
|
}
|
|
14
15
|
async load(label) {
|
|
15
|
-
return this.#map.require(label);
|
|
16
|
+
return new Blob([this.#map.require(label)]);
|
|
16
17
|
}
|
|
17
18
|
async delete(label) {
|
|
18
19
|
this.#map.delete(label);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-forklift.js","sourceRoot":"","sources":["../../s/cellar/memory-forklift.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAG9B,MAAM,OAAO,cAAc;IAC1B,IAAI,GAAG,IAAI,IAAI,EAAsB,CAAA;IAErC,KAAK,CAAC,CAAC,IAAI;QACV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACnC,MAAM,KAAK,CAAA;IACb,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"memory-forklift.js","sourceRoot":"","sources":["../../s/cellar/memory-forklift.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAG9B,MAAM,OAAO,cAAc;IAC1B,IAAI,GAAG,IAAI,IAAI,EAAsB,CAAA;IAErC,KAAK,CAAC,CAAC,IAAI;QACV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACnC,MAAM,KAAK,CAAA;IACb,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,IAAU;QACnC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACtD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa;QACvB,OAAO,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;CACD"}
|
|
@@ -5,7 +5,7 @@ export declare class OpfsForklift implements Forklift {
|
|
|
5
5
|
constructor(directory: FileSystemDirectoryHandle);
|
|
6
6
|
list(): AsyncIterable<string>;
|
|
7
7
|
has(label: string): Promise<boolean>;
|
|
8
|
-
save(label: string,
|
|
9
|
-
load(label: string): Promise<
|
|
8
|
+
save(label: string, file: Blob): Promise<void>;
|
|
9
|
+
load(label: string): Promise<Blob>;
|
|
10
10
|
delete(label: string): Promise<void>;
|
|
11
11
|
}
|
|
@@ -25,17 +25,15 @@ export class OpfsForklift {
|
|
|
25
25
|
throw err;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
async save(label,
|
|
28
|
+
async save(label, file) {
|
|
29
29
|
const fileHandle = await this.directory.getFileHandle(label, { create: true });
|
|
30
30
|
const writable = await fileHandle.createWritable();
|
|
31
|
-
await writable.write(
|
|
31
|
+
await writable.write(file);
|
|
32
32
|
await writable.close();
|
|
33
33
|
}
|
|
34
34
|
async load(label) {
|
|
35
35
|
const fileHandle = await this.directory.getFileHandle(label);
|
|
36
|
-
|
|
37
|
-
const buffer = await file.arrayBuffer();
|
|
38
|
-
return new Uint8Array(buffer);
|
|
36
|
+
return await fileHandle.getFile();
|
|
39
37
|
}
|
|
40
38
|
async delete(label) {
|
|
41
39
|
await this.directory.removeEntry(label);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opfs-forklift.js","sourceRoot":"","sources":["../../s/cellar/opfs-forklift.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,YAAY;IAOJ;IANpB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAe;QACjC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAA;QACnD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAC,MAAM,EAAE,IAAI,EAAC,CAAC,CAAA;QACxE,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,CAAA;IAC3B,CAAC;IAED,YAAoB,SAAoC;QAApC,cAAS,GAAT,SAAS,CAA2B;IAAG,CAAC;IAE5D,KAAK,CAAC,CAAC,IAAI;QACV,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7D,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;gBACzB,MAAM,IAAI,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,GAAG,EAAE,CAAC;YACZ,IAAK,GAAoB,CAAC,IAAI,KAAK,eAAe;gBAAE,OAAO,KAAK,CAAA;YAChE,MAAM,GAAG,CAAA;QACV,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"opfs-forklift.js","sourceRoot":"","sources":["../../s/cellar/opfs-forklift.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,YAAY;IAOJ;IANpB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAe;QACjC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAA;QACnD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAC,MAAM,EAAE,IAAI,EAAC,CAAC,CAAA;QACxE,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,CAAA;IAC3B,CAAC;IAED,YAAoB,SAAoC;QAApC,cAAS,GAAT,SAAS,CAA2B;IAAG,CAAC;IAE5D,KAAK,CAAC,CAAC,IAAI;QACV,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7D,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;gBACzB,MAAM,IAAI,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,OAAO,GAAG,EAAE,CAAC;YACZ,IAAK,GAAoB,CAAC,IAAI,KAAK,eAAe;gBAAE,OAAO,KAAK,CAAA;YAChE,MAAM,GAAG,CAAA;QACV,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,IAAU;QACnC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,EAAC,MAAM,EAAE,IAAI,EAAC,CAAC,CAAA;QAC5E,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,CAAA;QAClD,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa;QACvB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;QAC5D,OAAO,MAAM,UAAU,CAAC,OAAO,EAAE,CAAA;IAClC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC;CACD"}
|