@e280/quay 0.0.0-2 → 0.0.0-20

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.
Files changed (168) hide show
  1. package/README.md +98 -0
  2. package/package.json +17 -11
  3. package/s/cellar/cask.ts +1 -13
  4. package/s/cellar/cellar.test.ts +25 -42
  5. package/s/cellar/cellar.ts +16 -20
  6. package/s/cellar/index.ts +0 -4
  7. package/s/cellar/mammoth.ts +50 -0
  8. package/s/cellar/mammoth.worker.bundle.ts +30 -0
  9. package/s/demo/main.bundle.ts +2 -3
  10. package/s/dom/components/breadcrumb/component.ts +6 -5
  11. package/s/dom/components/browser/component.ts +11 -7
  12. package/s/dom/components/browser/style.css.ts +31 -31
  13. package/s/dom/components/dropzone/component.ts +6 -4
  14. package/s/dom/components/dropzone/style.css.ts +12 -13
  15. package/s/dom/components/filter/component.ts +13 -8
  16. package/s/dom/components/outliner/component.ts +8 -5
  17. package/s/dom/components/searchbar/component.ts +13 -7
  18. package/s/dom/components/sort/component.ts +13 -9
  19. package/s/dom/theme.css.ts +66 -2
  20. package/s/dom/views/tree/component.ts +10 -8
  21. package/s/dom/views/tree/style.css.ts +10 -10
  22. package/s/genius/parts/hy-tree.ts +10 -9
  23. package/s/index.html.ts +68 -73
  24. package/s/index.ts +6 -1
  25. package/s/logic/aspects/codex/codex.ts +3 -3
  26. package/s/logic/aspects/codex/example.ts +1 -4
  27. package/s/logic/aspects/codex/parts/codex-item.ts +4 -4
  28. package/s/logic/aspects/codex/parts/hierarchy.ts +1 -0
  29. package/s/logic/aspects/codex/parts/types.ts +1 -1
  30. package/s/logic/aspects/dropzone.ts +20 -16
  31. package/s/logic/aspects/tree-trail.ts +5 -4
  32. package/s/logic/brain.ts +5 -3
  33. package/s/logic/group.ts +13 -10
  34. package/s/logic/presets/media/group.ts +5 -4
  35. package/s/logic/presets/media/library.test.ts +82 -0
  36. package/s/logic/presets/media/library.ts +249 -0
  37. package/s/logic/presets/media/schema.ts +10 -1
  38. package/s/logic/presets/opfs/schema.ts +1 -1
  39. package/s/logic/presets/plain/group.ts +2 -2
  40. package/s/logic/presets/plain/schema.ts +1 -1
  41. package/s/logic/types.ts +1 -1
  42. package/s/tests.test.ts +2 -0
  43. package/x/cellar/cask.d.ts +2 -4
  44. package/x/cellar/cask.js +3 -12
  45. package/x/cellar/cask.js.map +1 -1
  46. package/x/cellar/cellar.d.ts +9 -7
  47. package/x/cellar/cellar.js +17 -22
  48. package/x/cellar/cellar.js.map +1 -1
  49. package/x/cellar/cellar.test.d.ts +2 -3
  50. package/x/cellar/cellar.test.js +24 -39
  51. package/x/cellar/cellar.test.js.map +1 -1
  52. package/x/cellar/index.d.ts +0 -3
  53. package/x/cellar/index.js +0 -3
  54. package/x/cellar/index.js.map +1 -1
  55. package/x/cellar/mammoth.d.ts +23 -0
  56. package/x/cellar/mammoth.js +34 -0
  57. package/x/cellar/mammoth.js.map +1 -0
  58. package/x/cellar/mammoth.worker.bundle.d.ts +1 -0
  59. package/x/cellar/mammoth.worker.bundle.js +20 -0
  60. package/x/cellar/mammoth.worker.bundle.js.map +1 -0
  61. package/x/cellar/mammoth.worker.bundle.min.js +8 -0
  62. package/x/cellar/mammoth.worker.bundle.min.js.map +7 -0
  63. package/x/demo/main.bundle.js +2 -2
  64. package/x/demo/main.bundle.js.map +1 -1
  65. package/x/demo/main.bundle.min.js +229 -197
  66. package/x/demo/main.bundle.min.js.LEGAL.txt +33 -0
  67. package/x/demo/main.bundle.min.js.map +7 -0
  68. package/x/dom/components/breadcrumb/component.d.ts +1 -1
  69. package/x/dom/components/breadcrumb/component.js +6 -5
  70. package/x/dom/components/breadcrumb/component.js.map +1 -1
  71. package/x/dom/components/browser/component.d.ts +1 -1
  72. package/x/dom/components/browser/component.js +10 -7
  73. package/x/dom/components/browser/component.js.map +1 -1
  74. package/x/dom/components/browser/style.css.d.ts +1 -1
  75. package/x/dom/components/browser/style.css.js +31 -30
  76. package/x/dom/components/browser/style.css.js.map +1 -1
  77. package/x/dom/components/dropzone/component.d.ts +1 -1
  78. package/x/dom/components/dropzone/component.js +6 -4
  79. package/x/dom/components/dropzone/component.js.map +1 -1
  80. package/x/dom/components/dropzone/style.css.d.ts +1 -1
  81. package/x/dom/components/dropzone/style.css.js +12 -12
  82. package/x/dom/components/dropzone/style.css.js.map +1 -1
  83. package/x/dom/components/filter/component.d.ts +1 -1
  84. package/x/dom/components/filter/component.js +10 -8
  85. package/x/dom/components/filter/component.js.map +1 -1
  86. package/x/dom/components/outliner/component.d.ts +1 -1
  87. package/x/dom/components/outliner/component.js +7 -5
  88. package/x/dom/components/outliner/component.js.map +1 -1
  89. package/x/dom/components/searchbar/component.d.ts +1 -1
  90. package/x/dom/components/searchbar/component.js +12 -6
  91. package/x/dom/components/searchbar/component.js.map +1 -1
  92. package/x/dom/components/sort/component.d.ts +1 -1
  93. package/x/dom/components/sort/component.js +11 -9
  94. package/x/dom/components/sort/component.js.map +1 -1
  95. package/x/dom/components.d.ts +7 -7
  96. package/x/dom/theme.css.d.ts +1 -1
  97. package/x/dom/theme.css.js +65 -1
  98. package/x/dom/theme.css.js.map +1 -1
  99. package/x/dom/views/tree/component.d.ts +1 -6
  100. package/x/dom/views/tree/component.js +10 -8
  101. package/x/dom/views/tree/component.js.map +1 -1
  102. package/x/dom/views/tree/style.css.d.ts +1 -1
  103. package/x/dom/views/tree/style.css.js +10 -10
  104. package/x/dom/views/tree/style.css.js.map +1 -1
  105. package/x/genius/parts/hy-tree.js +9 -8
  106. package/x/genius/parts/hy-tree.js.map +1 -1
  107. package/x/index.d.ts +6 -1
  108. package/x/index.html +70 -167
  109. package/x/index.html.d.ts +1 -2
  110. package/x/index.html.js +67 -73
  111. package/x/index.html.js.map +1 -1
  112. package/x/index.js +6 -1
  113. package/x/index.js.map +1 -1
  114. package/x/logic/aspects/codex/codex.js +3 -3
  115. package/x/logic/aspects/codex/codex.js.map +1 -1
  116. package/x/logic/aspects/codex/example.d.ts +0 -1
  117. package/x/logic/aspects/codex/example.js +1 -3
  118. package/x/logic/aspects/codex/example.js.map +1 -1
  119. package/x/logic/aspects/codex/parts/codex-item.d.ts +1 -1
  120. package/x/logic/aspects/codex/parts/codex-item.js +4 -4
  121. package/x/logic/aspects/codex/parts/codex-item.js.map +1 -1
  122. package/x/logic/aspects/codex/parts/hierarchy.js +1 -0
  123. package/x/logic/aspects/codex/parts/hierarchy.js.map +1 -1
  124. package/x/logic/aspects/codex/parts/types.d.ts +1 -1
  125. package/x/logic/aspects/dropzone.d.ts +1 -1
  126. package/x/logic/aspects/dropzone.js +19 -15
  127. package/x/logic/aspects/dropzone.js.map +1 -1
  128. package/x/logic/aspects/tree-trail.d.ts +1 -1
  129. package/x/logic/aspects/tree-trail.js +4 -4
  130. package/x/logic/aspects/tree-trail.js.map +1 -1
  131. package/x/logic/brain.d.ts +4 -2
  132. package/x/logic/brain.js.map +1 -1
  133. package/x/logic/group.d.ts +7 -7
  134. package/x/logic/group.js +10 -8
  135. package/x/logic/group.js.map +1 -1
  136. package/x/logic/presets/media/group.d.ts +1 -1
  137. package/x/logic/presets/media/group.js +3 -3
  138. package/x/logic/presets/media/group.js.map +1 -1
  139. package/x/logic/presets/media/library.d.ts +59 -0
  140. package/x/logic/presets/media/library.js +201 -0
  141. package/x/logic/presets/media/library.js.map +1 -0
  142. package/x/logic/presets/media/library.test.d.ts +9 -0
  143. package/x/logic/presets/media/library.test.js +62 -0
  144. package/x/logic/presets/media/library.test.js.map +1 -0
  145. package/x/logic/presets/media/schema.d.ts +10 -1
  146. package/x/logic/presets/opfs/schema.d.ts +1 -1
  147. package/x/logic/presets/plain/group.js +2 -2
  148. package/x/logic/presets/plain/group.js.map +1 -1
  149. package/x/logic/presets/plain/schema.d.ts +1 -1
  150. package/x/logic/types.d.ts +1 -1
  151. package/x/tests.test.js +2 -0
  152. package/x/tests.test.js.map +1 -1
  153. package/s/cellar/forklift.ts +0 -9
  154. package/s/cellar/memory-forklift.ts +0 -29
  155. package/s/cellar/opfs-forklift.ts +0 -49
  156. package/x/cellar/forklift.d.ts +0 -7
  157. package/x/cellar/forklift.js +0 -2
  158. package/x/cellar/forklift.js.map +0 -1
  159. package/x/cellar/memory-forklift.d.ts +0 -9
  160. package/x/cellar/memory-forklift.js +0 -21
  161. package/x/cellar/memory-forklift.js.map +0 -1
  162. package/x/cellar/opfs-forklift.d.ts +0 -11
  163. package/x/cellar/opfs-forklift.js +0 -44
  164. package/x/cellar/opfs-forklift.js.map +0 -1
  165. package/x/genius/folio.md +0 -29
  166. package/x/genius/quay.md +0 -13
  167. package/x/genius/turbo.md +0 -21
  168. package/x/importmap.json +0 -47
@@ -0,0 +1,201 @@
1
+ import { collect, sub } from "@e280/stz";
2
+ import { Kv, StorageMagazine } from "@e280/kv";
3
+ import { MediaGroup } from "./group.js";
4
+ import { Cellar } from "../../../cellar/cellar.js";
5
+ export class MediaLibrary extends MediaGroup {
6
+ static async open(scope = "default") {
7
+ const group = new this();
8
+ group.cellar = await Cellar.opfs("media");
9
+ group.#index = mediaIndex(scope);
10
+ group.#lineage = [group.#index];
11
+ await group.#load();
12
+ return group;
13
+ }
14
+ #index;
15
+ #lineage;
16
+ #root = this;
17
+ #objectUrls = new Map();
18
+ progress = sub();
19
+ cellar = new Cellar();
20
+ constructor() {
21
+ super();
22
+ this.#index = mediaIndex("default");
23
+ this.#lineage = [this.#index];
24
+ this.on.upload.sub(({ files, target }) => {
25
+ return this.#upload(files, target);
26
+ });
27
+ this.on.delete.sub(({ items }) => {
28
+ const hashes = this.#hashes(items);
29
+ return this.#delete(hashes);
30
+ });
31
+ }
32
+ get #isRoot() {
33
+ return this === this.#root;
34
+ }
35
+ async scope(name) {
36
+ const child = new MediaLibrary();
37
+ child.cellar = this.cellar;
38
+ child.#index = this.#index.scope(name);
39
+ child.#lineage = [...this.#lineage, child.#index];
40
+ child.#root = this.#root;
41
+ await child.#load();
42
+ return child;
43
+ }
44
+ async *records() {
45
+ for await (const [, record] of this.#index.entries())
46
+ yield record;
47
+ }
48
+ async include(hash) {
49
+ const record = await this.#root.#index.need(hash);
50
+ await this.#index.commit(this.#lineage.map(index => index.op.set(hash, record)));
51
+ if (record.format === "image" && !this.#objectUrls.has(hash))
52
+ await this.#loadPreview(record);
53
+ this.#attachRecord(record);
54
+ this.on.refresh.pub({});
55
+ }
56
+ async #load() {
57
+ for await (const record of this.records()) {
58
+ if (record.format === "image" && !this.#objectUrls.has(record.hash))
59
+ await this.#loadPreview(record);
60
+ this.#attachRecord(record, this.config.root);
61
+ }
62
+ }
63
+ async #upload(files, parent) {
64
+ await Promise.all(files.map(file => this.#storeFile(file, parent)));
65
+ }
66
+ async #storeFile(file, parent) {
67
+ const item = this.#attachPending(file, parent);
68
+ try {
69
+ const hash = await this.cellar.write(trackProgress(file.stream(), loaded => this.progress.pub({ item, loaded, total: file.size })));
70
+ const record = await this.#saveRecord(file, hash);
71
+ item.destroy();
72
+ this.#attachRecord(record, parent);
73
+ return record;
74
+ }
75
+ catch (error) {
76
+ item.destroy();
77
+ this.on.refresh.pub({});
78
+ throw error;
79
+ }
80
+ }
81
+ #attachPending(file, parent) {
82
+ const item = this.config.codex.create("file", {
83
+ label: file.name,
84
+ format: mediaFormat(file.type),
85
+ mime: file.type,
86
+ size: file.size,
87
+ previewUrl: null,
88
+ });
89
+ parent.attach(item);
90
+ this.on.refresh.pub({});
91
+ return item;
92
+ }
93
+ async #saveRecord(file, hash) {
94
+ const existing = await this.#index.get(hash) ?? await this.#root.#index.get(hash);
95
+ const now = Date.now();
96
+ const record = {
97
+ hash,
98
+ label: existing?.label ?? file.name,
99
+ format: mediaFormat(file.type),
100
+ mime: file.type,
101
+ size: file.size,
102
+ createdAt: existing?.createdAt ?? now,
103
+ updatedAt: now,
104
+ };
105
+ await this.#index.commit(this.#lineage.map(index => index.op.set(hash, record)));
106
+ if (record.format === "image")
107
+ this.#setPreview(hash, URL.createObjectURL(file));
108
+ return record;
109
+ }
110
+ #hashes(items) {
111
+ return items
112
+ .map(item => item.isKind("file") ? item.specimen.hash : undefined)
113
+ .filter((hash) => !!hash);
114
+ }
115
+ async #delete(hashes) {
116
+ const index = this.#index.crush();
117
+ const keys = (await collect(index.entries()))
118
+ .filter(([, record]) => hashes.includes(record.hash))
119
+ .map(([key]) => key);
120
+ await index.commit(keys.map(key => index.op.delete(key)));
121
+ for (const hash of hashes) {
122
+ this.#revokePreview(hash);
123
+ if (this.#isRoot)
124
+ await this.cellar.delete(hash);
125
+ }
126
+ }
127
+ findByHash(hash) {
128
+ for (const [item] of this.config.root.crawl()) {
129
+ if (item.isKind("file") && item.specimen.hash === hash)
130
+ return item;
131
+ }
132
+ }
133
+ dispose() {
134
+ for (const url of this.#objectUrls.values())
135
+ URL.revokeObjectURL(url);
136
+ this.#objectUrls.clear();
137
+ }
138
+ #attachRecord(record, parent = this.config.root) {
139
+ const existing = this.findByHash(record.hash);
140
+ if (existing)
141
+ return existing;
142
+ const item = this.config.codex.create("file", {
143
+ hash: record.hash,
144
+ label: record.label,
145
+ format: record.format,
146
+ mime: record.mime,
147
+ size: record.size,
148
+ previewUrl: this.#objectUrls.get(record.hash) ?? null,
149
+ });
150
+ parent.attach(item);
151
+ return item;
152
+ }
153
+ async #loadPreview(record) {
154
+ const cask = await this.cellar.load(record.hash);
155
+ const blob = new Blob([cask.file], { type: record.mime || "image/*" });
156
+ return this.#setPreview(record.hash, URL.createObjectURL(blob));
157
+ }
158
+ #setPreview(hash, url) {
159
+ this.#revokePreview(hash);
160
+ this.#objectUrls.set(hash, url);
161
+ return url;
162
+ }
163
+ #revokePreview(hash) {
164
+ const url = this.#objectUrls.get(hash);
165
+ if (url) {
166
+ URL.revokeObjectURL(url);
167
+ this.#objectUrls.delete(hash);
168
+ }
169
+ }
170
+ }
171
+ const mediaFormats = new Set(["video", "image", "audio"]);
172
+ const memoryIndexes = new Map();
173
+ function mediaFormat(mime) {
174
+ const [type] = mime.split("/");
175
+ return mediaFormats.has(type) ? type : "other";
176
+ }
177
+ function mediaIndex(scope) {
178
+ const storage = globalThis.localStorage;
179
+ if (storage)
180
+ return new Kv(new StorageMagazine(storage))
181
+ .scope("quay")
182
+ .scope("media")
183
+ .scope(scope);
184
+ const existing = memoryIndexes.get(scope);
185
+ if (existing)
186
+ return existing;
187
+ const index = new Kv();
188
+ memoryIndexes.set(scope, index);
189
+ return index;
190
+ }
191
+ function trackProgress(readable, onProgress) {
192
+ let loaded = 0;
193
+ return readable.pipeThrough(new TransformStream({
194
+ transform(chunk, controller) {
195
+ loaded += chunk.byteLength;
196
+ onProgress(loaded);
197
+ controller.enqueue(chunk);
198
+ },
199
+ }));
200
+ }
201
+ //# sourceMappingURL=library.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"library.js","sourceRoot":"","sources":["../../../../s/logic/presets/media/library.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Science } from "@e280/science";
2
+ declare const _default: {
3
+ "uploads files into cellar and index": Science.Test;
4
+ "upload respects upload permission": Science.Test;
5
+ "lists media records": Science.Test;
6
+ "includes existing media in a scope": Science.Test;
7
+ "root deletion removes media records and resources": Science.Test;
8
+ };
9
+ export default _default;
@@ -0,0 +1,62 @@
1
+ import { Txt } from "@e280/stz";
2
+ import { expect, Science, test } from "@e280/science";
3
+ import { MediaLibrary } from "./library.js";
4
+ import { Permissions } from "../../permissions.js";
5
+ delete globalThis.localStorage;
6
+ export default Science.suite({
7
+ "uploads files into cellar and index": test(async () => {
8
+ const group = new MediaLibrary();
9
+ await group.upload([file("hello.txt", "hello")], group.config.root);
10
+ const record = await recordByLabel(group, "hello.txt");
11
+ const item = group.findByHash(record.hash);
12
+ expect(item.specimen.label).is("hello.txt");
13
+ expect(await group.cellar.has(record.hash)).is(true);
14
+ }),
15
+ "upload respects upload permission": test(async () => {
16
+ const group = new MediaLibrary();
17
+ const file = new File([Txt.toBytes("hello")], "hello.txt", { type: "text/plain" });
18
+ group.config.permissions = () => Permissions.readOnly;
19
+ expect(() => group.upload([file], group.config.root)).throws();
20
+ }),
21
+ "lists media records": test(async () => {
22
+ const store = new MediaLibrary();
23
+ await store.upload([file("image.png", "image", "image/png")], store.config.root);
24
+ expect(await recordByLabel(store, "image.png")).ok();
25
+ }),
26
+ "includes existing media in a scope": test(async () => {
27
+ const library = new MediaLibrary();
28
+ await library.upload([file("include.txt", "include")], library.config.root);
29
+ const record = await recordByLabel(library, "include.txt");
30
+ const project = await library.scope("include-project");
31
+ await project.include(record.hash);
32
+ expect(project.findByHash(record.hash)).ok();
33
+ expect(await recordByLabel(project, "include.txt")).ok();
34
+ expect(await project.cellar.has(record.hash)).is(true);
35
+ await expect(() => project.include("missing")).throwsAsync();
36
+ }),
37
+ "root deletion removes media records and resources": test(async () => {
38
+ const store = new MediaLibrary();
39
+ await store.upload([file("delete.png", "delete-image", "image/png")], store.config.root);
40
+ const record = await recordByLabel(store, "delete.png");
41
+ const item = store.findByHash(record.hash);
42
+ await store.delete(item);
43
+ expect(store.findByHash(record.hash)).is(undefined);
44
+ expect(await store.cellar.has(record.hash)).is(false);
45
+ }),
46
+ });
47
+ function file(name, text, type = "text/plain") {
48
+ return new File([Txt.toBytes(text)], name, { type });
49
+ }
50
+ async function records(store) {
51
+ const records = [];
52
+ for await (const record of store.records())
53
+ records.push(record);
54
+ return records;
55
+ }
56
+ async function recordByLabel(store, label) {
57
+ const record = (await records(store)).find(r => r.label === label);
58
+ if (!record)
59
+ throw new Error(`expected record "${label}"`);
60
+ return record;
61
+ }
62
+ //# sourceMappingURL=library.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"library.test.js","sourceRoot":"","sources":["../../../../s/logic/presets/media/library.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { Content } from "@benev/slate";
1
+ import { Content } from "@e280/sly";
2
2
  import { AsSchema } from "../../aspects/codex/parts/types.js";
3
+ import { CodexItem } from "../../aspects/codex/parts/codex-item.js";
3
4
  export type MediaFormat = "video" | "image" | "audio" | "other";
4
5
  export type MediaSchema = AsSchema<{
5
6
  taxon: {
@@ -13,6 +14,14 @@ export type MediaSchema = AsSchema<{
13
14
  label: string;
14
15
  format: MediaFormat;
15
16
  previewUrl: string | null;
17
+ hash?: string;
18
+ mime?: string;
19
+ size?: number;
16
20
  };
17
21
  };
18
22
  }>;
23
+ export type MediaProgress = {
24
+ item: CodexItem<MediaSchema>;
25
+ loaded: number;
26
+ total: number;
27
+ };
@@ -1,4 +1,4 @@
1
- import { Content } from "@benev/slate";
1
+ import { Content } from "@e280/sly";
2
2
  import { AsSchema } from "../../aspects/codex/parts/types.js";
3
3
  export type OpfsSchema = AsSchema<{
4
4
  taxon: {
@@ -1,5 +1,5 @@
1
- import Quay from "../../../index.js";
2
1
  import { Group } from "../../group.js";
2
+ import { Permissions } from "../../permissions.js";
3
3
  import { Codex } from "../../aspects/codex/codex.js";
4
4
  export class PlainGroup extends Group {
5
5
  static config = () => {
@@ -23,7 +23,7 @@ export class PlainGroup extends Group {
23
23
  renderLabel: item => item.id,
24
24
  renderIcon: item => item.taxon.icon,
25
25
  renderPreview: () => null,
26
- permissions: item => Quay.permissions.all,
26
+ permissions: item => Permissions.all,
27
27
  };
28
28
  };
29
29
  constructor() {
@@ -1 +1 @@
1
- {"version":3,"file":"group.js","sourceRoot":"","sources":["../../../../s/logic/presets/plain/group.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,mBAAmB,CAAA;AACpC,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAA;AAGpC,OAAO,EAAC,KAAK,EAAC,MAAM,8BAA8B,CAAA;AAElD,MAAM,OAAO,UAAW,SAAQ,KAAkB;IACjD,MAAM,CAAC,MAAM,GAAG,GAA6B,EAAE;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAc;YACtC,IAAI,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC;SAClB,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACtB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC,CACrC,CAAA;QAED,OAAO;YACN,KAAK;YACL,IAAI;YACJ,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,IAAI,GAAG,EAA+B;iBAC3C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClD,aAAa,EAAE,KAAK;YACpB,OAAO,EAAE,IAAI,GAAG,EAAE;iBAChB,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;gBACvB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CACtB,CAAC,CAAA;YACH,CAAC;YACD,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;YAC5B,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;YACnC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI;YACzB,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;SACzC,CAAA;IACF,CAAC,CAAA;IAED;QACC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;IAC3B,CAAC"}
1
+ {"version":3,"file":"group.js","sourceRoot":"","sources":["../../../../s/logic/presets/plain/group.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAA;AAEpC,OAAO,EAAC,WAAW,EAAC,MAAM,sBAAsB,CAAA;AAEhD,OAAO,EAAC,KAAK,EAAC,MAAM,8BAA8B,CAAA;AAElD,MAAM,OAAO,UAAW,SAAQ,KAAkB;IACjD,MAAM,CAAC,MAAM,GAAG,GAA6B,EAAE;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAc;YACtC,IAAI,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC;SAClB,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACtB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC,CACrC,CAAA;QAED,OAAO;YACN,KAAK;YACL,IAAI;YACJ,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,IAAI,GAAG,EAA+B;iBAC3C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClD,aAAa,EAAE,KAAK;YACpB,OAAO,EAAE,IAAI,GAAG,EAAE;iBAChB,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;gBACvB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CACtB,CAAC,CAAA;YACH,CAAC;YACD,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;YAC5B,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;YACnC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI;YACzB,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG;SACpC,CAAA;IACF,CAAC,CAAA;IAED;QACC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;IAC3B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Content } from "@benev/slate";
1
+ import { Content } from "@e280/sly";
2
2
  import { AsSchema } from "../../aspects/codex/parts/types.js";
3
3
  export type PlainSchema = AsSchema<{
4
4
  taxon: {
@@ -1,8 +1,8 @@
1
+ import { Content } from "@e280/sly";
1
2
  import { Permission } from "./permissions.js";
2
3
  import { Codex } from "./aspects/codex/codex.js";
3
4
  import { Schema } from "./aspects/codex/parts/types.js";
4
5
  import { CodexItem } from "./aspects/codex/parts/codex-item.js";
5
- import { Content } from "@benev/slate";
6
6
  export type SearchFn<Sc extends Schema> = (item: CodexItem<Sc>) => boolean;
7
7
  export type SortFn<Sc extends Schema> = (a: CodexItem<Sc>, b: CodexItem<Sc>) => number;
8
8
  export interface GroupConfig<Sc extends Schema> {
package/x/tests.test.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Science } from "@e280/science";
2
2
  import cellar from "./cellar/cellar.test.js";
3
+ import media from "./logic/presets/media/library.test.js";
3
4
  await Science.run({
4
5
  cellar,
6
+ media
5
7
  });
6
8
  //# sourceMappingURL=tests.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tests.test.js","sourceRoot":"","sources":["../s/tests.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAA;AACrC,OAAO,MAAM,MAAM,yBAAyB,CAAA;AAE5C,MAAM,OAAO,CAAC,GAAG,CAAC;IACjB,MAAM;CACN,CAAC,CAAA"}
1
+ {"version":3,"file":"tests.test.js","sourceRoot":"","sources":["../s/tests.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAA;AACrC,OAAO,MAAM,MAAM,yBAAyB,CAAA;AAC5C,OAAO,KAAK,MAAM,uCAAuC,CAAA;AAEzD,MAAM,OAAO,CAAC,GAAG,CAAC;IACjB,MAAM;IACN,KAAK;CACL,CAAC,CAAA"}
@@ -1,9 +0,0 @@
1
-
2
- export type Forklift = {
3
- list(): AsyncIterable<string>
4
- has(label: string): Promise<boolean>
5
- save(label: string, bytes: Uint8Array): Promise<void>
6
- load(label: string): Promise<Uint8Array>
7
- delete(label: string): Promise<void>
8
- }
9
-
@@ -1,29 +0,0 @@
1
-
2
- import {MapG} from "@e280/stz"
3
- import {Forklift} from "./forklift.js"
4
-
5
- export class MemoryForklift implements Forklift {
6
- #map = new MapG<string, Uint8Array>()
7
-
8
- async *list(): AsyncIterable<string> {
9
- for (const label of this.#map.keys())
10
- yield label
11
- }
12
-
13
- async has(label: string): Promise<boolean> {
14
- return this.#map.has(label)
15
- }
16
-
17
- async save(label: string, bytes: Uint8Array): Promise<void> {
18
- this.#map.set(label, bytes)
19
- }
20
-
21
- async load(label: string): Promise<Uint8Array> {
22
- return this.#map.require(label)
23
- }
24
-
25
- async delete(label: string) {
26
- this.#map.delete(label)
27
- }
28
- }
29
-
@@ -1,49 +0,0 @@
1
-
2
- import {Forklift} from "./forklift.js"
3
-
4
- export class OpfsForklift implements Forklift {
5
- static async setup(dirname: string) {
6
- const root = await navigator.storage.getDirectory()
7
- const directory = await root.getDirectoryHandle(dirname, {create: true})
8
- return new this(directory)
9
- }
10
-
11
- constructor(private directory: FileSystemDirectoryHandle) {}
12
-
13
- async *list(): AsyncIterable<string> {
14
- for await (const [name, handle] of this.directory.entries()) {
15
- if (handle.kind === "file")
16
- yield name
17
- }
18
- }
19
-
20
- async has(label: string): Promise<boolean> {
21
- try {
22
- await this.directory.getFileHandle(label)
23
- return true
24
- }
25
- catch (err) {
26
- if ((err as DOMException).name === "NotFoundError") return false
27
- throw err
28
- }
29
- }
30
-
31
- async save(label: string, bytes: Uint8Array): Promise<void> {
32
- const fileHandle = await this.directory.getFileHandle(label, {create: true})
33
- const writable = await fileHandle.createWritable()
34
- await writable.write(bytes)
35
- await writable.close()
36
- }
37
-
38
- async load(label: string): Promise<Uint8Array> {
39
- const fileHandle = await this.directory.getFileHandle(label)
40
- const file = await fileHandle.getFile()
41
- const buffer = await file.arrayBuffer()
42
- return new Uint8Array(buffer)
43
- }
44
-
45
- async delete(label: string) {
46
- await this.directory.removeEntry(label)
47
- }
48
- }
49
-
@@ -1,7 +0,0 @@
1
- export type Forklift = {
2
- list(): AsyncIterable<string>;
3
- has(label: string): Promise<boolean>;
4
- save(label: string, bytes: Uint8Array): Promise<void>;
5
- load(label: string): Promise<Uint8Array>;
6
- delete(label: string): Promise<void>;
7
- };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=forklift.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"forklift.js","sourceRoot":"","sources":["../../s/cellar/forklift.ts"],"names":[],"mappings":""}
@@ -1,9 +0,0 @@
1
- import { Forklift } from "./forklift.js";
2
- export declare class MemoryForklift implements Forklift {
3
- #private;
4
- list(): AsyncIterable<string>;
5
- has(label: string): Promise<boolean>;
6
- save(label: string, bytes: Uint8Array): Promise<void>;
7
- load(label: string): Promise<Uint8Array>;
8
- delete(label: string): Promise<void>;
9
- }
@@ -1,21 +0,0 @@
1
- import { MapG } from "@e280/stz";
2
- export class MemoryForklift {
3
- #map = new MapG();
4
- async *list() {
5
- for (const label of this.#map.keys())
6
- yield label;
7
- }
8
- async has(label) {
9
- return this.#map.has(label);
10
- }
11
- async save(label, bytes) {
12
- this.#map.set(label, bytes);
13
- }
14
- async load(label) {
15
- return this.#map.require(label);
16
- }
17
- async delete(label) {
18
- this.#map.delete(label);
19
- }
20
- }
21
- //# sourceMappingURL=memory-forklift.js.map
@@ -1 +0,0 @@
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,KAAiB;QAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAa;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;CACD"}
@@ -1,11 +0,0 @@
1
- import { Forklift } from "./forklift.js";
2
- export declare class OpfsForklift implements Forklift {
3
- private directory;
4
- static setup(dirname: string): Promise<OpfsForklift>;
5
- constructor(directory: FileSystemDirectoryHandle);
6
- list(): AsyncIterable<string>;
7
- has(label: string): Promise<boolean>;
8
- save(label: string, bytes: Uint8Array): Promise<void>;
9
- load(label: string): Promise<Uint8Array>;
10
- delete(label: string): Promise<void>;
11
- }
@@ -1,44 +0,0 @@
1
- export class OpfsForklift {
2
- directory;
3
- static async setup(dirname) {
4
- const root = await navigator.storage.getDirectory();
5
- const directory = await root.getDirectoryHandle(dirname, { create: true });
6
- return new this(directory);
7
- }
8
- constructor(directory) {
9
- this.directory = directory;
10
- }
11
- async *list() {
12
- for await (const [name, handle] of this.directory.entries()) {
13
- if (handle.kind === "file")
14
- yield name;
15
- }
16
- }
17
- async has(label) {
18
- try {
19
- await this.directory.getFileHandle(label);
20
- return true;
21
- }
22
- catch (err) {
23
- if (err.name === "NotFoundError")
24
- return false;
25
- throw err;
26
- }
27
- }
28
- async save(label, bytes) {
29
- const fileHandle = await this.directory.getFileHandle(label, { create: true });
30
- const writable = await fileHandle.createWritable();
31
- await writable.write(bytes);
32
- await writable.close();
33
- }
34
- async load(label) {
35
- const fileHandle = await this.directory.getFileHandle(label);
36
- const file = await fileHandle.getFile();
37
- const buffer = await file.arrayBuffer();
38
- return new Uint8Array(buffer);
39
- }
40
- async delete(label) {
41
- await this.directory.removeEntry(label);
42
- }
43
- }
44
- //# sourceMappingURL=opfs-forklift.js.map
@@ -1 +0,0 @@
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,KAAiB;QAC1C,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,KAAK,CAAC,CAAA;QAC3B,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,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,CAAA;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QACvC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC;CACD"}
package/x/genius/folio.md DELETED
@@ -1,29 +0,0 @@
1
-
2
- # 🗂️ Folio
3
-
4
- A virtual filesystem for the web.
5
-
6
- Folio provides primitives for building intuitive file browsing experiences on the web.
7
- - Agnostic about where data is actually stored
8
- - For local, best to use [Turbo](./turbo.md) as an OPFS turbocharger
9
-
10
- > 🤷 **Why not just use OPFS?**
11
- > OPFS doesn't have cross-browser support for efficient move or rename operations.
12
- > Folio is like a souped-up extended opfs.
13
-
14
- Folio stores two kinds of data:
15
- - **Blob storage**
16
- Stores the binary payloads for files.
17
- Usually, blob storage will target *opfs* — though localstorage, indexeddb, or cloud storage are options.
18
- sha256 hashes are the identifiers, thus binary payloads are thus de-duplicated.
19
- - **Index storage**
20
- Stores metadata and directory hierarchy.
21
- Usually, index storage will target *indexeddb* — though localstorage or cloud storage are options.
22
-
23
- <br/>
24
-
25
- ---
26
-
27
- > ### Wip: implementation plan
28
- > - Folio implements the `Twig` interface
29
-
package/x/genius/quay.md DELETED
@@ -1,13 +0,0 @@
1
-
2
- # 🪝 Quay integration
3
-
4
- ```ts
5
- import {Quay, Opfs, OpfsSchema} from "@e280/quay"
6
-
7
- const quay = new Quay()
8
- const opfs = await Opfs.setup()
9
- const group = quay.group<OpfsSchema>(opfs)
10
-
11
- register(group.elements())
12
- ```
13
-