Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 9, 2026

This PR addresses Issues 13-17 from the static review of PR #436, fixing code consistency, removing dead code, improving performance, and enhancing code clarity in the vault implementation.

Changes Made

Issue 13 - Code Consistency (components/annotorious-annotator/line-parser.js)

  • Removed inconsistent this.vault = vault assignment from constructor
  • Updated all usages to use module-level vault directly, matching pattern used in all other components

Issue 14 - Dead Code Removal (js/vault.js)

  • Removed unreachable empty catch block in prefetchDocuments() method
  • The catch block was dead code because each promise already has its own .catch() handler

Issue 15 - Performance Fix (js/vault.js)

  • Removed duplicate localStorage write in hydrateFromObject() method
  • Eliminated redundant explicit localStorage.setItem() call since this.set() already handles caching
  • Fixes expensive double-serialization issue for large objects

Issue 16 - Bug Fix (js/vault.js)

  • Fixed all() method to correctly work with Map data structure
  • Changed from Object.values(this.store) (always returns [] for Maps) to [...this.store.values()]

Issue 17 - Code Clarity (js/utils.js and js/vault.js)

  • Changed urlFromIdAndType() to return null instead of empty string for IIIF resource types
  • Using null semantically indicates "no URL exists" rather than using empty string as control-flow signal
  • Updated vault guard comment for clarity

Testing

  • ✅ All files passed JavaScript syntax checks
  • ✅ Code review completed with no critical issues
  • ✅ CodeQL security scan passed with 0 alerts

These changes improve code consistency, remove dead code, fix performance issues, and enhance code clarity without breaking existing functionality.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI mentioned this pull request Feb 9, 2026
Copilot AI changed the title [WIP] Refactor IIIF resource fetching and hydration with vault utility Request clarification on Issues 13-17 from static review Feb 9, 2026
Copilot AI requested a review from cubap February 9, 2026 18:46
@cubap
Copy link
Member

cubap commented Feb 9, 2026

Here is the context from the comment pasted directly in for @copilot to consider:

Minor Issues 🟡
Issue 13: this.vault = vault instance assignment is inconsistent with other components
File: components/annotorious-annotator/line-parser.js:55
Category: Code Consistency

Problem:
AnnotoriousAnnotator assigns this.vault = vault in its constructor and uses this.vault.get(...) throughout. Every other component in this PR uses the module-level vault directly (e.g., vault.get(...)). This creates an inconsistent pattern — readers must check whether this.vault is the same singleton or something different.

Suggested Fix: Use vault directly like all other components, and remove the this.vault assignment.

Issue 14: Empty catch block silently swallows errors in prefetchDocuments
File: js/vault.js:258-260
Category: Error Handling — Dead Code

Problem:
The outer try/catch around Promise.all(promises) is unreachable because every individual promise already has its own .catch() handler that returns null. Promise.all will never reject. The empty catch block is dead code.

Current Code:

try {
await Promise.all(promises)
} catch (err) {
}
Suggested Fix:

await Promise.all(promises)
Issue 15: Double localStorage write in hydrateFromObject
File: js/vault.js:176-179
Category: Performance — Redundant Work

Problem:
this.set(data, storageType) on line 176 internally calls localStorage.setItem(cacheKey, JSON.stringify(item)). Then line 179 does it again explicitly:

this.set(data, storageType) // writes to localStorage internally
const cacheKeyToUse = hasKnownType ? this._cacheKey(dataType, id) : cacheKey
try {
localStorage.setItem(cacheKeyToUse, JSON.stringify(data)) // writes AGAIN
} catch {}
Every hydrateFromObject call serializes and writes the parent object to localStorage twice. For large objects, JSON.stringify is expensive.

Suggested Fix: Remove lines 177-180 (the explicit localStorage.setItem). The set() call already handles it.

Issue 16: all() method uses Object.values() on a Map — always returns []
File: js/vault.js:243-245
Category: Bug in Dead Code

Problem:
this.store is a Map (line 6). Object.values() on a Map returns an empty array because Map entries are not enumerable own string-keyed properties. Currently dead code (no callers found), but will be a surprise to anyone who tries to use it.

all() {
return Object.values(this.store) // Always returns []
}
Suggested Fix:

all() {
return [...this.store.values()]
}
Issue 17: urlFromIdAndType returns empty string for IIIF types — fragile control flow coupling
File: js/utils.js:34-40
Category: Code Clarity

Problem:
The added cases return '' with a comment saying "Return empty string to trigger fetch failure and fallback to seed/embedded." This is using an empty return value as a control-flow signal, which is fragile. The vault's _fetchAndHydrate checks if (!uri) to guard against this, but the coupling between these two files is implicit and undocumented.

Suggested: Consider returning null (semantically "no URL exists") instead of ''. Update the vault guard to match.

…ormance issues

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 9, 2026

Here is the context from the comment pasted directly in for @copilot to consider:

Minor Issues 🟡
...

All Issues 13-17 have been addressed in commit ba241ab:

Issue 13: Removed this.vault = vault from line-parser.js and updated all usages to use vault directly for consistency.

Issue 14: Removed the unreachable empty catch block from prefetchDocuments().

Issue 15: Removed duplicate localStorage write in hydrateFromObject() - this.set() already handles it.

Issue 16: Fixed all() method to use [...this.store.values()] instead of Object.values(this.store).

Issue 17: Changed urlFromIdAndType to return null instead of '' for IIIF types and updated the vault guard comment.

All changes have been syntax-checked and passed CodeQL security scan.

Copilot AI changed the title Request clarification on Issues 13-17 from static review Address Issues 13-17 from static review: Fix vault consistency, error handling, and performance issues Feb 9, 2026
@cubap cubap marked this pull request as ready for review February 9, 2026 19:44
@cubap cubap merged commit 01f8684 into vaulting Feb 9, 2026
1 check passed
@cubap cubap deleted the copilot/sub-pr-436-again branch February 9, 2026 19:44
thehabes added a commit that referenced this pull request Feb 11, 2026
* Hydrate from seed when fetch fails

Introduce a seed-based hydration path and helper (hydrateFromObject) so an already-provided item object can be used if the network fetch fails. Reorder logic to define hydration first, use the seed fallback on non-OK responses and exceptions, and return the hydrated object. Also adjust calls to this.get and this.set to pass the embedded object and the correct type. Local caching to localStorage is preserved.

* runVaulttest

* vault all fetches

* Prefetch manifests before resolving canvases

Add Vault.prefetchDocuments to eagerly cache manifest documents and use it when a canvas or annotation page cannot be resolved from the vault. Components updated (continue-working, transcription-block, transcription interface) now attempt to hydrate all project manifests and retry vault lookups before falling back to placeholders. getImage was converted to async and now uses vault.get (with prefetch) instead of direct fetch, with explicit fallbacks to 404/no-image assets. These changes reduce failed network fetches and improve resolution of IIIF v2/v3 canvases and pages.

* Use vault and prefetch manifests; enhance Vault

Replace ad-hoc fetches with the centralized vault API across multiple components and add a manifest prefetch fallback when an item is not immediately resolvable. Components updated: annotorious-annotator/line-parser, column-selector, continue-working, default-transcribe, legacy-annotator/plain, line-image, simple-transcription — they now import and use the shared vault, attempt vault.prefetchDocuments(TPEN.activeProject.manifest) when a resource is missing, and retry resolving. Default-transcribe and others now use vault.get for annotation/page/contentresource resolution and show clearer failure messages.

Major Vault improvements (js/vault.js):
- Normalizes IDs (removes fragment, expands 24-char Mongo hex IDs to TPEN.RERUMURL/id/...).
- Deduplicates concurrent fetches with inFlightPromises to avoid duplicate network requests.
- Improved hydration: walks embedded objects, queues and caches known IIIF resource types, skips common non-resource properties, normalizes and caches discovered URLs/IDs, and stores data keyed by detected resource type when available.
- More resilient fetch handling (returns null on failure if a seed exists) and safer localStorage writes keyed to resource type.
- PrefetchDocuments now calls vault.get with a best-effort type and collects errors.
- Removed the debug runVaultTest export.

These changes make resource resolution more consistent and robust, reduce duplicate network loads, and allow components to recover by hydrating manifests when resources are initially missing.

* Process IIIF resources and simplify ID normalization

Treat canvas/manifest/collection IDs as external/embedded (return empty URL) and simplify _normalizeId to only strip fragment identifiers. Add a _processIIIFResource helper to detect IIIF resources, call get() for them, and return a minimal {id,type,label} representation while avoiding duplicate fetches via the visited set. Update _fetchAndHydrate to invoke this helper for array items and non-array object values. Remove previous behavior that auto-prefixed Mongo hex IDs with TPEN.RERUMURL and the older string-URL detection/fetch logic to better handle embedded IIIF manifests and avoid incorrect fetching.

* Update interfaces/transcription/index.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update components/read-only-transcribe/index.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Guard against empty URI in vault fetch to prevent unnecessary requests (#437)

* Initial plan

* Add guard to prevent fetch with empty URI

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Add prefetchManifests and prefetchCollections aliases with explicit type parameters (#438)

* Initial plan

* Add prefetchManifests and prefetchCollections aliases and update all usages

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Refactor prefetch methods to use docType parameter instead of duplicating code

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Eliminate N+1 fetches for embedded IIIF resources in vault (#439)

* Initial plan

* Fix N+1 fetch issue by caching embedded IIIF resources directly

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Improve comments explaining embedded object detection logic

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Improve embedded object detection with specific content properties

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Allow annotations with body OR target to be cached as embedded

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Add explicit IIIF v2 prefixed types to resource set (#440)

* Initial plan

* Fix IIIF v2 prefix handling in type normalization

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Move prefix pattern to class constant and document resource types

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Revert prefix stripping; explicitly add IIIF v2 prefixed types

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Clarify documentation for agent and annotationlist types

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Update vault.js

* deprecate these

* strip out TPEN.js and vault.js

This component should not include these dependencies.

* Import vault in read-only-transcribe component

Add an import for the vault module (../../js/vault.js) in components/read-only-transcribe/index.js so the component can access vault-related functionality.

* This will work here (#443)

* Early guard to avoid NPEs when this.#transcriptions cannot be used (#444)

* Address Issues 13-17 from static review: Fix vault consistency, error handling, and performance issues (#442)

* Initial plan

* Address Issues 13-17: Fix vault consistency, error handling, and performance issues

Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>

* Fix vault.js issues 8-11: Hoist constants, fix noCache, clone data, add getWithFallback helper (#445)

Issues Fixed:
- Issue 8: Move SKIP_PROPERTIES and IIIF_RESOURCE_TYPES to module scope to prevent recreation on every fetch (28 + 13 = 41 object allocations eliminated per fetch)
- Issue 9: Extract vault.getWithFallback() helper method to consolidate repeated 5-line fallback pattern used in 10+ locations
- Issue 10: Fix noCache parameter to bypass in-memory store, not just localStorage. When noCache=true, caller gets fresh fetch, not stale cached copy
- Issue 11: Clone data with structuredClone() before BFS mutation to prevent corrupting caller's original object via shared reference

Performance Impact:
- Eliminates unnecessary Set allocations (Issue 8)
- Reduces code duplication and maintenance burden (Issue 9)
- Fixes cache bypass behavior (Issue 10)
- Prevents data corruption bugs (Issue 11)

* Update Conditionals to avoid NPEs (#447)

* update conditions to fix pre existing errors

* update conditions to fix pre existing errors

* Use vault.getWithFallback for fetching (#449)

Replace repeated vault.get + prefetchManifests patterns with a single vault.getWithFallback utility to simplify resource resolution and avoid duplicated manifest-hydration logic. Affected components: annotorious-annotator/line-parser.js, column-selector/index.js, continue-working/index.js, default-transcribe/index.js, legacy-annotator/plain.js, simple-transcription/index.js, transcription-block/index.js, interfaces/transcription/index.js. Preserves existing behavior (including the optional strict flag) while centralizing the fallback to project manifests.

* refactor manage columns to use vault (#450)

* refactor manage columns to use vault

* refactor manage columns to use vault

* hotfix for error messaging

* No 'Auto Parse' for now

* No 'Auto Parse' for now

* Fix so CONTRIBUTOR users see the link into the /annotator interface

* See transcription text in .transcription-input on the transcription interface.

* Don't change @deprecated components

* Changes while reviewing

* Changes during review

* Changes during review

* zooming on view transcription interface

* Don't let view transcription interface be larger than the viewport and cause scrolling

* double right-click to zoom out

* double right-click to zoom out

* small change for accessibility

* small change for accessibility.  Add some consistency around how these buttons show or not.

* small change for accessibility.  Add some consistency around how these buttons show or not.

* whoops make it prettier

* changes while reviewing

* remove references to elements that are no longer used

* Extra defensive for an extra chance to find the image

* some cleanup

* Changes while reviewing

* Changes while reviewing

* Changes while reviewing

* Changes while reviewing

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>
Co-authored-by: Bryan Haberberger <bryan.j.haberberger@slu.edu>
cubap added a commit that referenced this pull request Feb 12, 2026
* Hydrate from seed when fetch fails

Introduce a seed-based hydration path and helper (hydrateFromObject) so an already-provided item object can be used if the network fetch fails. Reorder logic to define hydration first, use the seed fallback on non-OK responses and exceptions, and return the hydrated object. Also adjust calls to this.get and this.set to pass the embedded object and the correct type. Local caching to localStorage is preserved.

* runVaulttest

* vault all fetches

* Prefetch manifests before resolving canvases

Add Vault.prefetchDocuments to eagerly cache manifest documents and use it when a canvas or annotation page cannot be resolved from the vault. Components updated (continue-working, transcription-block, transcription interface) now attempt to hydrate all project manifests and retry vault lookups before falling back to placeholders. getImage was converted to async and now uses vault.get (with prefetch) instead of direct fetch, with explicit fallbacks to 404/no-image assets. These changes reduce failed network fetches and improve resolution of IIIF v2/v3 canvases and pages.

* Use vault and prefetch manifests; enhance Vault

Replace ad-hoc fetches with the centralized vault API across multiple components and add a manifest prefetch fallback when an item is not immediately resolvable. Components updated: annotorious-annotator/line-parser, column-selector, continue-working, default-transcribe, legacy-annotator/plain, line-image, simple-transcription — they now import and use the shared vault, attempt vault.prefetchDocuments(TPEN.activeProject.manifest) when a resource is missing, and retry resolving. Default-transcribe and others now use vault.get for annotation/page/contentresource resolution and show clearer failure messages.

Major Vault improvements (js/vault.js):
- Normalizes IDs (removes fragment, expands 24-char Mongo hex IDs to TPEN.RERUMURL/id/...).
- Deduplicates concurrent fetches with inFlightPromises to avoid duplicate network requests.
- Improved hydration: walks embedded objects, queues and caches known IIIF resource types, skips common non-resource properties, normalizes and caches discovered URLs/IDs, and stores data keyed by detected resource type when available.
- More resilient fetch handling (returns null on failure if a seed exists) and safer localStorage writes keyed to resource type.
- PrefetchDocuments now calls vault.get with a best-effort type and collects errors.
- Removed the debug runVaultTest export.

These changes make resource resolution more consistent and robust, reduce duplicate network loads, and allow components to recover by hydrating manifests when resources are initially missing.

* Process IIIF resources and simplify ID normalization

Treat canvas/manifest/collection IDs as external/embedded (return empty URL) and simplify _normalizeId to only strip fragment identifiers. Add a _processIIIFResource helper to detect IIIF resources, call get() for them, and return a minimal {id,type,label} representation while avoiding duplicate fetches via the visited set. Update _fetchAndHydrate to invoke this helper for array items and non-array object values. Remove previous behavior that auto-prefixed Mongo hex IDs with TPEN.RERUMURL and the older string-URL detection/fetch logic to better handle embedded IIIF manifests and avoid incorrect fetching.

* Update interfaces/transcription/index.js



* Update components/read-only-transcribe/index.js



* Guard against empty URI in vault fetch to prevent unnecessary requests (#437)

* Initial plan

* Add guard to prevent fetch with empty URI



---------




* Add prefetchManifests and prefetchCollections aliases with explicit type parameters (#438)

* Initial plan

* Add prefetchManifests and prefetchCollections aliases and update all usages



* Refactor prefetch methods to use docType parameter instead of duplicating code



---------




* Eliminate N+1 fetches for embedded IIIF resources in vault (#439)

* Initial plan

* Fix N+1 fetch issue by caching embedded IIIF resources directly



* Improve comments explaining embedded object detection logic



* Improve embedded object detection with specific content properties



* Allow annotations with body OR target to be cached as embedded



---------




* Add explicit IIIF v2 prefixed types to resource set (#440)

* Initial plan

* Fix IIIF v2 prefix handling in type normalization



* Move prefix pattern to class constant and document resource types



* Revert prefix stripping; explicitly add IIIF v2 prefixed types



* Clarify documentation for agent and annotationlist types



---------




* Update vault.js

* deprecate these

* strip out TPEN.js and vault.js

This component should not include these dependencies.

* Import vault in read-only-transcribe component

Add an import for the vault module (../../js/vault.js) in components/read-only-transcribe/index.js so the component can access vault-related functionality.

* This will work here (#443)

* Early guard to avoid NPEs when this.#transcriptions cannot be used (#444)

* Address Issues 13-17 from static review: Fix vault consistency, error handling, and performance issues (#442)

* Initial plan

* Address Issues 13-17: Fix vault consistency, error handling, and performance issues



---------




* Fix vault.js issues 8-11: Hoist constants, fix noCache, clone data, add getWithFallback helper (#445)

Issues Fixed:
- Issue 8: Move SKIP_PROPERTIES and IIIF_RESOURCE_TYPES to module scope to prevent recreation on every fetch (28 + 13 = 41 object allocations eliminated per fetch)
- Issue 9: Extract vault.getWithFallback() helper method to consolidate repeated 5-line fallback pattern used in 10+ locations
- Issue 10: Fix noCache parameter to bypass in-memory store, not just localStorage. When noCache=true, caller gets fresh fetch, not stale cached copy
- Issue 11: Clone data with structuredClone() before BFS mutation to prevent corrupting caller's original object via shared reference

Performance Impact:
- Eliminates unnecessary Set allocations (Issue 8)
- Reduces code duplication and maintenance burden (Issue 9)
- Fixes cache bypass behavior (Issue 10)
- Prevents data corruption bugs (Issue 11)

* Update Conditionals to avoid NPEs (#447)

* update conditions to fix pre existing errors

* update conditions to fix pre existing errors

* Use vault.getWithFallback for fetching (#449)

Replace repeated vault.get + prefetchManifests patterns with a single vault.getWithFallback utility to simplify resource resolution and avoid duplicated manifest-hydration logic. Affected components: annotorious-annotator/line-parser.js, column-selector/index.js, continue-working/index.js, default-transcribe/index.js, legacy-annotator/plain.js, simple-transcription/index.js, transcription-block/index.js, interfaces/transcription/index.js. Preserves existing behavior (including the optional strict flag) while centralizing the fallback to project manifests.

* refactor manage columns to use vault (#450)

* refactor manage columns to use vault

* refactor manage columns to use vault

* hotfix for error messaging

* No 'Auto Parse' for now

* No 'Auto Parse' for now

* Fix so CONTRIBUTOR users see the link into the /annotator interface

* See transcription text in .transcription-input on the transcription interface.

* Don't change @deprecated components

* Changes while reviewing

* Changes during review

* Changes during review

* zooming on view transcription interface

* Don't let view transcription interface be larger than the viewport and cause scrolling

* double right-click to zoom out

* double right-click to zoom out

* small change for accessibility

* small change for accessibility.  Add some consistency around how these buttons show or not.

* small change for accessibility.  Add some consistency around how these buttons show or not.

* whoops make it prettier

* changes while reviewing

* remove references to elements that are no longer used

* Extra defensive for an extra chance to find the image

* some cleanup

* Changes while reviewing

* Changes while reviewing

* Changes while reviewing

* Changes while reviewing

---------

Co-authored-by: Patrick Cuba <cubap@slu.edu>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants