@hoardodile/host 0.1.2 → 0.1.4
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/dist/chunks/worker-entry.mjs +6 -1
- package/dist/hoard/index.d.ts +24 -19
- package/dist/hoard/index.js +22 -4
- package/dist/hoard/index.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +77 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/hoard/index.ts +4 -1
- package/src/hoard/paths.ts +37 -11
- package/src/hoard/versioned-folder-ops.ts +29 -6
- package/src/hooks.test.ts +70 -0
- package/src/hooks.ts +26 -0
- package/src/install-api.ts +68 -0
- package/src/sandbox/host.ts +30 -1
- package/src/sandbox/worker-entry.mjs +6 -1
|
@@ -43,6 +43,7 @@ const HOOK_NAMES = [
|
|
|
43
43
|
"coverLocal",
|
|
44
44
|
"listFiles",
|
|
45
45
|
"imageHashes",
|
|
46
|
+
"onInstall",
|
|
46
47
|
]
|
|
47
48
|
|
|
48
49
|
const API_METHOD_NAMES = [
|
|
@@ -283,7 +284,11 @@ function send(message) {
|
|
|
283
284
|
function approxByteSize(value) {
|
|
284
285
|
if (value instanceof Uint8Array) return value.byteLength
|
|
285
286
|
try {
|
|
286
|
-
return
|
|
287
|
+
// `undefined` (hooks that legitimately return nothing — e.g.
|
|
288
|
+
// `onInstall`) stringifies to `undefined`, not a string: an empty
|
|
289
|
+
// payload must size 0, never throw into the Infinity branch.
|
|
290
|
+
const text = JSON.stringify(value)
|
|
291
|
+
return (typeof text === "string" ? text : "").length * 2
|
|
287
292
|
} catch {
|
|
288
293
|
return Infinity
|
|
289
294
|
}
|
package/dist/hoard/index.d.ts
CHANGED
|
@@ -188,7 +188,8 @@ declare const RESOURCE_DATA_DIR_NAME = "data";
|
|
|
188
188
|
* per-version database snapshot), `db-backups/` (manual backups,
|
|
189
189
|
* only kept for the current version), `snapshots/` (automatic daily
|
|
190
190
|
* snapshots, only kept for the current version), `resources/<id>/`,
|
|
191
|
-
* `characters/<id>/`, `
|
|
191
|
+
* `characters/<id>/`, `tags/<id>/` (tag art — see {@link VersionPaths.tag}),
|
|
192
|
+
* `plugins/<id>/` (installed content plugins
|
|
192
193
|
* frozen with that version; the builtin `file` plugin is not stored
|
|
193
194
|
* here). Old versions are FROZEN: no writes ever land in
|
|
194
195
|
* `versions/<v>` once a `versions/<v+1>` exists.
|
|
@@ -245,10 +246,18 @@ type VersionPaths = {
|
|
|
245
246
|
resources(): string;
|
|
246
247
|
/** Root folder of all characters in this version: `<root>/versions/<v>/characters`. */
|
|
247
248
|
characters(): string;
|
|
249
|
+
/** Root folder of all tags in this version: `<root>/versions/<v>/tags`. */
|
|
250
|
+
tags(): string;
|
|
248
251
|
/** Root folder of all documents in this version: `<root>/versions/<v>/documents`. */
|
|
249
252
|
documents(): string;
|
|
250
253
|
/** Root folder of a character: `<root>/versions/<v>/characters/<id>`. */
|
|
251
254
|
character(id: string): string;
|
|
255
|
+
/**
|
|
256
|
+
* Root folder of a tag: `<root>/versions/<v>/tags/<id>`. Holds the
|
|
257
|
+
* tag's single image slot (`image.<ext>`), the same convention as
|
|
258
|
+
* character avatar/fullbody slots.
|
|
259
|
+
*/
|
|
260
|
+
tag(id: string): string;
|
|
252
261
|
/** Root of manual backups: `<root>/versions/<v>/db-backups`. */
|
|
253
262
|
dbBackups(): string;
|
|
254
263
|
/** Path to one manual backup: `<root>/versions/<v>/db-backups/<name>`. */
|
|
@@ -263,7 +272,7 @@ type VersionPaths = {
|
|
|
263
272
|
* delete cannot remove a folder whose files live under frozen past
|
|
264
273
|
* archives.
|
|
265
274
|
*/
|
|
266
|
-
deletedMarker(kind: "resources" | "characters", id: string): string;
|
|
275
|
+
deletedMarker(kind: "resources" | "characters" | "tags", id: string): string;
|
|
267
276
|
/** Root folder of a document: `<root>/versions/<v>/documents/<id>`. */
|
|
268
277
|
document(id: string): string;
|
|
269
278
|
/**
|
|
@@ -290,11 +299,11 @@ type LocalPaths = {
|
|
|
290
299
|
logs(): string;
|
|
291
300
|
/**
|
|
292
301
|
* Path to a local derived cover/thumb variant:
|
|
293
|
-
* `<localRoot>/cache/<resources|characters>/<id>/<variant>.<format>`.
|
|
302
|
+
* `<localRoot>/cache/<resources|characters|tags>/<id>/<variant>.<format>`.
|
|
294
303
|
* Holds synthesized covers (resource covers, character avatars and
|
|
295
|
-
* fullbody images); re-rendered when cleared.
|
|
304
|
+
* fullbody images, tag art); re-rendered when cleared.
|
|
296
305
|
*/
|
|
297
|
-
localCover(subjectKind: "resource" | "character", id: string, variant: string, format?: string): string;
|
|
306
|
+
localCover(subjectKind: "resource" | "character" | "tag", id: string, variant: string, format?: string): string;
|
|
298
307
|
/**
|
|
299
308
|
* Per-file derived image variant:
|
|
300
309
|
* `<localRoot>/cache/resources/<id>/file-preview/<sourceCacheId>__<variantKey>.<format>`.
|
|
@@ -320,6 +329,13 @@ type LocalPaths = {
|
|
|
320
329
|
* (b) thumbnail variants (`avatar.webp`, `fullbody.webp`).
|
|
321
330
|
*/
|
|
322
331
|
character(id: string): string;
|
|
332
|
+
/**
|
|
333
|
+
* Root of the local per-tag directory:
|
|
334
|
+
* `<localRoot>/cache/tags/<id>`.
|
|
335
|
+
* Holds (a) versioned copies of replaced tag art and (b) the tag
|
|
336
|
+
* thumbnail variant (`image.avif`).
|
|
337
|
+
*/
|
|
338
|
+
tag(id: string): string;
|
|
323
339
|
/** Root of the trash: `<localRoot>/trash`. */
|
|
324
340
|
trash(): string;
|
|
325
341
|
/** Path to a single trashed item: `<localRoot>/trash/<id>`. */
|
|
@@ -677,6 +693,7 @@ declare function versionedDbFile(root: string, v: number): string;
|
|
|
677
693
|
*/
|
|
678
694
|
declare function versionedPath(root: string, v: number): string;
|
|
679
695
|
|
|
696
|
+
type VersionedFolderSubjectKind = "resource" | "character" | "tag";
|
|
680
697
|
type VersionedFolderOps = {
|
|
681
698
|
/** Ensure the current-version entity folder exists. */
|
|
682
699
|
ensureFolder(id: string): Promise<void>;
|
|
@@ -696,21 +713,9 @@ type VersionedFolderOps = {
|
|
|
696
713
|
*/
|
|
697
714
|
moveFolderToTrash(id: string): Promise<string>;
|
|
698
715
|
};
|
|
699
|
-
/**
|
|
700
|
-
* The four lifecycle operations shared by the resource and character
|
|
701
|
-
* file-system layers. They differ only in which versioned folder they
|
|
702
|
-
* target and how the trash / placeholder names are derived.
|
|
703
|
-
*
|
|
704
|
-
* `moveFolderToTrash` treats `EPERM`/`EBUSY`/`UNKNOWN` as transient Windows
|
|
705
|
-
* locks (a file inside the folder is still open) and leaves the source in
|
|
706
|
-
* place; a boot-time orphan sweep reclaims it later.
|
|
707
|
-
*
|
|
708
|
-
* `readOnly` is a live `{ current: boolean }` ref (the server's runtime
|
|
709
|
-
* read-only flag), so a version switch mid-request re-reads it.
|
|
710
|
-
*/
|
|
711
716
|
declare function buildVersionedFolderOps(paths: StoragePaths, readOnly: {
|
|
712
717
|
readonly current: boolean;
|
|
713
|
-
}, kind:
|
|
718
|
+
}, kind: VersionedFolderSubjectKind): VersionedFolderOps;
|
|
714
719
|
/**
|
|
715
720
|
* Move every file in `sourceFolder` whose name matches `match` into
|
|
716
721
|
* `destFolder` under a timestamped archive name (`<prefix><stamp><ext>`, or
|
|
@@ -748,4 +753,4 @@ type VersionedWriteCommand<T> = (paths: StoragePaths["latest"]) => T | Promise<T
|
|
|
748
753
|
*/
|
|
749
754
|
declare function writeVersioned<T>(paths: StoragePaths, readOnly: boolean, cmd: VersionedWriteCommand<T>): Promise<T>;
|
|
750
755
|
|
|
751
|
-
export { type CreateNextVersionResult, type CreateStoragePathsOptions, type DirSizeOptions, type LocalPaths, ORDER_MANIFEST_NAME, type OccupiedNames, PluginVaultPathError, RESOURCE_DATA_DIR_NAME, type StoragePaths, type VaultCommitResult, type VersionPaths, type VersionedFolderOps, type VersionedWriteCommand, archiveStaleFiles, assertInside, assertSafeSegment, buildVersionedFolderOps, commitVaultFile, createNextVersion, createOccupiedNames, createStoragePaths, currentVersion, discardVaultTempFile, ensureBootstrapVersion, extractArchiveInto, findStagedArchiveFile, findStagedPoolFile, imageVariantKey, listArchiveEntries, listVersions, naturalSort, occupyEntryName, orderEntries, orderManifestPath, parseOrderManifest, parsePluginVaultDest, readActiveVersion, readOrderManifest, removeStagedPoolFile, resolveStagedPoolFiles, sanitizeEntryName, sumDirSizes, uniqueEntryName, validateArchiveBudget, vaultFileSha256, vaultReadFile, vaultRemoveFile, vaultStatFile, vaultTempFile, vaultTotalSize, versionedDbFile, versionedPath, writeActiveVersion, writeOrderManifest, writeStagedArchiveFile, writeStagedPoolFile, writeVersioned };
|
|
756
|
+
export { type CreateNextVersionResult, type CreateStoragePathsOptions, type DirSizeOptions, type LocalPaths, ORDER_MANIFEST_NAME, type OccupiedNames, PluginVaultPathError, RESOURCE_DATA_DIR_NAME, type StoragePaths, type VaultCommitResult, type VersionPaths, type VersionedFolderOps, type VersionedFolderSubjectKind, type VersionedWriteCommand, archiveStaleFiles, assertInside, assertSafeSegment, buildVersionedFolderOps, commitVaultFile, createNextVersion, createOccupiedNames, createStoragePaths, currentVersion, discardVaultTempFile, ensureBootstrapVersion, extractArchiveInto, findStagedArchiveFile, findStagedPoolFile, imageVariantKey, listArchiveEntries, listVersions, naturalSort, occupyEntryName, orderEntries, orderManifestPath, parseOrderManifest, parsePluginVaultDest, readActiveVersion, readOrderManifest, removeStagedPoolFile, resolveStagedPoolFiles, sanitizeEntryName, sumDirSizes, uniqueEntryName, validateArchiveBudget, vaultFileSha256, vaultReadFile, vaultRemoveFile, vaultStatFile, vaultTempFile, vaultTotalSize, versionedDbFile, versionedPath, writeActiveVersion, writeOrderManifest, writeStagedArchiveFile, writeStagedPoolFile, writeVersioned };
|
package/dist/hoard/index.js
CHANGED
|
@@ -1375,8 +1375,10 @@ function createStoragePaths(opts) {
|
|
|
1375
1375
|
resourceData: (id) => join6(vRoot, "resources", assertSafeSegment(id), RESOURCE_DATA_DIR_NAME),
|
|
1376
1376
|
resources: () => join6(vRoot, "resources"),
|
|
1377
1377
|
characters: () => join6(vRoot, "characters"),
|
|
1378
|
+
tags: () => join6(vRoot, "tags"),
|
|
1378
1379
|
documents: () => join6(vRoot, "documents"),
|
|
1379
1380
|
character: (id) => join6(vRoot, "characters", assertSafeSegment(id)),
|
|
1381
|
+
tag: (id) => join6(vRoot, "tags", assertSafeSegment(id)),
|
|
1380
1382
|
dbBackups: () => join6(vRoot, "db-backups"),
|
|
1381
1383
|
dbBackup: (name) => join6(vRoot, "db-backups", assertSafeSegment(name)),
|
|
1382
1384
|
snapshots: () => join6(vRoot, "snapshots"),
|
|
@@ -1412,6 +1414,7 @@ function createStoragePaths(opts) {
|
|
|
1412
1414
|
resFilesCache: (id) => join6(cacheRoot, "resources", assertSafeSegment(id), "files-cache.json"),
|
|
1413
1415
|
resource: (id) => join6(cacheRoot, "resources", assertSafeSegment(id)),
|
|
1414
1416
|
character: (id) => join6(cacheRoot, "characters", assertSafeSegment(id)),
|
|
1417
|
+
tag: (id) => join6(cacheRoot, "tags", assertSafeSegment(id)),
|
|
1415
1418
|
trash: () => join6(localRoot, "trash"),
|
|
1416
1419
|
trashItem: (id) => join6(localRoot, "trash", assertSafeSegment(id)),
|
|
1417
1420
|
tmp: () => join6(cacheRoot, "tmp"),
|
|
@@ -1469,7 +1472,7 @@ function createStoragePaths(opts) {
|
|
|
1469
1472
|
};
|
|
1470
1473
|
}
|
|
1471
1474
|
function localCoverSubjectDir(subjectKind) {
|
|
1472
|
-
return subjectKind === "resource" ? "resources" : "characters";
|
|
1475
|
+
return subjectKind === "resource" ? "resources" : subjectKind === "character" ? "characters" : "tags";
|
|
1473
1476
|
}
|
|
1474
1477
|
function toCacheBasename(filename) {
|
|
1475
1478
|
const dot = filename.lastIndexOf(".");
|
|
@@ -1858,10 +1861,25 @@ async function writeVersioned(paths, readOnly, cmd) {
|
|
|
1858
1861
|
}
|
|
1859
1862
|
|
|
1860
1863
|
// src/hoard/versioned-folder-ops.ts
|
|
1864
|
+
var KIND_LAYOUT = {
|
|
1865
|
+
resource: { trashPrefix: "resources-", deletedKind: "resources" },
|
|
1866
|
+
character: { trashPrefix: "characters-", deletedKind: "characters" },
|
|
1867
|
+
tag: { trashPrefix: "tags-", deletedKind: "tags" }
|
|
1868
|
+
};
|
|
1861
1869
|
function buildVersionedFolderOps(paths, readOnly, kind) {
|
|
1862
|
-
const folderOf = (id) => (current) =>
|
|
1863
|
-
|
|
1864
|
-
|
|
1870
|
+
const folderOf = (id) => (current) => {
|
|
1871
|
+
switch (kind) {
|
|
1872
|
+
case "resource":
|
|
1873
|
+
return current.resource(id);
|
|
1874
|
+
case "character":
|
|
1875
|
+
return current.character(id);
|
|
1876
|
+
case "tag":
|
|
1877
|
+
return current.tag(id);
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
const layout = KIND_LAYOUT[kind];
|
|
1881
|
+
const trashPrefix = layout.trashPrefix;
|
|
1882
|
+
const deletedKind = layout.deletedKind;
|
|
1865
1883
|
async function ensureFolder(id) {
|
|
1866
1884
|
await writeVersioned(
|
|
1867
1885
|
paths,
|