Dispatch manifest update event
This commit is contained in:
parent
06032e6800
commit
1a2d817cf9
7 changed files with 65 additions and 10 deletions
24
README.md
24
README.md
|
|
@ -206,6 +206,30 @@ document.addEventListener("docslib:rendered", (event) => {
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
При обнаружении новой ревизии клиент отправляет всплывающее DOM-событие `on_manifest_update`. Обработчик из `custom_js` регистрируется до начала фоновой проверки:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.addEventListener("on_manifest_update", (event) => {
|
||||||
|
const {
|
||||||
|
manifest,
|
||||||
|
currentManifest,
|
||||||
|
revision,
|
||||||
|
previousRevision,
|
||||||
|
source,
|
||||||
|
cached,
|
||||||
|
applied,
|
||||||
|
} = event.detail;
|
||||||
|
|
||||||
|
console.log(`Manifest ${previousRevision} → ${revision}`, {
|
||||||
|
manifest,
|
||||||
|
currentManifest,
|
||||||
|
source, // "remote" или "embedded"
|
||||||
|
cached, // удалось ли записать обновление в IndexedDB
|
||||||
|
applied, // false: оно применится при следующем открытии
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
Код из `custom_js` считается доверенным и выполняется в контексте страницы. Изменение системного или пользовательского CSS/JS меняет `revision`, поэтому обновлённый runtime сохраняется в IndexedDB и применяется после перезагрузки клиента.
|
Код из `custom_js` считается доверенным и выполняется в контексте страницы. Изменение системного или пользовательского CSS/JS меняет `revision`, поэтому обновлённый runtime сохраняется в IndexedDB и применяется после перезагрузки клиента.
|
||||||
|
|
||||||
## Live-preview
|
## Live-preview
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ from .server import build, create_app, run
|
||||||
from .ui import HeaderButton
|
from .ui import HeaderButton
|
||||||
|
|
||||||
__all__ = ["Component", "HeaderButton", "Page", "build", "create_app", "run"]
|
__all__ = ["Component", "HeaderButton", "Page", "build", "create_app", "run"]
|
||||||
__version__ = "0.3.4"
|
__version__ = "0.3.5"
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function announceManifestUpdate(nextManifest, source) {
|
||||||
|
const previousRevision = lastSyncedRevision;
|
||||||
|
let cached = false;
|
||||||
|
try {
|
||||||
|
await cachePut(nextManifest);
|
||||||
|
cached = true;
|
||||||
|
} catch (_) { /* the update event still reports an unavailable cache */ }
|
||||||
|
lastSyncedRevision = String(nextManifest.revision || lastSyncedRevision);
|
||||||
|
document.dispatchEvent(new CustomEvent("on_manifest_update", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: {
|
||||||
|
manifest: nextManifest,
|
||||||
|
currentManifest: manifest,
|
||||||
|
revision: nextManifest.revision,
|
||||||
|
previousRevision,
|
||||||
|
source,
|
||||||
|
cached,
|
||||||
|
applied: false,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
async function syncManifest() {
|
async function syncManifest() {
|
||||||
if (syncing) return false;
|
if (syncing) return false;
|
||||||
setSyncing(true);
|
setSyncing(true);
|
||||||
|
|
@ -450,11 +472,11 @@
|
||||||
if (
|
if (
|
||||||
isManifest(embedded) &&
|
isManifest(embedded) &&
|
||||||
embedded.schema_version === manifest.schema_version &&
|
embedded.schema_version === manifest.schema_version &&
|
||||||
String(embedded.updated_at || "") > String(manifest.updated_at || "")
|
String(embedded.updated_at || "") > String(manifest.updated_at || "") &&
|
||||||
|
embedded.revision !== lastSyncedRevision
|
||||||
) {
|
) {
|
||||||
await cachePut(embedded).catch(() => {});
|
await announceManifestUpdate(embedded, "embedded");
|
||||||
lastSyncedRevision = String(embedded.revision || lastSyncedRevision);
|
changed = true;
|
||||||
changed = embedded.revision !== manifest.revision;
|
|
||||||
}
|
}
|
||||||
const response = await fetch(config.manifestUrl, { cache: "no-store" });
|
const response = await fetch(config.manifestUrl, { cache: "no-store" });
|
||||||
if (!response.ok) throw new Error(String(response.status));
|
if (!response.ok) throw new Error(String(response.status));
|
||||||
|
|
@ -462,8 +484,7 @@
|
||||||
if (!isManifest(remote) || remote.schema_version !== embedded.schema_version) throw new Error("manifest");
|
if (!isManifest(remote) || remote.schema_version !== embedded.schema_version) throw new Error("manifest");
|
||||||
const remoteChanged = remote.revision !== lastSyncedRevision;
|
const remoteChanged = remote.revision !== lastSyncedRevision;
|
||||||
if (remoteChanged) {
|
if (remoteChanged) {
|
||||||
await cachePut(remote).catch(() => {});
|
await announceManifestUpdate(remote, "remote");
|
||||||
lastSyncedRevision = String(remote.revision || lastSyncedRevision);
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
elements.refresh.classList.remove("error");
|
elements.refresh.classList.remove("error");
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
document.addEventListener("docslib:rendered", (event) => {
|
document.addEventListener("docslib:rendered", (event) => {
|
||||||
document.documentElement.dataset.exampleRevision = event.detail.manifest.revision;
|
document.documentElement.dataset.exampleRevision = event.detail.manifest.revision;
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
|
document.addEventListener("on_manifest_update", (event) => {
|
||||||
|
document.documentElement.dataset.pendingRevision = event.detail.revision;
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "shared-docs-lib"
|
name = "shared-docs-lib"
|
||||||
version = "0.3.4"
|
version = "0.3.5"
|
||||||
description = "Build self-contained, Obsidian-like documentation sites from Python functions."
|
description = "Build self-contained, Obsidian-like documentation sites from Python functions."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,12 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
|
||||||
assert "return cached" in html
|
assert "return cached" in html
|
||||||
assert 'id="docslib-loader-style"' in html
|
assert 'id="docslib-loader-style"' in html
|
||||||
assert "docslib:rendered" in html
|
assert "docslib:rendered" in html
|
||||||
|
system_js = manifest["client"]["js"]["system"]
|
||||||
|
assert 'new CustomEvent("on_manifest_update"' in system_js
|
||||||
|
assert "currentManifest: manifest" in system_js
|
||||||
|
assert "previousRevision" in system_js
|
||||||
|
assert "cached," in system_js
|
||||||
|
assert "applied: false" in system_js
|
||||||
assert "docslib-runtime-style" in html
|
assert "docslib-runtime-style" in html
|
||||||
assert "indexedDB.open" in html
|
assert "indexedDB.open" in html
|
||||||
assert "link.dataset.page = button.page" in html
|
assert "link.dataset.page = button.page" in html
|
||||||
|
|
@ -168,7 +174,7 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
|
||||||
|
|
||||||
|
|
||||||
def test_build_writes_static_bundle(tmp_path):
|
def test_build_writes_static_bundle(tmp_path):
|
||||||
assert __version__ == "0.3.4"
|
assert __version__ == "0.3.5"
|
||||||
|
|
||||||
@Page("1", "Static page")
|
@Page("1", "Static page")
|
||||||
def static_page():
|
def static_page():
|
||||||
|
|
|
||||||
2
uv.lock
generated
2
uv.lock
generated
|
|
@ -452,7 +452,7 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shared-docs-lib"
|
name = "shared-docs-lib"
|
||||||
version = "0.3.4"
|
version = "0.3.5"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue