@dirwell/theme-ledger 0.0.0-stage → 0.0.1-alpha
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/LICENSE +21 -0
- package/README.md +16 -2
- package/dist/THIRD_PARTY_NOTICES.txt +30 -0
- package/dist/client.js +82 -0
- package/dist/component.css +0 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +601 -0
- package/dist/index.mjs.map +1 -0
- package/dist/model-K7UzS9YB.d.mts +46 -0
- package/dist/model.d.mts +2 -0
- package/dist/model.mjs +1 -0
- package/dist/source/Ledger.svelte +639 -0
- package/dist/source/component.d.mts +4 -0
- package/dist/source/shared/icons.mjs +12 -0
- package/dist/source/shared/navigation.mjs +294 -0
- package/dist/source/shared/records.mjs +60 -0
- package/dist/styles.css +815 -0
- package/package.json +47 -3
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// ../core/src/json.ts
|
|
2
|
+
function copyJsonObject(value) {
|
|
3
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4
|
+
const copy = (input, depth) => {
|
|
5
|
+
if (depth > 32) throw new TypeError("Presentation data is too deeply nested");
|
|
6
|
+
if (input === null || typeof input === "string" || typeof input === "boolean") return input;
|
|
7
|
+
if (typeof input === "number" && Number.isFinite(input)) return input;
|
|
8
|
+
if (typeof input !== "object" || input === null || seen.has(input))
|
|
9
|
+
throw new TypeError("Presentation data must be finite, acyclic JSON");
|
|
10
|
+
seen.add(input);
|
|
11
|
+
try {
|
|
12
|
+
if (Array.isArray(input)) return input.map((item) => copy(item, depth + 1));
|
|
13
|
+
if (Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null)
|
|
14
|
+
throw new TypeError("Presentation data must use plain objects");
|
|
15
|
+
return Object.fromEntries(
|
|
16
|
+
Object.entries(input).map(([key, item]) => [key, copy(item, depth + 1)])
|
|
17
|
+
);
|
|
18
|
+
} finally {
|
|
19
|
+
seen.delete(input);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
23
|
+
throw new TypeError("Presentation data must be an object");
|
|
24
|
+
const result = copy(value, 0);
|
|
25
|
+
if (typeof result !== "object" || result === null || Array.isArray(result))
|
|
26
|
+
throw new TypeError("Presentation data must be an object");
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ../core/src/client.ts
|
|
31
|
+
var ListingDataError = class extends Error {
|
|
32
|
+
name = "ListingDataError";
|
|
33
|
+
};
|
|
34
|
+
var StaleListingError = class extends ListingDataError {
|
|
35
|
+
};
|
|
36
|
+
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
+
var count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
38
|
+
var kind = (value) => typeof value === "string" && ["directory", "file", "symlink", "other"].includes(value);
|
|
39
|
+
function string(value, name) {
|
|
40
|
+
if (typeof value !== "string") throw new ListingDataError(`Invalid ${name}`);
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function boolean(value, name) {
|
|
44
|
+
if (typeof value !== "boolean") throw new ListingDataError(`Invalid ${name}`);
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function href(value, base) {
|
|
48
|
+
if (value === null) return null;
|
|
49
|
+
const result = new URL(string(value, "href"), base);
|
|
50
|
+
if (!["http:", "https:"].includes(result.protocol))
|
|
51
|
+
throw new ListingDataError("Unsupported listing link protocol");
|
|
52
|
+
return result.href;
|
|
53
|
+
}
|
|
54
|
+
function entry(value, base) {
|
|
55
|
+
if (!object(value) || !kind(value.kind) || typeof value.size !== "number" || !Number.isFinite(value.size) || value.size < 0)
|
|
56
|
+
throw new ListingDataError("Invalid listing entry");
|
|
57
|
+
let link = null;
|
|
58
|
+
if (value.link !== null) {
|
|
59
|
+
if (!object(value.link)) throw new ListingDataError("Invalid link metadata");
|
|
60
|
+
const targetKind = value.link.targetKind;
|
|
61
|
+
if (targetKind !== null && (!kind(targetKind) || targetKind === "symlink"))
|
|
62
|
+
throw new ListingDataError("Invalid target kind");
|
|
63
|
+
const targetSize = value.link.targetSize;
|
|
64
|
+
if (targetSize !== null && (typeof targetSize !== "number" || !Number.isFinite(targetSize) || targetSize < 0))
|
|
65
|
+
throw new ListingDataError("Invalid target size");
|
|
66
|
+
link = {
|
|
67
|
+
target: string(value.link.target, "target"),
|
|
68
|
+
targetKind,
|
|
69
|
+
targetSize,
|
|
70
|
+
unavailable: boolean(value.link.unavailable, "unavailable"),
|
|
71
|
+
cycle: boolean(value.link.cycle, "cycle")
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...value.presentation === void 0 ? {} : { presentation: copyJsonObject(value.presentation) },
|
|
76
|
+
id: string(value.id, "id"),
|
|
77
|
+
name: string(value.name, "name"),
|
|
78
|
+
kind: value.kind,
|
|
79
|
+
href: href(value.href, base),
|
|
80
|
+
exitsExplorer: boolean(value.exitsExplorer, "exitsExplorer"),
|
|
81
|
+
size: value.size,
|
|
82
|
+
modifiedAt: string(value.modifiedAt, "modifiedAt"),
|
|
83
|
+
link
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function manifest(value) {
|
|
87
|
+
if (!object(value) || value.version !== 1 || !count(value.total) || !Array.isArray(value.blocks) || !object(value.sort))
|
|
88
|
+
throw new ListingDataError("Invalid listing manifest");
|
|
89
|
+
const sort = value.sort;
|
|
90
|
+
if (typeof sort.field !== "string" || !["name", "size", "modified"].includes(sort.field) || typeof sort.direction !== "string" || !["asc", "desc"].includes(sort.direction) || typeof sort.nameMode !== "string" || !["locale", "natural", "unicode"].includes(sort.nameMode) || typeof sort.directoriesFirst !== "boolean")
|
|
91
|
+
throw new ListingDataError("Invalid listing order");
|
|
92
|
+
const field = sort.field === "size" ? "size" : sort.field === "modified" ? "modified" : "name";
|
|
93
|
+
const direction = sort.direction === "desc" ? "desc" : "asc";
|
|
94
|
+
const nameMode = sort.nameMode === "unicode" ? "unicode" : sort.nameMode === "locale" ? "locale" : "natural";
|
|
95
|
+
const blocks = value.blocks.map((item) => {
|
|
96
|
+
if (!object(item) || !count(item.offset) || !count(item.count))
|
|
97
|
+
throw new ListingDataError("Invalid block descriptor");
|
|
98
|
+
return { href: string(item.href, "block href"), offset: item.offset, count: item.count };
|
|
99
|
+
});
|
|
100
|
+
if (blocks.length === 0) throw new ListingDataError("Missing blocks");
|
|
101
|
+
return {
|
|
102
|
+
version: 1,
|
|
103
|
+
revision: string(value.revision, "revision"),
|
|
104
|
+
directory: string(value.directory, "directory"),
|
|
105
|
+
hrefBase: string(value.hrefBase, "href base"),
|
|
106
|
+
total: value.total,
|
|
107
|
+
sort: { field, direction, nameMode, directoriesFirst: sort.directoriesFirst },
|
|
108
|
+
blocks
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function loadListing(manifestUrl, options = {}) {
|
|
112
|
+
const request = options.fetch ?? fetch;
|
|
113
|
+
const maxEntries = options.maxEntries ?? 1e5;
|
|
114
|
+
if (!count(maxEntries)) throw new ListingDataError("Invalid entry limit");
|
|
115
|
+
const source = new URL(manifestUrl);
|
|
116
|
+
if (!["http:", "https:"].includes(source.protocol))
|
|
117
|
+
throw new ListingDataError("Listing loading requires HTTP(S); use native file navigation");
|
|
118
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
119
|
+
try {
|
|
120
|
+
const init = {
|
|
121
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
122
|
+
cache: attempt === 0 ? options.cache ?? "default" : "reload"
|
|
123
|
+
};
|
|
124
|
+
const response = await request(source, init);
|
|
125
|
+
if (!response.ok) throw new ListingDataError(`Manifest request failed: ${response.status}`);
|
|
126
|
+
const current = manifest(await response.json());
|
|
127
|
+
if (current.total > maxEntries)
|
|
128
|
+
throw new ListingDataError("Listing exceeds the configured entry limit");
|
|
129
|
+
const base = new URL(current.hrefBase, source);
|
|
130
|
+
if (!["http:", "https:"].includes(base.protocol))
|
|
131
|
+
throw new ListingDataError("Unsupported href base protocol");
|
|
132
|
+
const entries = [];
|
|
133
|
+
const ids = /* @__PURE__ */ new Set();
|
|
134
|
+
for (const descriptor of current.blocks) {
|
|
135
|
+
if (descriptor.offset !== entries.length || descriptor.count + entries.length > current.total)
|
|
136
|
+
throw new ListingDataError("Invalid block coverage");
|
|
137
|
+
const blockUrl = new URL(descriptor.href, source);
|
|
138
|
+
if (blockUrl.origin !== source.origin || !["http:", "https:"].includes(blockUrl.protocol))
|
|
139
|
+
throw new ListingDataError("Block leaves the manifest origin");
|
|
140
|
+
const blockResponse = await request(blockUrl, init);
|
|
141
|
+
if (blockResponse.status === 404 || blockResponse.status === 410)
|
|
142
|
+
throw new StaleListingError("Block no longer available");
|
|
143
|
+
if (!blockResponse.ok)
|
|
144
|
+
throw new ListingDataError(`Block request failed: ${blockResponse.status}`);
|
|
145
|
+
const data = await blockResponse.json();
|
|
146
|
+
if (!object(data) || data.version !== 1 || data.revision !== current.revision)
|
|
147
|
+
throw new StaleListingError("Listing revision changed");
|
|
148
|
+
if (data.offset !== descriptor.offset || data.total !== current.total || !Array.isArray(data.entries) || data.entries.length !== descriptor.count)
|
|
149
|
+
throw new ListingDataError("Invalid block envelope");
|
|
150
|
+
for (const raw of data.entries) {
|
|
151
|
+
const record = entry(raw, base);
|
|
152
|
+
if (ids.has(record.id)) throw new ListingDataError("Duplicate entry ID");
|
|
153
|
+
ids.add(record.id);
|
|
154
|
+
entries.push(record);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (entries.length !== current.total) throw new ListingDataError("Incomplete listing");
|
|
158
|
+
return { manifest: current, entries };
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (options.signal?.aborted || !(error instanceof StaleListingError) || attempt === 1)
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
throw new ListingDataError("Listing unavailable");
|
|
165
|
+
}
|
|
166
|
+
function parseListingEntries(value, baseHref, maxEntries = 1e5) {
|
|
167
|
+
if (!Array.isArray(value) || value.length > maxEntries)
|
|
168
|
+
throw new ListingDataError("Invalid page slice");
|
|
169
|
+
const base = new URL(baseHref), ids = /* @__PURE__ */ new Set();
|
|
170
|
+
const result = value.map((raw) => entry(raw, base));
|
|
171
|
+
for (const record of result) {
|
|
172
|
+
if (ids.has(record.id)) throw new ListingDataError("Duplicate entry ID");
|
|
173
|
+
ids.add(record.id);
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ../shared-theme/src/navigation.ts
|
|
179
|
+
async function fetchThemePage(dataHref, pageHref, theme, signal, fresh = false, attempt = 0) {
|
|
180
|
+
const source = new URL(dataHref, document.baseURI);
|
|
181
|
+
if (source.origin !== location.origin)
|
|
182
|
+
throw new ListingDataError("Folder leaves the theme origin");
|
|
183
|
+
const response = await fetch(source, { signal, cache: fresh ? "no-store" : "default" });
|
|
184
|
+
if (!response.ok) throw new ListingDataError("Unavailable folder");
|
|
185
|
+
const value = await response.json();
|
|
186
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
187
|
+
throw new ListingDataError("Invalid folder snapshot");
|
|
188
|
+
const data = value;
|
|
189
|
+
if (data.version !== 1 || data.theme !== theme || typeof data.title !== "string" || typeof data.path !== "string" || !Number.isSafeInteger(data.total) || Number(data.total) < 0 || !Array.isArray(data.breadcrumbs))
|
|
190
|
+
throw new ListingDataError("Unsupported folder snapshot");
|
|
191
|
+
if (data.metadataHead !== void 0 && typeof data.metadataHead !== "string")
|
|
192
|
+
throw new ListingDataError("Invalid folder metadata");
|
|
193
|
+
const base = document.querySelector("base")?.href ?? pageHref;
|
|
194
|
+
const link = (raw) => {
|
|
195
|
+
if (raw === null) return null;
|
|
196
|
+
if (typeof raw !== "string") throw new ListingDataError("Invalid folder link");
|
|
197
|
+
const url = new URL(raw, base);
|
|
198
|
+
if (!["http:", "https:"].includes(url.protocol) || url.origin !== location.origin)
|
|
199
|
+
throw new ListingDataError("Unsupported folder link");
|
|
200
|
+
return url.href;
|
|
201
|
+
};
|
|
202
|
+
const entries = parseListingEntries(data.entries, base).map((entry2) => ({
|
|
203
|
+
...entry2,
|
|
204
|
+
...entry2.presentation ? {
|
|
205
|
+
presentation: {
|
|
206
|
+
...entry2.presentation,
|
|
207
|
+
folderDataHref: link(entry2.presentation.folderDataHref ?? null)
|
|
208
|
+
}
|
|
209
|
+
} : {}
|
|
210
|
+
}));
|
|
211
|
+
if (entries.length > Number(data.total)) throw new ListingDataError("Invalid folder count");
|
|
212
|
+
const result = {
|
|
213
|
+
...data,
|
|
214
|
+
updatesHref: link(data.updatesHref ?? null),
|
|
215
|
+
entries,
|
|
216
|
+
dataHref: source.href,
|
|
217
|
+
manifestHref: link(data.manifestHref),
|
|
218
|
+
rootHref: link(data.rootHref),
|
|
219
|
+
rootDataHref: link(data.rootDataHref),
|
|
220
|
+
parentHref: link(data.parentHref),
|
|
221
|
+
parentDataHref: link(data.parentDataHref),
|
|
222
|
+
breadcrumbs: data.breadcrumbs.map((raw) => {
|
|
223
|
+
if (typeof raw !== "object" || raw === null || !("name" in raw) || !("href" in raw) || !("dataHref" in raw) || typeof raw.name !== "string")
|
|
224
|
+
throw new ListingDataError("Invalid breadcrumb");
|
|
225
|
+
return { name: raw.name, href: link(raw.href), dataHref: link(raw.dataHref) };
|
|
226
|
+
})
|
|
227
|
+
};
|
|
228
|
+
if (fresh && result.manifestHref) {
|
|
229
|
+
const loaded = await loadListing(result.manifestHref, { signal, cache: "no-store" });
|
|
230
|
+
if (loaded.manifest.total !== data.total || data.listingRevision !== void 0 && loaded.manifest.revision !== data.listingRevision) {
|
|
231
|
+
if (attempt < 2) return fetchThemePage(dataHref, pageHref, theme, signal, true, attempt + 1);
|
|
232
|
+
throw new ListingDataError("Folder changed while refreshing");
|
|
233
|
+
}
|
|
234
|
+
result.entries = [...loaded.entries];
|
|
235
|
+
}
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
var hotModels = /* @__PURE__ */ new WeakMap();
|
|
239
|
+
function restoreThemePage(initial, hot) {
|
|
240
|
+
if (!hot || typeof document === "undefined") return initial;
|
|
241
|
+
const root = document.querySelector("[data-dirwell-theme]");
|
|
242
|
+
if (!root) return initial;
|
|
243
|
+
const snapshot = hotModels.get(root) ?? initial;
|
|
244
|
+
hotModels.set(root, snapshot);
|
|
245
|
+
return snapshot;
|
|
246
|
+
}
|
|
247
|
+
function applyThemeMetadata(page, pageHref) {
|
|
248
|
+
const root = document.querySelector("[data-dirwell-theme]");
|
|
249
|
+
if (root && hotModels.has(root)) hotModels.set(root, page);
|
|
250
|
+
document.title = typeof page.title === "string" ? page.title : "";
|
|
251
|
+
const template = document.createElement("template");
|
|
252
|
+
template.innerHTML = typeof page.metadataHead === "string" ? page.metadataHead : "";
|
|
253
|
+
document.head.querySelectorAll("[data-dirwell-metadata]").forEach((element) => element.remove());
|
|
254
|
+
const base = document.querySelector("base")?.href ?? pageHref;
|
|
255
|
+
const url = (value) => {
|
|
256
|
+
try {
|
|
257
|
+
const target = new URL(value, base);
|
|
258
|
+
return ["http:", "https:"].includes(target.protocol) ? target.href : null;
|
|
259
|
+
} catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
for (const element of template.content.children) {
|
|
264
|
+
if (!element.hasAttribute("data-dirwell-metadata")) continue;
|
|
265
|
+
let next;
|
|
266
|
+
if (element.tagName === "META") {
|
|
267
|
+
const attribute = element.hasAttribute("property") ? "property" : "name";
|
|
268
|
+
const key = element.getAttribute(attribute) ?? "";
|
|
269
|
+
if (!/^(?:description|og:[a-z_:]+|twitter:[a-z_:]+)$/i.test(key)) continue;
|
|
270
|
+
let content = element.getAttribute("content") ?? "";
|
|
271
|
+
if (["og:image", "og:url", "twitter:image"].includes(key)) {
|
|
272
|
+
const resolved = url(content);
|
|
273
|
+
if (resolved === null) continue;
|
|
274
|
+
content = resolved;
|
|
275
|
+
}
|
|
276
|
+
next = document.createElement("meta");
|
|
277
|
+
next.setAttribute(attribute, key);
|
|
278
|
+
next.setAttribute("content", content);
|
|
279
|
+
} else if (element.tagName === "LINK" && element.getAttribute("rel") === "canonical") {
|
|
280
|
+
const href2 = url(element.getAttribute("href") ?? "");
|
|
281
|
+
if (href2 === null) continue;
|
|
282
|
+
next = document.createElement("link");
|
|
283
|
+
next.setAttribute("rel", "canonical");
|
|
284
|
+
next.setAttribute("href", href2);
|
|
285
|
+
} else continue;
|
|
286
|
+
next.setAttribute("data-dirwell-metadata", "");
|
|
287
|
+
document.head.append(next);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export {
|
|
291
|
+
applyThemeMetadata,
|
|
292
|
+
fetchThemePage,
|
|
293
|
+
restoreThemePage
|
|
294
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// ../shared-theme/src/records.ts
|
|
2
|
+
var directoryLike = (entry) => entry.kind === "directory" || entry.link?.targetKind === "directory";
|
|
3
|
+
var entryType = (entry) => entry.kind === "symlink" ? "link" : directoryLike(entry) ? "directory" : "file";
|
|
4
|
+
function fuzzy(query, value) {
|
|
5
|
+
let score = 0, start = 0, last = -2;
|
|
6
|
+
for (const character of query.trim().toLocaleLowerCase()) {
|
|
7
|
+
const index = value.toLocaleLowerCase().indexOf(character, start);
|
|
8
|
+
if (index < 0) return null;
|
|
9
|
+
if (index === last + 1) score += 8;
|
|
10
|
+
if (index === 0 || /[\s/_.-]/.test(value[index - 1] ?? "")) score += 5;
|
|
11
|
+
score += Math.max(0, 4 - index * 0.05);
|
|
12
|
+
last = index;
|
|
13
|
+
start = index + 1;
|
|
14
|
+
}
|
|
15
|
+
return score - value.length * 0.01;
|
|
16
|
+
}
|
|
17
|
+
function visibleRecords(entries, query, types, sort) {
|
|
18
|
+
return entries.map((entry) => ({ entry, score: fuzzy(query, `${entry.name} ${entry.link?.target ?? ""}`) })).filter((item) => types.includes(entryType(item.entry)) && item.score !== null).sort((left, right) => {
|
|
19
|
+
if (query.trim() && left.score !== right.score) return (right.score ?? 0) - (left.score ?? 0);
|
|
20
|
+
const a = left.entry, b = right.entry;
|
|
21
|
+
if (sort.directoriesFirst && directoryLike(a) !== directoryLike(b))
|
|
22
|
+
return directoryLike(a) ? -1 : 1;
|
|
23
|
+
const name = () => sort.nameMode === "unicode" ? compareUnicode(a.name, b.name) : a.name.localeCompare(b.name, void 0, {
|
|
24
|
+
numeric: sort.nameMode === "natural",
|
|
25
|
+
sensitivity: "base"
|
|
26
|
+
});
|
|
27
|
+
const primary = (sort.field === "name" ? name() : sort.field === "size" ? (a.kind === "directory" ? 0 : a.size) - (b.kind === "directory" ? 0 : b.size) : a.modifiedAt.localeCompare(b.modifiedAt)) || name();
|
|
28
|
+
return (sort.direction === "asc" ? primary : -primary) || compareUnicode(a.id, b.id);
|
|
29
|
+
}).map((item) => item.entry);
|
|
30
|
+
}
|
|
31
|
+
function compareUnicode(left, right) {
|
|
32
|
+
const a = [...left], b = [...right];
|
|
33
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
34
|
+
const delta = (a[i]?.codePointAt(0) ?? 0) - (b[i]?.codePointAt(0) ?? 0);
|
|
35
|
+
if (delta) return delta;
|
|
36
|
+
}
|
|
37
|
+
return a.length - b.length;
|
|
38
|
+
}
|
|
39
|
+
function size(bytes) {
|
|
40
|
+
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
|
|
41
|
+
let value = bytes, index = 0;
|
|
42
|
+
while (value >= 1024 && index < 4) {
|
|
43
|
+
value /= 1024;
|
|
44
|
+
index++;
|
|
45
|
+
}
|
|
46
|
+
return `${value.toFixed(index === 0 || value >= 100 ? 0 : 1)} ${units[index]}`;
|
|
47
|
+
}
|
|
48
|
+
function modified(value, local = false) {
|
|
49
|
+
const date = new Date(value);
|
|
50
|
+
if (Number.isNaN(date.getTime())) return "Unknown";
|
|
51
|
+
return local ? date.toLocaleString(void 0, { dateStyle: "short", timeStyle: "short" }) : `${date.toISOString().slice(0, 16).replace("T", " ")} UTC`;
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
directoryLike,
|
|
55
|
+
entryType,
|
|
56
|
+
fuzzy,
|
|
57
|
+
modified,
|
|
58
|
+
size,
|
|
59
|
+
visibleRecords
|
|
60
|
+
};
|