Release Healer Man 0.1.29
This commit is contained in:
1 parent
8c9809d3e0
commit
544c1bee91
120 files changed
+4363
-1036
No files matched your search
@@ -1,8 +1,10 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { gzipSync, gunzipSync } from "node:zlib";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
BROWSER_CONTENT_CACHE_NAME,
|
||||
browserContentObjectPath,
|
||||
checkForContentUpdates,
|
||||
contentPackHasUpdate,
|
||||
contentPackIsBundled,
|
||||
@@ -120,7 +122,8 @@ describe("browser content packs", () => {
|
||||
error: "",
|
||||
});
|
||||
const active = storage.stores.get(BROWSER_CONTENT_CACHE_NAME);
|
||||
expect(await (await active?.match("http://localhost/assets/characters/test.glb"))?.text()).toBe("first-model");
|
||||
expect(await (await active?.match(browserContentObjectPath(manifest.files["/assets/characters/test.glb"])))?.text()).toBe("first-model");
|
||||
const originalObject = browserContentObjectPath(manifest.files["/assets/characters/test.glb"]);
|
||||
|
||||
manifest = contentManifest("content-two", "updated.glb", updatedBytes);
|
||||
await checkForContentUpdates();
|
||||
@@ -129,12 +132,13 @@ describe("browser content packs", () => {
|
||||
|
||||
corruptUpdate = true;
|
||||
await expect(installContentPack("characters:test")).rejects.toThrow(/verification/i);
|
||||
expect(await (await active?.match("http://localhost/assets/characters/test.glb"))?.text()).toBe("first-model");
|
||||
expect(await (await active?.match(originalObject))?.text()).toBe("first-model");
|
||||
|
||||
corruptUpdate = false;
|
||||
await installContentPack("characters:test");
|
||||
expect(contentPackHasUpdate("characters:test")).toBe(false);
|
||||
expect(await (await active?.match("http://localhost/assets/characters/test.glb"))?.text()).toBe("updated-model");
|
||||
expect(await (await active?.match(browserContentObjectPath(manifest.files["/assets/characters/test.glb"])))?.text()).toBe("updated-model");
|
||||
expect(await active?.match(originalObject)).toBeUndefined();
|
||||
|
||||
await removeContentPack("characters:test");
|
||||
expect(contentPackIsInstalled("characters:test")).toBe(false);
|
||||
@@ -151,6 +155,63 @@ describe("browser content packs", () => {
|
||||
expect(contentPackIsUsable("core:ui")).toBe(true);
|
||||
});
|
||||
|
||||
it("stores a compressed duplicate once and retains it until its last pack is removed", async () => {
|
||||
const original = new TextEncoder().encode("original shared geometry ".repeat(200));
|
||||
const compressed = gzipSync(original);
|
||||
const firstPath = "/assets/characters/shared-first.glb";
|
||||
const secondPath = "/assets/characters/shared-second.glb";
|
||||
const thirdPath = "/assets/characters/shared-third.glb";
|
||||
const base = contentManifest("compressed", "original.glb", original);
|
||||
const entry = { ...base.files["/assets/characters/test.glb"], download: {
|
||||
url: "/content/objects/shared.glb.gz", encoding: "gzip" as const, sha256: sha256(compressed), bytes: compressed.length,
|
||||
} };
|
||||
const manifest: ContentManifest = { ...base, packs: [
|
||||
{ ...base.packs[0], id: "characters:shared-first", fileCount: 2 },
|
||||
{ ...base.packs[0], id: "characters:shared-second" },
|
||||
], files: {
|
||||
[firstPath]: { ...entry, packId: "characters:shared-first" },
|
||||
[secondPath]: { ...entry, packId: "characters:shared-first" },
|
||||
[thirdPath]: { ...entry, packId: "characters:shared-second" },
|
||||
} };
|
||||
const storage = new MemoryCacheStorage();
|
||||
vi.spyOn(Capacitor, "isNativePlatform").mockReturnValue(false);
|
||||
vi.stubGlobal("caches", storage as unknown as CacheStorage);
|
||||
const fetcher = vi.fn(async (url: RequestInfo | URL) => String(url).endsWith("manifest.json") ? Response.json(manifest) : new Response(compressed));
|
||||
vi.stubGlobal("fetch", fetcher);
|
||||
await checkForContentUpdates();
|
||||
await installContentPack("characters:shared-first");
|
||||
const active = storage.stores.get(BROWSER_CONTENT_CACHE_NAME)!;
|
||||
expect(active.responses.size).toBe(3);
|
||||
const objectPath = browserContentObjectPath(entry);
|
||||
expect(gunzipSync(Buffer.from(await (await active.match(objectPath))!.arrayBuffer()))).toEqual(Buffer.from(original));
|
||||
expect(getContentManagerSnapshot().totalBytes).toBe(compressed.length);
|
||||
await installContentPack("characters:shared-second");
|
||||
expect(getContentManagerSnapshot().totalBytes).toBe(0);
|
||||
expect(fetcher.mock.calls.filter(([url]) => String(url).endsWith(".gz"))).toHaveLength(1);
|
||||
await removeContentPack("characters:shared-first");
|
||||
expect(await active.match(objectPath)).toBeDefined();
|
||||
expect(contentPackIsUsable("characters:shared-second")).toBe(true);
|
||||
await removeContentPack("characters:shared-second");
|
||||
expect(active.responses.size).toBe(0);
|
||||
});
|
||||
|
||||
it("rejects a valid gzip payload that expands to the wrong original model", async () => {
|
||||
const original = new TextEncoder().encode("expected model");
|
||||
const compressed = gzipSync("different model");
|
||||
const base = contentManifest("bad-compressed", "model.glb", original);
|
||||
const manifest = { ...base, files: { "/assets/characters/test.glb": { ...base.files["/assets/characters/test.glb"],
|
||||
download: { url: "/content/objects/model.glb.gz", encoding: "gzip", sha256: sha256(compressed), bytes: compressed.length },
|
||||
} } };
|
||||
const storage = new MemoryCacheStorage();
|
||||
vi.spyOn(Capacitor, "isNativePlatform").mockReturnValue(false);
|
||||
vi.stubGlobal("caches", storage as unknown as CacheStorage);
|
||||
vi.stubGlobal("fetch", vi.fn(async (url: RequestInfo | URL) => String(url).endsWith("manifest.json") ? Response.json(manifest) : new Response(compressed)));
|
||||
await checkForContentUpdates();
|
||||
await expect(installContentPack("characters:test")).rejects.toThrow(/expanded content failed verification/i);
|
||||
expect(storage.stores.get(BROWSER_CONTENT_CACHE_NAME)?.responses.size).toBe(0);
|
||||
expect(contentPackIsUsable("characters:test")).toBe(false);
|
||||
});
|
||||
|
||||
it("uses source-served dungeons in development and the content gate in shipped builds", () => {
|
||||
vi.spyOn(Capacitor, "isNativePlatform").mockReturnValue(false);
|
||||
vi.stubEnv("DEV", true);
|
||||
|
||||
Reference in new issue
Block a user