Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 59 additions & 6 deletions apps/presentation/dashboard/vite.chat.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,67 @@
import { readFileSync } from "node:fs";
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
import { defineConfig, type Plugin } from "vite";

const dashboardPublicDir = resolve(import.meta.dirname, "public");
const chatOutDir = resolve(import.meta.dirname, "../../../loopx/web/chat");
const retainedAssetsPath = resolve(chatOutDir, "asset-retention.json");
const sharedPwaAssets = ["manifest.webmanifest", "pwa/icon-192.png", "pwa/icon-512.png"] as const;

function retainedChatAssets(): Plugin {
const previousIndex = resolve(chatOutDir, "index.html");
const previousEntryAssets = existsSync(previousIndex)
? [...readFileSync(previousIndex, "utf8").matchAll(/(?:src|href)="\/chat\/(assets\/[^"]+)"/g)].map((match) => match[1])
: [];
const previousManifest = existsSync(retainedAssetsPath)
? JSON.parse(readFileSync(retainedAssetsPath, "utf8"))
: { schema_version: "loopx_chat_asset_retention_v1", generations: [] };
const previousGenerations = previousManifest.generations;
if (previousManifest.schema_version !== "loopx_chat_asset_retention_v1"
|| !Array.isArray(previousGenerations) || previousGenerations.some(
(generation) => !Array.isArray(generation) || generation.some(
(asset) => typeof asset !== "string" || !/^assets\/[A-Za-z0-9._-]+$/.test(asset),
),
)) {
throw new Error("Invalid chat asset retention manifest");
}
const previousGeneration = previousGenerations.find((generation) =>
previousEntryAssets.every((asset) => generation.includes(asset)),
) ?? previousEntryAssets;

return {
name: "loopx-bounded-chat-asset-retention",
writeBundle(_options, bundle) {
const generations: string[][] = [];
const retained = new Set<string>();
for (const generation of [
Object.keys(bundle).filter((path) => path.startsWith("assets/")).sort(),
previousGeneration,
...previousGenerations,
]) {
const normalized = [...new Set(generation)].sort();
if (normalized.some((asset) => !existsSync(resolve(chatOutDir, asset)))) continue;
if (normalized.every((asset) => retained.has(asset))) continue;
if (normalized.length && !generations.some((item) => item.join("\0") === normalized.join("\0"))) {
generations.push(normalized);
normalized.forEach((asset) => retained.add(asset));
}
// ponytail: one prior bundle protects rolling upgrades; add a larger
// retention window only if multi-release stale tabs become a real need.
if (generations.length === 2) break;
}
for (const name of readdirSync(resolve(chatOutDir, "assets"))) {
if (!retained.has(`assets/${name}`)) rmSync(resolve(chatOutDir, "assets", name));
}
writeFileSync(retainedAssetsPath, `${JSON.stringify({
schema_version: "loopx_chat_asset_retention_v1",
generations,
}, null, 2)}\n`);
},
};
}

function emitSharedPwaAssets(): Plugin {
return {
name: "loopx-shared-dashboard-pwa-assets",
Expand All @@ -28,12 +83,10 @@ export default defineConfig({
// The chat bundle shares the root dashboard's manifest and icons without
// copying unrelated showcase assets into the packaged chat directory.
publicDir: false,
plugins: [react(), tailwindcss(), emitSharedPwaAssets()],
plugins: [react(), tailwindcss(), emitSharedPwaAssets(), retainedChatAssets()],
build: {
outDir: resolve(import.meta.dirname, "../../../loopx/web/chat"),
// Keep prior hashed assets: a running dashboard or an in-flight page may
// still reference an older index.html; deleting old files turns a stale
// page into a white screen. index.html always points at the newest hashes.
outDir: chatOutDir,
// Retention is bounded by retainedChatAssets instead of growing forever.
emptyOutDir: false,
},
});
23 changes: 23 additions & 0 deletions examples/dashboard-pwa-bundle-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import annotations

import json
import re
from pathlib import Path


Expand Down Expand Up @@ -52,6 +53,27 @@ def assert_pwa_bundle(label: str, bundle: Path, manifest_href: str) -> None:
)


def assert_bounded_chat_assets() -> None:
retention = json.loads(
(CHAT_BUNDLE / "asset-retention.json").read_text(encoding="utf-8")
)
assert retention["schema_version"] == "loopx_chat_asset_retention_v1"
generations = retention["generations"]
assert 1 <= len(generations) <= 2, generations
retained = {asset for generation in generations for asset in generation}
referenced = set(
re.findall(
r'(?:src|href)="/chat/(assets/[^"]+)"',
(CHAT_BUNDLE / "index.html").read_text(encoding="utf-8"),
)
)
assert referenced <= set(generations[0]), (referenced, generations[0])
assert retained == {
f"assets/{path.name}" for path in (CHAT_BUNDLE / "assets").iterdir()
}
assert all((CHAT_BUNDLE / asset).is_file() for asset in retained)


def main() -> int:
# The full-public suite is Python-only and starts from a clean checkout, so
# the ignored Vite output is not guaranteed to exist. Always validate the
Expand All @@ -66,6 +88,7 @@ def main() -> int:
if ROOT_BUNDLE.is_dir():
assert_pwa_bundle("root dashboard bundle", ROOT_BUNDLE, "manifest.webmanifest")
assert_pwa_bundle("chat dashboard", CHAT_BUNDLE, "/chat/manifest.webmanifest")
assert_bounded_chat_assets()
print("dashboard-pwa-bundle-smoke ok")
return 0

Expand Down
35 changes: 35 additions & 0 deletions loopx/web/chat/asset-retention.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"schema_version": "loopx_chat_asset_retention_v1",
"generations": [
[
"assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2",
"assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2",
"assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2",
"assets/geist-latin-wght-normal-BgDaEnEv.woff2",
"assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2",
"assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2",
"assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2",
"assets/geist-mono-latin-wght-normal-XN7g48iV.woff2",
"assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2",
"assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2",
"assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2",
"assets/index-Bb6tQe9a.js",
"assets/index-CAld8Q9B.css"
],
[
"assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2",
"assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2",
"assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2",
"assets/geist-latin-wght-normal-BgDaEnEv.woff2",
"assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2",
"assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2",
"assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2",
"assets/geist-mono-latin-wght-normal-XN7g48iV.woff2",
"assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2",
"assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2",
"assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2",
"assets/index-BCCJib1i.css",
"assets/index-o5yb9gCp.js"
]
]
}
1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-0bhIx5_M.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-1ek48Zfo.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-4FpkdPZm.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-5XHJEBmR.css

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-6lOUUHx7.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-87n1zlNJ.css

This file was deleted.

107 changes: 0 additions & 107 deletions loopx/web/chat/assets/index-9IiDicAv.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-9d1S9bUM.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-9wD_r5Rp.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-B1C2FwbO.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-B88OPx8f.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-B8L75LO_.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BEQmjl7v.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BFBuCPSV.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-BGO6BJCs.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-BGlIOe4t.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BHRJcYkB.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-BP0RmPHX.css

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-BP1QffUh.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BQbV8tqm.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-BSxkq-RJ.css

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-BUErjEJT.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BX4BmVJP.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BXZ4jJJg.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BZ6v5kqr.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-BZAVdCU1.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-BbFX7OqK.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Bbl2q4GJ.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Bh5uiZqS.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Bmspg3Jw.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Bs_ZC86m.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-BwhHW4cM.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Bwi155pp.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Bx6T9PIc.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-C-0JyRzm.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-C1OHhOOV.css

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-C2CmDc5R.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-C2EQGEVq.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-C4xwmI7d.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-C7_1lK3X.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CKyCniT-.js

This file was deleted.

107 changes: 0 additions & 107 deletions loopx/web/chat/assets/index-CLqMm9A9.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-CSu-RA-2.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-CThe5lVk.css

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-CWBLcLBj.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-CWu9Zb0m.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CYIgLUGs.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-CaWp_NBN.css

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-CbyH4L9F.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-Ci7Bb-Hg.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-CiiYGC4Q.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CnN4AJQ2.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Co9vSS-Z.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CqxVBlFA.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CreWNyY-.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-CuaTN_p4.js

This file was deleted.

121 changes: 0 additions & 121 deletions loopx/web/chat/assets/index-CwxDMCrv.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-CxRl9_vT.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-CyzsRtSq.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-D-ZLwkDk.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-D18UKAne.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-D1JcAJp-.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-D2CGbqTd.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-D9laKLBQ.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DC5HFDv1.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-DI6Nc7FE.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DKJ5p2QF.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DKKSJxDm.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DLmo9pnP.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DNTHj6za.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-DODAzFAe.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DOLQXkmn.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DSyBT6Kt.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DYYo3B8I.css

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-DaU9YYwh.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Db3HU1A2.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DclJg8hK.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DfZWJsx8.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DgCU_eGn.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DiCXWPfR.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Dk5Y5CRw.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-DlWGFd3A.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Do79u7RP.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-DpJpoD0M.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-DqUh5BjW.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Dqp1Ys3x.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-DuhTDceN.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-Dv3QRK2m.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-HvFwA8w4.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-KX57MZ3S.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-O0nPVPnM.js

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-Q7kkcYrR.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-RBq2pqOr.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-RG-_aLC3.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-RaDXclvH.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-Yu1zpL1O.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-Z33f5-Wp.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-b4ejRnTD.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-ceDA-lHU.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-czeYrGNG.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-hcH65Zv0.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-hmItHWz2.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-k0HHvCOH.css

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-kPzCW1DS.css

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-m_MgoO2m.js

This file was deleted.

1 change: 0 additions & 1 deletion loopx/web/chat/assets/index-mnVpUNXZ.css

This file was deleted.

128 changes: 0 additions & 128 deletions loopx/web/chat/assets/index-qs7RHoKv.js

This file was deleted.

129 changes: 0 additions & 129 deletions loopx/web/chat/assets/index-wKzSBw1w.js

This file was deleted.

126 changes: 0 additions & 126 deletions loopx/web/chat/assets/index-yQOik-72.js

This file was deleted.