From 3f1b20f4c8ac87baf5910aefd5d15f8b8dd36681 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 14 Apr 2026 19:27:55 +0800 Subject: [PATCH 1/2] Fix cross-realm linksTo MIME type handling for file/image defs --- packages/realm-server/tests/indexing-test.ts | 95 +++++++++++++++++++ .../realm-index-query-engine.ts | 28 +++--- 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/packages/realm-server/tests/indexing-test.ts b/packages/realm-server/tests/indexing-test.ts index d19ec87497..87e22e144b 100644 --- a/packages/realm-server/tests/indexing-test.ts +++ b/packages/realm-server/tests/indexing-test.ts @@ -1283,6 +1283,101 @@ module(basename(__filename), function () { ); }); }); + + module('cross-realm FileDef linksTo', function (hooks) { + let consumerRealm: Realm; + + setupPermissionedRealmsCached(hooks, { + mode: 'before', + realms: [ + // provider + { + realmURL: testRealm1URL, + permissions: { + ['@node-test_realm:localhost']: ['read'], + }, + fileSystem: { + 'cross-realm-note.txt': 'hello from provider realm', + }, + }, + // consumer + { + realmURL: testRealm2URL, + permissions: { + '*': ['read', 'write'], + '@node-test_realm:localhost': ['read', 'realm-owner'], + }, + fileSystem: { + 'file-linker.gts': ` + import { CardDef, field, linksTo } from "https://cardstack.com/base/card-api"; + import { FileDef } from "https://cardstack.com/base/file-api"; + + export class FileLinker extends CardDef { + @field attachment = linksTo(() => FileDef); + } + `, + 'file-linker-1.json': { + data: { + attributes: {}, + relationships: { + attachment: { + links: { + self: `${testRealm1URL}cross-realm-note.txt`, + }, + // Simulate stale relationship typing that can appear in index payloads. + data: { + type: 'card', + id: `${testRealm1URL}cross-realm-note.txt`, + }, + }, + }, + meta: { + adoptsFrom: { + module: './file-linker', + name: 'FileLinker', + }, + }, + }, + }, + }, + }, + ], + onRealmSetup({ dbAdapter, realms }) { + permissionedDbAdapter = dbAdapter; + consumerRealm = realms.find( + ({ realm }) => realm.url === testRealm2URL, + )!.realm; + }, + }); + + test('indexes cross-realm linksTo FileDef relationships', async function (assert) { + let entry = await consumerRealm.realmIndexQueryEngine.instance( + new URL(`${testRealm2URL}file-linker-1`), + ); + assert.strictEqual(entry?.type, 'instance', 'instance indexes'); + + let rows = (await permissionedDbAdapter.execute( + `SELECT has_error + FROM boxel_index + WHERE url = $1 + AND type = 'instance' + AND (is_deleted = FALSE OR is_deleted IS NULL)`, + { bind: [`${testRealm2URL}file-linker-1.json`] }, + )) as { has_error: boolean | null }[]; + assert.strictEqual(rows.length, 1, 'found one instance index row'); + assert.false(Boolean(rows[0]?.has_error), 'instance row has no error'); + + let deps = await depsForIndexEntry( + permissionedDbAdapter, + `${testRealm2URL}file-linker-1.json`, + 'instance', + ); + assert.ok( + deps.includes(`${testRealm1URL}cross-realm-note.txt`), + 'deps include cross-realm FileDef target URL', + ); + }); + }); }); }); diff --git a/packages/runtime-common/realm-index-query-engine.ts b/packages/runtime-common/realm-index-query-engine.ts index bf5d0a12a2..6b8d3fe1cd 100644 --- a/packages/runtime-common/realm-index-query-engine.ts +++ b/packages/runtime-common/realm-index-query-engine.ts @@ -41,7 +41,6 @@ import { type CodeRef, } from './code-ref'; import { - isSingleCardDocument, type SingleCardDocument, type LinkableCollectionDocument, isLinkableCollectionDocument, @@ -960,9 +959,18 @@ export class RealmIndexQueryEngine { } } } else { - let response = await this.#fetch(linkURL, { - headers: { Accept: SupportedMimeType.CardJson }, - }); + let response: Response; + + if(expectsCard){ + response = await this.#fetch(linkURL, { + headers: { Accept: SupportedMimeType.CardJson }, + }); + } else { + response = await this.#fetch(linkURL, { + headers: { Accept: SupportedMimeType.FileMeta }, + }); + } + if (!response.ok) { let cardError = await CardError.fromFetchResponse( linkURL.href, @@ -970,18 +978,8 @@ export class RealmIndexQueryEngine { ); throw cardError; } + let json = await response.json(); - if (!isSingleCardDocument(json)) { - throw new Error( - `instance ${ - linkURL.href - } is not a card document. it is: ${JSON.stringify( - json, - null, - 2, - )}`, - ); - } linkResource = { ...json.data, ...{ links: { self: json.data.id } }, From e06f743501e4c13b54ef37ecee0e406d611e3d23 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 14 Apr 2026 19:48:08 +0800 Subject: [PATCH 2/2] fix lint --- packages/runtime-common/realm-index-query-engine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-common/realm-index-query-engine.ts b/packages/runtime-common/realm-index-query-engine.ts index 6b8d3fe1cd..9b9f60983f 100644 --- a/packages/runtime-common/realm-index-query-engine.ts +++ b/packages/runtime-common/realm-index-query-engine.ts @@ -961,7 +961,7 @@ export class RealmIndexQueryEngine { } else { let response: Response; - if(expectsCard){ + if (expectsCard) { response = await this.#fetch(linkURL, { headers: { Accept: SupportedMimeType.CardJson }, });