From b48091f0814785bf1e3e6209f8ab27a73711a16a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:00:54 +0000 Subject: [PATCH 1/5] Initial plan From 1e8aea9004ec7e2b527228bb6ffc281d7b8712e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:03:40 +0000 Subject: [PATCH 2/5] Fix N+1 fetch issue by caching embedded IIIF resources directly Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- js/vault.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/js/vault.js b/js/vault.js index 89809aa6..1fd63a19 100644 --- a/js/vault.js +++ b/js/vault.js @@ -69,7 +69,24 @@ class Vault { if (resourceId && resourceType && iiifResourceTypes.has(normalizedType) && !visited.has(resourceId)) { visited.add(resourceId) - await this.get(resource, resourceType) + + // Check if resource is a full embedded object (has properties beyond id/type) + // or just a minimal reference (only id/type or just a string) + const isEmbeddedObject = typeof resource === 'object' && resource !== null && + Object.keys(resource).some(key => + key !== 'id' && key !== '@id' && + key !== 'type' && key !== '@type' && + key !== 'label' && key !== 'title' + ) + + if (isEmbeddedObject) { + // For embedded objects, cache directly without fetching + this.set(resource, normalizedType) + } else { + // For ID strings or minimal references, fetch the full resource + await this.get(resource, resourceType) + } + return { id: resourceId, type: resourceType, label: resource?.label ?? resource?.title } } return null From 3c51eb5276029bbddb1bbba27f02e685e508340f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:04:55 +0000 Subject: [PATCH 3/5] Improve comments explaining embedded object detection logic Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- js/vault.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/js/vault.js b/js/vault.js index 1fd63a19..3b1be62d 100644 --- a/js/vault.js +++ b/js/vault.js @@ -70,8 +70,12 @@ class Vault { if (resourceId && resourceType && iiifResourceTypes.has(normalizedType) && !visited.has(resourceId)) { visited.add(resourceId) - // Check if resource is a full embedded object (has properties beyond id/type) - // or just a minimal reference (only id/type or just a string) + // Check if resource is a full embedded object vs a minimal reference. + // A minimal reference (e.g., {id, type, label}) should be fetched to get full details. + // An embedded object (e.g., Canvas with height/width/items) should be cached directly. + // We exclude id/type (identity), label/title (descriptive metadata that appears in both) + // and check for any other properties (like height, width, items, body, target, etc.) + // that indicate this is a complete embedded resource rather than just a reference. const isEmbeddedObject = typeof resource === 'object' && resource !== null && Object.keys(resource).some(key => key !== 'id' && key !== '@id' && From 2b042b03df81b1c8f80baedda9e918a03922ec36 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:18:14 +0000 Subject: [PATCH 4/5] Improve embedded object detection with specific content properties Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- js/vault.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/js/vault.js b/js/vault.js index 3b1be62d..0ea9adc2 100644 --- a/js/vault.js +++ b/js/vault.js @@ -70,18 +70,21 @@ class Vault { if (resourceId && resourceType && iiifResourceTypes.has(normalizedType) && !visited.has(resourceId)) { visited.add(resourceId) - // Check if resource is a full embedded object vs a minimal reference. - // A minimal reference (e.g., {id, type, label}) should be fetched to get full details. - // An embedded object (e.g., Canvas with height/width/items) should be cached directly. - // We exclude id/type (identity), label/title (descriptive metadata that appears in both) - // and check for any other properties (like height, width, items, body, target, etc.) - // that indicate this is a complete embedded resource rather than just a reference. + // Check if resource is a full embedded object vs a minimal stub/reference. + // A stub with just {id, type, label} should be fetched to get full content. + // An embedded object has properties that indicate substantial content: + // - items/annotations: arrays containing child resources (Canvas, Manifest, AnnotationPage, Collection) + // - body/target: core annotation properties + // - height+width: Canvas dimensions (both must be present) + // Stubs may have other metadata (label, summary, thumbnail) but lack content properties. + const hasItems = Array.isArray(resource?.items) && resource.items.length > 0 + const hasAnnotations = Array.isArray(resource?.annotations) && resource.annotations.length > 0 + const hasBody = resource?.body !== undefined + const hasTarget = resource?.target !== undefined + const hasCanvasDimensions = resource?.height !== undefined && resource?.width !== undefined + const isEmbeddedObject = typeof resource === 'object' && resource !== null && - Object.keys(resource).some(key => - key !== 'id' && key !== '@id' && - key !== 'type' && key !== '@type' && - key !== 'label' && key !== 'title' - ) + (hasItems || hasAnnotations || (hasBody && hasTarget) || hasCanvasDimensions) if (isEmbeddedObject) { // For embedded objects, cache directly without fetching From 0800ae4f459e97e9caac3f10669352eab445ced4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:19:49 +0000 Subject: [PATCH 5/5] Allow annotations with body OR target to be cached as embedded Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- js/vault.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/vault.js b/js/vault.js index 0ea9adc2..029aa76a 100644 --- a/js/vault.js +++ b/js/vault.js @@ -74,7 +74,7 @@ class Vault { // A stub with just {id, type, label} should be fetched to get full content. // An embedded object has properties that indicate substantial content: // - items/annotations: arrays containing child resources (Canvas, Manifest, AnnotationPage, Collection) - // - body/target: core annotation properties + // - body/target: core annotation properties (at least one present) // - height+width: Canvas dimensions (both must be present) // Stubs may have other metadata (label, summary, thumbnail) but lack content properties. const hasItems = Array.isArray(resource?.items) && resource.items.length > 0 @@ -84,7 +84,7 @@ class Vault { const hasCanvasDimensions = resource?.height !== undefined && resource?.width !== undefined const isEmbeddedObject = typeof resource === 'object' && resource !== null && - (hasItems || hasAnnotations || (hasBody && hasTarget) || hasCanvasDimensions) + (hasItems || hasAnnotations || hasBody || hasTarget || hasCanvasDimensions) if (isEmbeddedObject) { // For embedded objects, cache directly without fetching