@hyperbook/markdown 0.59.3 → 0.59.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.
@@ -30,9 +30,9 @@ hyperbook.bootstrap = (function () {
30
30
  details.addEventListener("toggle", () => {
31
31
  if (id) {
32
32
  if (details.open) {
33
- hyperbook.store.collapsibles.put({ id });
33
+ hyperbook.store.db.collapsibles.put({ id });
34
34
  } else {
35
- hyperbook.store.collapsibles.delete(id);
35
+ hyperbook.store.db.collapsibles.delete(id);
36
36
  }
37
37
 
38
38
  // Sync all elements with the same ID
@@ -57,7 +57,7 @@ hyperbook.bootstrap = (function () {
57
57
  * @param {HTMLElement} root
58
58
  */
59
59
  const updateCollapsibles = (root) => {
60
- hyperbook.store.collapsibles.toArray().then((collapsibles) => {
60
+ hyperbook.store.db.collapsibles.toArray().then((collapsibles) => {
61
61
  const detailsEls = root.querySelectorAll("details.section, details.directive-collapsible");
62
62
  for (let details of detailsEls) {
63
63
  const id = details.getAttribute("data-id");
@@ -95,7 +95,7 @@ hyperbook.bootstrap = (function () {
95
95
  const bookmarkEls = root.getElementsByClassName("bookmark");
96
96
  for (let bookmarkEl of bookmarkEls) {
97
97
  const key = bookmarkEl.getAttribute("data-key");
98
- hyperbook.store.bookmarks.get(key).then((bookmark) => {
98
+ hyperbook.store.db.bookmarks.get(key).then((bookmark) => {
99
99
  if (bookmark) {
100
100
  bookmarkEl.classList.add("active");
101
101
  }
@@ -15,6 +15,7 @@ hyperbook.cloud = (function () {
15
15
  const AUTH_USER_KEY = "hyperbook_auth_user";
16
16
  const LAST_EVENT_ID_KEY = "hyperbook_last_event_id";
17
17
  const EVENT_BATCH_MAX_SIZE = 512 * 1024; // 512KB
18
+ const OFFLINE_QUEUE_MAX_SIZE = 100; // FIX: cap offline queue to avoid unbounded memory growth
18
19
  let isLoadingFromCloud = false;
19
20
  let syncManager = null;
20
21
 
@@ -122,17 +123,27 @@ hyperbook.cloud = (function () {
122
123
  this.updateUI("saving");
123
124
 
124
125
  try {
125
- // Take a snapshot of pending events
126
+ // Snapshot exactly which events we're attempting to send,
127
+ // so that any events added during the async save are not lost.
128
+ // FIX: was `this.pendingEvents = []` after save, which would silently
129
+ // discard events that arrived between the slice() and the clear.
126
130
  const eventsToSend = this.pendingEvents.slice();
127
131
  const serialized = JSON.stringify(eventsToSend);
128
132
 
129
133
  if (!this.isOnline) {
130
- this.offlineQueue.push({
131
- events: eventsToSend,
132
- afterEventId: this.lastEventId,
133
- timestamp: Date.now(),
134
- });
135
- this.pendingEvents = [];
134
+ // FIX: enforce offline queue size cap to prevent unbounded memory growth
135
+ if (this.offlineQueue.length >= OFFLINE_QUEUE_MAX_SIZE) {
136
+ console.warn("Offline queue full — falling back to snapshot on reconnect");
137
+ this.offlineQueue = [{ snapshot: true, timestamp: Date.now() }];
138
+ } else {
139
+ this.offlineQueue.push({
140
+ events: eventsToSend,
141
+ afterEventId: this.lastEventId,
142
+ timestamp: Date.now(),
143
+ });
144
+ }
145
+ // FIX: only clear the events we snapshotted
146
+ this.pendingEvents = this.pendingEvents.slice(eventsToSend.length);
136
147
  this.updateUI("offline-queued");
137
148
  return;
138
149
  }
@@ -151,12 +162,16 @@ hyperbook.cloud = (function () {
151
162
  // 409 — stale state, re-fetch
152
163
  console.log("⚠ Stale state detected, re-fetching from cloud...");
153
164
  await loadFromCloud();
154
- this.pendingEvents = [];
165
+ // FIX: only discard the events we tried to send, not any that
166
+ // arrived concurrently during the async round-trip
167
+ this.pendingEvents = this.pendingEvents.slice(eventsToSend.length);
155
168
  window.location.reload();
156
169
  return;
157
170
  }
158
171
 
159
- this.pendingEvents = [];
172
+ // FIX: only discard the events we snapshotted, preserving any
173
+ // events that were added while the network request was in flight
174
+ this.pendingEvents = this.pendingEvents.slice(eventsToSend.length);
160
175
  this.lastEventId = result.lastEventId;
161
176
  localStorage.setItem(
162
177
  LAST_EVENT_ID_KEY,
@@ -176,8 +191,13 @@ hyperbook.cloud = (function () {
176
191
  });
177
192
  }
178
193
 
179
- async sendEvents(events, afterEventId) {
180
- var effectiveAfterId = afterEventId !== undefined ? afterEventId : this.lastEventId;
194
+ // FIX: removed the redundant `afterEventId` parameter. It was never passed
195
+ // explicitly by `performSave`, so the default always took effect, making the
196
+ // parameter misleading. `processOfflineQueue` now passes it via options instead.
197
+ async sendEvents(events, options = {}) {
198
+ const afterEventId = options.afterEventId !== undefined
199
+ ? options.afterEventId
200
+ : this.lastEventId;
181
201
  try {
182
202
  const data = await apiRequest(
183
203
  `/api/store/${HYPERBOOK_CLOUD.id}/events`,
@@ -185,7 +205,7 @@ hyperbook.cloud = (function () {
185
205
  method: "POST",
186
206
  body: JSON.stringify({
187
207
  events: events,
188
- afterEventId: effectiveAfterId,
208
+ afterEventId: afterEventId,
189
209
  }),
190
210
  },
191
211
  );
@@ -264,11 +284,28 @@ hyperbook.cloud = (function () {
264
284
 
265
285
  console.log(`Processing ${this.offlineQueue.length} queued saves...`);
266
286
 
287
+ // FIX: if the queue was compacted to a snapshot sentinel, send a full
288
+ // snapshot instead of trying to replay individual events
289
+ if (this.offlineQueue.length === 1 && this.offlineQueue[0].snapshot) {
290
+ this.offlineQueue = [];
291
+ try {
292
+ const result = await this.sendSnapshot();
293
+ this.lastEventId = result.lastEventId;
294
+ localStorage.setItem(LAST_EVENT_ID_KEY, String(this.lastEventId));
295
+ this.lastSaveTime = Date.now();
296
+ console.log("✓ Offline snapshot flushed");
297
+ } catch (error) {
298
+ console.error("Failed to flush offline snapshot:", error);
299
+ }
300
+ return;
301
+ }
302
+
267
303
  // Send queued events in order
268
304
  for (let i = 0; i < this.offlineQueue.length; i++) {
269
305
  const queued = this.offlineQueue[i];
270
306
  try {
271
- const result = await this.sendEvents(queued.events, queued.afterEventId);
307
+ // FIX: use named options object to match the updated sendEvents signature
308
+ const result = await this.sendEvents(queued.events, { afterEventId: queued.afterEventId });
272
309
 
273
310
  if (result.conflict) {
274
311
  // Conflict — discard remaining queue, re-fetch
@@ -317,24 +354,27 @@ hyperbook.cloud = (function () {
317
354
  });
318
355
  }
319
356
 
357
+ // FIX: manualSave's no-pending-events path now runs inside saveMutex,
358
+ // preventing a concurrent performSave from racing with sendSnapshot
320
359
  async manualSave() {
321
360
  if (this.pendingEvents.length === 0) {
322
361
  // No pending events — send full snapshot
323
362
  this.clearTimers();
324
- try {
325
- this.updateUI("saving");
326
- const result = await this.sendSnapshot();
327
- this.lastEventId = result.lastEventId;
328
- localStorage.setItem(
329
- LAST_EVENT_ID_KEY,
330
- String(this.lastEventId),
331
- );
332
- this.updateUI("saved");
333
- } catch (error) {
334
- console.error("Manual save failed:", error);
335
- this.updateUI("error");
336
- }
337
- return;
363
+ return this.saveMutex.runExclusive(async () => {
364
+ try {
365
+ this.updateUI("saving");
366
+ const result = await this.sendSnapshot();
367
+ this.lastEventId = result.lastEventId;
368
+ localStorage.setItem(
369
+ LAST_EVENT_ID_KEY,
370
+ String(this.lastEventId),
371
+ );
372
+ this.updateUI("saved");
373
+ } catch (error) {
374
+ console.error("Manual save failed:", error);
375
+ this.updateUI("error");
376
+ }
377
+ });
338
378
  }
339
379
  this.clearTimers();
340
380
  await this.performSave("manual");
@@ -599,8 +639,12 @@ hyperbook.cloud = (function () {
599
639
  minSaveInterval: 1000,
600
640
  });
601
641
 
642
+ // Suppress events from directive initialization (e.g., restoring collapsible
643
+ // state triggers Dexie writes via toggle events after hooks are registered).
644
+ isLoadingFromCloud = true;
645
+
602
646
  // Hook Dexie tables to capture granular events (skip currentState — ephemeral UI data)
603
- hyperbook.store.tables.forEach((table) => {
647
+ hyperbook.store.db.tables.forEach((table) => {
604
648
  if (table.name === "currentState") return;
605
649
 
606
650
  table.hook("creating", function (primKey, obj) {
@@ -630,6 +674,10 @@ hyperbook.cloud = (function () {
630
674
  });
631
675
  });
632
676
  });
677
+
678
+ // Allow directive initialization to settle before accepting sync events
679
+ await new Promise((r) => requestAnimationFrame(() => setTimeout(r, 0)));
680
+ isLoadingFromCloud = false;
633
681
  }
634
682
  }
635
683
 
@@ -41,7 +41,7 @@ hyperbook.abc = (function () {
41
41
  });
42
42
 
43
43
  resetEl?.addEventListener("click", () => {
44
- hyperbook.store.abcMusic.delete(id);
44
+ hyperbook.store.db.abcMusic.delete(id);
45
45
  window.location.reload();
46
46
  });
47
47
 
@@ -54,7 +54,7 @@ hyperbook.abc = (function () {
54
54
  });
55
55
 
56
56
  editorEl.addEventListener("code-input_load", async () => {
57
- const storeResult = await hyperbook.store.abcMusic
57
+ const storeResult = await hyperbook.store.db.abcMusic
58
58
  .where("id")
59
59
  .equals(editorEl.id)
60
60
  .first();
@@ -78,7 +78,7 @@ hyperbook.abc = (function () {
78
78
  });
79
79
 
80
80
  editorEl.addEventListener("change", () => {
81
- hyperbook.store.abcMusic.put({
81
+ hyperbook.store.db.abcMusic.put({
82
82
  id: editorEl.id,
83
83
  tune: editorEl.value,
84
84
  });
@@ -53,7 +53,7 @@ hyperbook.audio = (function () {
53
53
  wavesurfer.on("play", () => update(id));
54
54
  wavesurferInstances[id] = wavesurfer;
55
55
 
56
- hyperbook.store.audio.get(id).then((result) => {
56
+ hyperbook.store.db.audio.get(id).then((result) => {
57
57
  if (result) {
58
58
  wavesurfer.setTime(result.time);
59
59
  }
@@ -117,7 +117,7 @@ hyperbook.audio = (function () {
117
117
  playEl.classList.remove("playing");
118
118
  }
119
119
 
120
- hyperbook.store.audio.put({ id, time });
120
+ hyperbook.store.db.audio.put({ id, time });
121
121
 
122
122
  durationEl.innerHTML = ` ${secondsToTimestamp(time)}/${secondsToTimestamp(duration)}`;
123
123
  }
@@ -8,7 +8,7 @@
8
8
  */
9
9
  hyperbook.bookmarks = (function () {
10
10
  function update(root = document) {
11
- hyperbook.store.bookmarks
11
+ hyperbook.store.db.bookmarks
12
12
  .toArray()
13
13
  .then((bookmarks) => {
14
14
  return bookmarks.map((bookmark) => {
@@ -14,7 +14,7 @@ hyperbook.embed.consent = (function () {
14
14
 
15
15
  async function isAllowed(consentId) {
16
16
  try {
17
- var entry = await hyperbook.store.consent.get(consentId);
17
+ var entry = await hyperbook.store.db.consent.get(consentId);
18
18
  return entry?.allowed === true;
19
19
  } catch (e) {
20
20
  return false;
@@ -22,7 +22,7 @@ hyperbook.embed.consent = (function () {
22
22
  }
23
23
 
24
24
  async function allow(consentId) {
25
- await hyperbook.store.consent.put({ id: consentId, allowed: true });
25
+ await hyperbook.store.db.consent.put({ id: consentId, allowed: true });
26
26
  }
27
27
 
28
28
  function loadContent(wrapper) {
@@ -12,14 +12,14 @@ hyperbook.geogebra = (function () {
12
12
  for (const el of els) {
13
13
  const id = el.getAttribute("data-id");
14
14
 
15
- const result = await hyperbook.store.geogebra.get(id);
15
+ const result = await hyperbook.store.db.geogebra.get(id);
16
16
  if (result && result.state) {
17
17
  el.setBase64(result.state);
18
18
  }
19
19
 
20
20
  el.registerUpdateListener(() => {
21
21
  el.getBase64((b) => {
22
- hyperbook.store.geogebra.put({ id, state: b });
22
+ hyperbook.store.db.geogebra.put({ id, state: b });
23
23
  });
24
24
  });
25
25
  }
@@ -15,7 +15,7 @@ hyperbook.h5p = (function () {
15
15
  const save = (id) =>
16
16
  H5P.getUserData(id, "state", (error, userData) => {
17
17
  if (!error) {
18
- hyperbook.store.h5p.put({ id, userData });
18
+ hyperbook.store.db.h5p.put({ id, userData });
19
19
  }
20
20
  });
21
21
 
@@ -41,7 +41,7 @@ hyperbook.h5p = (function () {
41
41
  const src = el.getAttribute("data-src");
42
42
  const id = el.getAttribute("data-id");
43
43
  if (h5pFrame && src) {
44
- const result = await hyperbook.store.h5p.get(id);
44
+ const result = await hyperbook.store.db.h5p.get(id);
45
45
  const h5pOptions = {
46
46
  ...h5pBaseOptions,
47
47
  id,
@@ -13,12 +13,12 @@ hyperbook.learningmap = (function () {
13
13
  for (let elem of elems) {
14
14
  const map = elem.getElementsByTagName("hyperbook-learningmap")[0];
15
15
  if (map) {
16
- const result = await hyperbook.store.learningmap.get(elem.id);
16
+ const result = await hyperbook.store.db.learningmap.get(elem.id);
17
17
  if (result) {
18
18
  map.initialState = result;
19
19
  }
20
20
  map.addEventListener("change", function (event) {
21
- hyperbook.store.learningmap
21
+ hyperbook.store.db.learningmap
22
22
  .update(elem.id, {
23
23
  id: elem.id,
24
24
  nodes: event.detail.nodes,
@@ -28,7 +28,7 @@ hyperbook.learningmap = (function () {
28
28
  })
29
29
  .then((updated) => {
30
30
  if (updated == 0) {
31
- hyperbook.store.learningmap.put({
31
+ hyperbook.store.db.learningmap.put({
32
32
  id: elem.id,
33
33
  nodes: event.detail.nodes,
34
34
  x: event.detail.x,
@@ -204,14 +204,14 @@ var multievent = {
204
204
  });
205
205
  }
206
206
 
207
- await hyperbook.store.multievent.put({
207
+ await hyperbook.store.db.multievent.put({
208
208
  id: "multievent_" + clNr + "_" + window.location.pathname,
209
209
  state: JSON.stringify(state)
210
210
  });
211
211
  },
212
212
  loadState: async function (clNr) {
213
213
  try {
214
- var record = await hyperbook.store.multievent.get("multievent_" + clNr + "_" + window.location.pathname);
214
+ var record = await hyperbook.store.db.multievent.get("multievent_" + clNr + "_" + window.location.pathname);
215
215
  if (!record) return false;
216
216
 
217
217
  var state = JSON.parse(record.state);
@@ -54,7 +54,7 @@ hyperbook.p5 = (function () {
54
54
  });
55
55
 
56
56
  resetEl?.addEventListener("click", () => {
57
- hyperbook.store.p5.delete(id);
57
+ hyperbook.store.db.p5.delete(id);
58
58
  window.location.reload();
59
59
  });
60
60
 
@@ -68,7 +68,7 @@ hyperbook.p5 = (function () {
68
68
 
69
69
  editor?.addEventListener("code-input_load", async () => {
70
70
  if (id) {
71
- const result = await hyperbook.store.p5.get(id);
71
+ const result = await hyperbook.store.db.p5.get(id);
72
72
  if (result) {
73
73
  editor.value = result.sketch;
74
74
  const code = result.sketch;
@@ -79,7 +79,7 @@ hyperbook.p5 = (function () {
79
79
  }
80
80
 
81
81
  editor.addEventListener("input", () => {
82
- hyperbook.store.p5.put({ id, sketch: editor.value });
82
+ hyperbook.store.db.p5.put({ id, sketch: editor.value });
83
83
  });
84
84
  }
85
85
 
@@ -15,7 +15,7 @@ hyperbook.protect = (function () {
15
15
  const value = inputEl.value;
16
16
  const id = el.getAttribute("data-id");
17
17
 
18
- hyperbook.store.protect.put({ id, passwordHash: btoa(value) }).then(() => {
18
+ hyperbook.store.db.protect.put({ id, passwordHash: btoa(value) }).then(() => {
19
19
  const els = document.querySelectorAll(
20
20
  `input[data-id="${el.getAttribute("data-id")}"]`
21
21
  );
@@ -30,7 +30,7 @@ hyperbook.protect = (function () {
30
30
  */
31
31
  function onUpdateToast(inputEl, el, hiddenEl) {
32
32
  const id = el.getAttribute("data-id");
33
- hyperbook.store.protect.get(id).then((result) => {
33
+ hyperbook.store.db.protect.get(id).then((result) => {
34
34
  if (result) {
35
35
  const value = atob(result.passwordHash);
36
36
  inputEl.value = value;
@@ -58,7 +58,7 @@ hyperbook.protect = (function () {
58
58
  const id = el.getAttribute("data-id");
59
59
 
60
60
  if (!inputEl) continue;
61
- hyperbook.store.protect.get(id).then((result) => {
61
+ hyperbook.store.db.protect.get(id).then((result) => {
62
62
  if (result) {
63
63
  inputEl.value = atob(result.passwordHash);
64
64
  } else {
@@ -170,7 +170,7 @@ hyperbook.python = (function () {
170
170
  });
171
171
 
172
172
  resetEl?.addEventListener("click", () => {
173
- hyperbook.store.pyide.delete(id);
173
+ hyperbook.store.db.pyide.delete(id);
174
174
  window.location.reload();
175
175
  });
176
176
 
@@ -203,14 +203,14 @@ hyperbook.python = (function () {
203
203
  inputBtn?.addEventListener("click", showInput);
204
204
 
205
205
  editor.addEventListener("code-input_load", async () => {
206
- const result = await hyperbook.store.pyide.get(id);
206
+ const result = await hyperbook.store.db.pyide.get(id);
207
207
  if (result) {
208
208
  editor.value = result.script;
209
209
  }
210
210
  });
211
211
 
212
212
  editor.addEventListener("input", () => {
213
- hyperbook.store.pyide.put({ id, script: editor.value });
213
+ hyperbook.store.db.pyide.put({ id, script: editor.value });
214
214
  });
215
215
 
216
216
  test?.addEventListener("click", async () => {
@@ -11,7 +11,7 @@ hyperbook.slideshow = (function () {
11
11
  * @param {string} id
12
12
  */
13
13
  const update = (id) => {
14
- hyperbook.store.slideshow.get(id).then((result) => {
14
+ hyperbook.store.db.slideshow.get(id).then((result) => {
15
15
  const active = result?.active ?? 0;
16
16
  const dots = document.querySelectorAll(`.dot[data-id="${id}"]`);
17
17
  const images = document.querySelectorAll(
@@ -38,11 +38,11 @@ hyperbook.slideshow = (function () {
38
38
  */
39
39
  const moveBy = (id, steps) => {
40
40
  const images = document.querySelectorAll(`.dot[data-id="${id}"]`);
41
- hyperbook.store.slideshow.get(id).then((result) => {
41
+ hyperbook.store.db.slideshow.get(id).then((result) => {
42
42
  let active = result?.active ?? 0;
43
43
  active += steps;
44
44
  active = ((active % images.length) + images.length) % images.length;
45
- hyperbook.store.slideshow.put({ id, active }).then(() => {
45
+ hyperbook.store.db.slideshow.put({ id, active }).then(() => {
46
46
  window.hyperbook.slideshow.update(id);
47
47
  });
48
48
  });
@@ -55,7 +55,7 @@ hyperbook.slideshow = (function () {
55
55
  const setActive = (id, index) => {
56
56
  const images = document.querySelectorAll(`.dot[data-id="${id}"]`);
57
57
  if (index >= 0 && index < images.length) {
58
- hyperbook.store.slideshow.put({ id, active: index }).then(() => {
58
+ hyperbook.store.db.slideshow.put({ id, active: index }).then(() => {
59
59
  window.hyperbook.slideshow.update(id);
60
60
  });
61
61
  }
@@ -13,7 +13,7 @@ hyperbook.struktolab = (function () {
13
13
  const editorId = editor.getAttribute("data-id");
14
14
 
15
15
  // Load saved content for this editor
16
- hyperbook.store.struktolab.get(editorId).then((result) => {
16
+ hyperbook.store.db.struktolab.get(editorId).then((result) => {
17
17
  if (result) {
18
18
  editor.loadJSON(JSON.parse(result.tree));
19
19
  }
@@ -21,7 +21,7 @@ hyperbook.struktolab = (function () {
21
21
 
22
22
  // Listen for changes in the editor
23
23
  editor.addEventListener("change", (e) => {
24
- hyperbook.store.struktolab.put({
24
+ hyperbook.store.db.struktolab.put({
25
25
  id: editorId,
26
26
  tree: JSON.stringify(e.detail.tree),
27
27
  });
@@ -17,7 +17,7 @@ hyperbook.tabs = (function () {
17
17
  // Listen for changes on radio inputs
18
18
  input.addEventListener("change", () => {
19
19
  if (input.checked) {
20
- hyperbook.store.tabs.put({
20
+ hyperbook.store.db.tabs.put({
21
21
  id: tabsId,
22
22
  active: tabId,
23
23
  });
@@ -29,7 +29,7 @@ hyperbook.tabs = (function () {
29
29
  });
30
30
 
31
31
  // Restore saved tab selections
32
- hyperbook.store.tabs.each((result) => {
32
+ hyperbook.store.db.tabs.each((result) => {
33
33
  selectTab(result.id, result.active);
34
34
  });
35
35
  };
@@ -27,7 +27,7 @@ hyperbook.textinput = (function () {
27
27
  const id = textarea.getAttribute("data-id");
28
28
 
29
29
  // Load saved text from store
30
- hyperbook.store.textinput.get(id).then((result) => {
30
+ hyperbook.store.db.textinput.get(id).then((result) => {
31
31
  if (result && result.text) {
32
32
  textarea.value = result.text;
33
33
  }
@@ -37,7 +37,7 @@ hyperbook.textinput = (function () {
37
37
 
38
38
  // Save text to store on input with debouncing
39
39
  const saveToStore = debounce(() => {
40
- hyperbook.store.textinput.put({
40
+ hyperbook.store.db.textinput.put({
41
41
  id: id,
42
42
  text: textarea.value,
43
43
  }).catch((error) => {
@@ -41,7 +41,7 @@ hyperbook.webide = (function () {
41
41
 
42
42
  resetEl?.addEventListener("click", () => {
43
43
  if (window.confirm(hyperbook.i18n.get("webide-reset-prompt"))) {
44
- hyperbook.store.webide.delete(id);
44
+ hyperbook.store.db.webide.delete(id);
45
45
  window.location.reload();
46
46
  }
47
47
  });
@@ -77,7 +77,7 @@ hyperbook.webide = (function () {
77
77
  });
78
78
 
79
79
  const load = async () => {
80
- const result = await hyperbook.store.webide.get(id);
80
+ const result = await hyperbook.store.db.webide.get(id);
81
81
  if (!result) {
82
82
  return;
83
83
  }
@@ -91,7 +91,7 @@ hyperbook.webide = (function () {
91
91
  load();
92
92
 
93
93
  const update = () => {
94
- hyperbook.store.webide.put({
94
+ hyperbook.store.db.webide.put({
95
95
  id,
96
96
  html: editorHTML?.value,
97
97
  css: editorCSS?.value,
@@ -109,7 +109,7 @@ hyperbook.webide = (function () {
109
109
  });
110
110
 
111
111
  editorHTML?.addEventListener("code-input_load", async () => {
112
- const result = await hyperbook.store.webide.get(id);
112
+ const result = await hyperbook.store.db.webide.get(id);
113
113
  if (result) {
114
114
  editorHTML.value = result.html;
115
115
  }
@@ -122,7 +122,7 @@ hyperbook.webide = (function () {
122
122
  });
123
123
 
124
124
  editorCSS?.addEventListener("code-input_load", async () => {
125
- const result = await hyperbook.store.webide.get(id);
125
+ const result = await hyperbook.store.db.webide.get(id);
126
126
  if (result) {
127
127
  editorCSS.value = result.css;
128
128
  }
@@ -135,7 +135,7 @@ hyperbook.webide = (function () {
135
135
  });
136
136
 
137
137
  editorJS?.addEventListener("code-input_load", async () => {
138
- const result = await hyperbook.store.webide.get(id);
138
+ const result = await hyperbook.store.db.webide.get(id);
139
139
  if (result) {
140
140
  editorJS.value = result.js;
141
141
  }
@@ -8,7 +8,7 @@ hyperbook.youtube.consent = (function () {
8
8
 
9
9
  async function isAllowed() {
10
10
  try {
11
- var entry = await hyperbook.store.consent.get(CONSENT_ID);
11
+ var entry = await hyperbook.store.db.consent.get(CONSENT_ID);
12
12
  return entry?.allowed === true;
13
13
  } catch (e) {
14
14
  return false;
@@ -16,7 +16,7 @@ hyperbook.youtube.consent = (function () {
16
16
  }
17
17
 
18
18
  async function allow() {
19
- await hyperbook.store.consent.put({ id: CONSENT_ID, allowed: true });
19
+ await hyperbook.store.db.consent.put({ id: CONSENT_ID, allowed: true });
20
20
  }
21
21
 
22
22
  function loadContent(wrapper) {
@@ -26,28 +26,6 @@
26
26
  /**
27
27
  * @typedef {Object} HyperbookStore
28
28
  * @property {import("dexie").Dexie} db - The underlying Dexie database instance.
29
- * @property {import("dexie").Table} currentState - Ephemeral UI state (mouse, scroll, window size).
30
- * @property {import("dexie").Table} collapsibles - Persisted open/close state for collapsible elements.
31
- * @property {import("dexie").Table} abcMusic - ABC music editor tunes.
32
- * @property {import("dexie").Table} audio - Audio playback positions.
33
- * @property {import("dexie").Table} bookmarks - User bookmarks (path + label).
34
- * @property {import("dexie").Table} p5 - p5.js sketches.
35
- * @property {import("dexie").Table} protect - Password hashes for protected content.
36
- * @property {import("dexie").Table} pyide - Python IDE scripts.
37
- * @property {import("dexie").Table} slideshow - Active slide indices.
38
- * @property {import("dexie").Table} tabs - Active tab selections.
39
- * @property {import("dexie").Table} excalidraw - Excalidraw drawing state.
40
- * @property {import("dexie").Table} webide - Web IDE editor contents (HTML/CSS/JS).
41
- * @property {import("dexie").Table} h5p - H5P user data.
42
- * @property {import("dexie").Table} geogebra - GeoGebra applet state.
43
- * @property {import("dexie").Table} learningmap - Learning map node positions and zoom.
44
- * @property {import("dexie").Table} textinput - Text input field values.
45
- * @property {import("dexie").Table} custom - Custom directive payload storage.
46
- * @property {import("dexie").Table} onlineide - Online IDE scripts.
47
- * @property {import("dexie").Table} sqlideScripts - SQL IDE scripts.
48
- * @property {import("dexie").Table} sqlideDatabases - SQL IDE databases.
49
- * @property {import("dexie").Table} multievent - Multi-event state.
50
- * @property {import("dexie").Table} typst - Typst editor code.
51
29
  * @property {() => Promise<void>} export - Export all store data as a JSON download.
52
30
  * @property {() => Promise<void>} reset - Clear all store data after user confirmation.
53
31
  * @property {() => Promise<void>} import - Import store data from a JSON file.
@@ -192,11 +192,10 @@ hyperbook.store = (function () {
192
192
  input.click();
193
193
  }
194
194
 
195
- // Expose the Dexie db instance properties and public API
196
- return Object.assign(db, {
195
+ return {
197
196
  db,
198
197
  export: hyperbookExport,
199
198
  reset: hyperbookReset,
200
199
  import: hyperbookImport,
201
- });
200
+ };
202
201
  })();
package/dist/assets/ui.js CHANGED
@@ -55,14 +55,14 @@ hyperbook.ui = (function () {
55
55
  */
56
56
  function toggleBookmark(key, label) {
57
57
  const el = document.querySelectorAll(`.bookmark[data-key="${key}"]`);
58
- hyperbook.store.bookmarks.get(key).then((bookmark) => {
58
+ hyperbook.store.db.bookmarks.get(key).then((bookmark) => {
59
59
  if (!bookmark) {
60
- hyperbook.store.bookmarks.add({ path: key, label }).then(() => {
60
+ hyperbook.store.db.bookmarks.add({ path: key, label }).then(() => {
61
61
  el.forEach((e) => e.classList.add("active"));
62
62
  hyperbook.bookmarks.update();
63
63
  });
64
64
  } else {
65
- hyperbook.store.bookmarks.delete(key).then(() => {
65
+ hyperbook.store.db.bookmarks.delete(key).then(() => {
66
66
  el.forEach((e) => e.classList.remove("active"));
67
67
  hyperbook.bookmarks.update();
68
68
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperbook/markdown",
3
- "version": "0.59.3",
3
+ "version": "0.59.4",
4
4
  "author": "Mike Barkmin",
5
5
  "homepage": "https://github.com/openpatch/hyperbook#readme",
6
6
  "license": "MIT",