From a72e99265d2b97b4a00bf6aab92ea2966f079427 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 23 Dec 2025 20:53:26 +0000 Subject: [PATCH 01/48] Don't link to staging --- .../506ef767-d8be-4c19-afc8-f03318602cb5.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/catalog-realm/SystemCard/506ef767-d8be-4c19-afc8-f03318602cb5.json b/packages/catalog-realm/SystemCard/506ef767-d8be-4c19-afc8-f03318602cb5.json index c7ffa956d1c..a6730819317 100644 --- a/packages/catalog-realm/SystemCard/506ef767-d8be-4c19-afc8-f03318602cb5.json +++ b/packages/catalog-realm/SystemCard/506ef767-d8be-4c19-afc8-f03318602cb5.json @@ -26,16 +26,6 @@ "self": "../RecommendedModel/37533a45-5b7a-4cfd-a169-a46976e155be" } }, - "modelConfigurations.1": { - "links": { - "self": "https://realms-staging.stack.cards/catalog/ModelConfiguration/anthropic-claude-haiku-45" - } - }, - "modelConfigurations.2": { - "links": { - "self": "https://realms-staging.stack.cards/ctse/personal/ModelConfiguration/08dfc745-4e5c-4be7-b1ba-a7ba56ebd4e3" - } - }, "defaultModelConfiguration": { "links": { "self": null @@ -43,4 +33,4 @@ } } } -} \ No newline at end of file +} From fd6228f5ecb7d9c0339bc2f1ba14096625a611b9 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 23 Dec 2025 20:54:00 +0000 Subject: [PATCH 02/48] Simplify setup to require a single session room for all comms --- packages/host/app/services/matrix-service.ts | 13 +++--- packages/matrix/helpers/index.ts | 30 ------------- ...1000_add-realm-user-id-to-session-rooms.js | 9 ++++ .../handlers/handle-create-session.ts | 14 +++++-- .../handlers/handle-realm-auth.ts | 6 +++ packages/realm-server/main.ts | 8 ++-- packages/realm-server/node-realm.ts | 21 ++++++++-- packages/realm-server/server.ts | 33 ++------------- .../db-queries/session-room-queries.ts | 37 ++++++++++++---- packages/runtime-common/realm.ts | 42 +++++++++---------- 10 files changed, 109 insertions(+), 104 deletions(-) create mode 100644 packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js diff --git a/packages/host/app/services/matrix-service.ts b/packages/host/app/services/matrix-service.ts index d1cbaeb1122..d05ade6ddb7 100644 --- a/packages/host/app/services/matrix-service.ts +++ b/packages/host/app/services/matrix-service.ts @@ -1810,6 +1810,7 @@ export default class MatrixService extends Service { event.type === 'm.room.message' && event.content?.msgtype === APP_BOXEL_REALM_SERVER_EVENT_MSGTYPE ) { + console.log('Received realm server event', event); await this.realmServer.handleEvent(event); } else if ( event.type === APP_BOXEL_REALM_EVENT_TYPE && @@ -1831,14 +1832,16 @@ export default class MatrixService extends Service { let realmResourceForEvent = this.realm.realmForSessionRoomId( event.room_id!, ); + console.log('Trying to figure out realm for event', { + event, + realmResourceForEvent, + }); if (!realmResourceForEvent) { - realmEventsLogger.debug( - 'Ignoring realm event because no realm found', - event, - ); + console.log('Ignoring realm event because no realm found', event); } else { + // TODO: CHECK THAT THE SENDER IS THE REALM SERVER? if (realmResourceForEvent.info?.realmUserId !== event.sender) { - realmEventsLogger.warn( + console.log( `Realm event sender ${event.sender} is not the realm user ${realmResourceForEvent.info?.realmUserId}`, event, ); diff --git a/packages/matrix/helpers/index.ts b/packages/matrix/helpers/index.ts index 39a1eb22d7b..4e6edfa4e7c 100644 --- a/packages/matrix/helpers/index.ts +++ b/packages/matrix/helpers/index.ts @@ -120,36 +120,6 @@ export async function setRealmRedirects(page: Page) { } export async function registerRealmUsers(synapse: SynapseInstance) { - await registerUser( - synapse, - 'base_realm', - await realmPassword('base_realm', realmSecretSeed), - ); - await registerUser( - synapse, - 'experiments_realm', - await realmPassword('experiments_realm', realmSecretSeed), - ); - await registerUser( - synapse, - 'catalog_realm', - await realmPassword('catalog_realm', realmSecretSeed), - ); - await registerUser( - synapse, - 'skills_realm', - await realmPassword('skills_realm', realmSecretSeed), - ); - await registerUser( - synapse, - 'test_realm', - await realmPassword('test_realm', realmSecretSeed), - ); - await registerUser( - synapse, - 'node-test_realm', - await realmPassword('node-test_realm', realmSecretSeed), - ); await registerUser( synapse, 'realm_server', diff --git a/packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js b/packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js new file mode 100644 index 00000000000..f28057745f5 --- /dev/null +++ b/packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js @@ -0,0 +1,9 @@ +exports.up = (pgm) => { + pgm.addColumns('session_rooms', { + realm_user_id: { type: 'varchar' }, + }); +}; + +exports.down = (pgm) => { + pgm.dropColumns('session_rooms', ['realm_user_id']); +}; diff --git a/packages/realm-server/handlers/handle-create-session.ts b/packages/realm-server/handlers/handle-create-session.ts index 8bd1c49d879..b95efe051bd 100644 --- a/packages/realm-server/handlers/handle-create-session.ts +++ b/packages/realm-server/handlers/handle-create-session.ts @@ -1,7 +1,6 @@ import { fetchSessionRoom, logger, - REALM_SERVER_REALM, SupportedMimeType, upsertSessionRoom, } from '@cardstack/runtime-common'; @@ -42,17 +41,26 @@ export default function handleCreateSessionRequest({ createJWT: async (user: string, sessionRoom: string) => createJWT({ user, sessionRoom }, realmSecretSeed), ensureSessionRoom: async (userId: string) => { + const realmServerUserId = matrixClient.getUserId(); + if (!realmServerUserId) { + throw new Error( + 'Realm server Matrix user ID is not available, unable to create session room', + ); + } + console.log('Realm server user ID:', realmServerUserId); let sessionRoom = await fetchSessionRoom( dbAdapter, - REALM_SERVER_REALM, + realmServerUserId, userId, ); + console.log('Fetched session room from DB:', sessionRoom); if (!sessionRoom) { + console.log('No session room???', userId); sessionRoom = await matrixClient.createDM(userId); await upsertSessionRoom( dbAdapter, - REALM_SERVER_REALM, + realmServerUserId, userId, sessionRoom, ); diff --git a/packages/realm-server/handlers/handle-realm-auth.ts b/packages/realm-server/handlers/handle-realm-auth.ts index 1e70c1c3b18..0708d531202 100644 --- a/packages/realm-server/handlers/handle-realm-auth.ts +++ b/packages/realm-server/handlers/handle-realm-auth.ts @@ -50,6 +50,12 @@ export default function handleRealmAuth({ } try { + console.log( + 'Realm auth creating session for realm:', + realmUrl, + 'and user:', + matrixUserId, + ); let sessionRoom = await realm.ensureSessionRoom(matrixUserId); sessions[realmUrl] = createJWT( { diff --git a/packages/realm-server/main.ts b/packages/realm-server/main.ts index 843ce85d027..a299cdeaae8 100644 --- a/packages/realm-server/main.ts +++ b/packages/realm-server/main.ts @@ -228,11 +228,12 @@ const getIndexHTML = async () => { await waitForWorkerManager(workerManagerPort); } - let realmServerMatrixClient = new MatrixClient({ + let matrixClient = new MatrixClient({ matrixURL: new URL(MATRIX_URL), username: REALM_SERVER_MATRIX_USERNAME, seed: REALM_SECRET_SEED, }); + await matrixClient.login(); let prerenderer = createRemotePrerenderer(prerendererUrl); let createPrerenderAuth = buildCreatePrerenderAuth(REALM_SECRET_SEED); @@ -261,12 +262,11 @@ const getIndexHTML = async () => { { url, adapter: realmAdapter, - matrix: { url: new URL(matrixURL), username }, secretSeed: REALM_SECRET_SEED, virtualNetwork, dbAdapter, queue, - realmServerMatrixClient, + matrixClient, definitionLookup, }, { @@ -304,7 +304,7 @@ const getIndexHTML = async () => { let server = new RealmServer({ realms, virtualNetwork, - matrixClient: realmServerMatrixClient, + matrixClient, realmsRootPath, realmServerSecretSeed: REALM_SERVER_SECRET_SEED, realmSecretSeed: REALM_SECRET_SEED, diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index 329b35e268b..3e9ea5d712b 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -234,7 +234,7 @@ export class NodeAdapter implements RealmAdapter { dbAdapter: DBAdapter, ): Promise { realmEventsLog.debug('Broadcasting realm event', event); - + let realmUserId; if (dbAdapter.isClosed) { realmEventsLog.warn( `Database adapter is closed, skipping sending realm event`, @@ -243,12 +243,25 @@ export class NodeAdapter implements RealmAdapter { } try { await matrixClient.login(); + realmUserId = matrixClient.getUserId(); + if (!realmUserId) { + realmEventsLog.error( + 'Matrix client has no user ID after login, unable to broadcast realm event', + event, + ); + return; + } } catch (e) { realmEventsLog.error('Error logging into matrix. Skipping broadcast', e); return; } - let dmRooms = await this.waitForSessionRooms(dbAdapter, realmUrl); + let dmRooms = await this.waitForSessionRooms( + dbAdapter, + realmUrl, + realmUserId, + ); + console.log('Dm rooms for realm: ', realmUrl, dmRooms); realmEventsLog.debug('Sending to dm rooms', Object.values(dmRooms)); @@ -269,6 +282,7 @@ export class NodeAdapter implements RealmAdapter { private async waitForSessionRooms( dbAdapter: DBAdapter, realmUrl: string, + realmUserId: string, attempts = 3, delayMs = 50, ): Promise> { @@ -278,7 +292,7 @@ export class NodeAdapter implements RealmAdapter { let dmRooms: Record = {}; try { - dmRooms = await fetchAllSessionRooms(dbAdapter, realmUrl); + dmRooms = await fetchAllSessionRooms(dbAdapter, realmUrl, realmUserId); } catch (e) { realmEventsLog.error('Error getting account data', e); return {}; // bail immediately on errors instead of retrying @@ -296,6 +310,7 @@ export class NodeAdapter implements RealmAdapter { return await this.waitForSessionRooms( dbAdapter, realmUrl, + realmUserId, attempts - 1, delayMs, ); diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index b1ca890654c..bc409dab8df 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -33,7 +33,6 @@ import { fetchRequestFromContext, methodOverrideSupport, } from './middleware'; -import { registerUser } from './synapse'; import convertAcceptHeaderQueryParam from './middleware/convert-accept-header-qp'; import convertAuthHeaderQueryParam from './middleware/convert-auth-header-qp'; import { NodeAdapter } from './node-realm'; @@ -44,10 +43,7 @@ import { extractSupportedMimeType } from '@cardstack/runtime-common/router'; import { any, type Expression } from '@cardstack/runtime-common/expression'; import * as Sentry from '@sentry/node'; import type { MatrixClient } from '@cardstack/runtime-common/matrix-client'; -import { - passwordFromSeed, - getMatrixUsername, -} from '@cardstack/runtime-common/matrix-client'; +import { getMatrixUsername } from '@cardstack/runtime-common/matrix-client'; import { createRoutes } from './routes'; import { APP_BOXEL_REALM_SERVER_EVENT_MSGTYPE } from '@cardstack/runtime-common/matrix-constants'; import type { Prerenderer } from '@cardstack/runtime-common'; @@ -536,18 +532,7 @@ export class RealmServer { let realmPath = resolve(join(this.realmsRootPath, ownerUsername, endpoint)); ensureDirSync(realmPath); - let username = `realm/${ownerUsername}_${endpoint}`; - let { userId } = await registerUser({ - matrixURL: this.matrixClient.matrixURL, - displayname: username, - username, - password: await passwordFromSeed(username, this.realmSecretSeed), - registrationSecret: await this.getMatrixRegistrationSecret(), - }); - this.log.debug(`created realm bot user '${userId}' for new realm ${url}`); - await insertPermissions(this.dbAdapter, new URL(url), { - [userId]: DEFAULT_PERMISSIONS, [ownerUserId]: DEFAULT_PERMISSIONS, }); @@ -573,12 +558,10 @@ export class RealmServer { let realm = this.createAndMountRealm( realmPath, url, - username, undefined, undefined, userInitiatedPriority, ); - await realm.ensureSessionRoom(ownerUserId); return { realm, @@ -589,7 +572,6 @@ export class RealmServer { private createAndMountRealm = ( path: string, url: string, - username: string, copiedFromRealm?: URL, enableFileWatcher?: boolean, fromScratchIndexPriority?: number, @@ -616,11 +598,7 @@ export class RealmServer { virtualNetwork: this.virtualNetwork, dbAdapter: this.dbAdapter, queue: this.queue, - matrix: { - url: new URL(this.matrixClient.matrixURL), - username, - }, - realmServerMatrixClient: this.matrixClient, + matrixClient: this.matrixClient, definitionLookup: this.definitionLookup, }, Object.keys(realmOptions).length ? realmOptions : undefined, @@ -676,7 +654,6 @@ export class RealmServer { continue; } let adapter = new NodeAdapter(realmPath, this.enableFileWatcher); - let username = `realm/${owner}_${realmName}`; let realm = new Realm({ url, adapter, @@ -684,11 +661,7 @@ export class RealmServer { virtualNetwork: this.virtualNetwork, dbAdapter: this.dbAdapter, queue: this.queue, - matrix: { - url: this.matrixClient.matrixURL, - username, - }, - realmServerMatrixClient: this.matrixClient, + matrixClient: this.matrixClient, definitionLookup: this.definitionLookup, }); this.virtualNetwork.mount(realm.handle); diff --git a/packages/runtime-common/db-queries/session-room-queries.ts b/packages/runtime-common/db-queries/session-room-queries.ts index 17d9d23efe4..c92fd6211ab 100644 --- a/packages/runtime-common/db-queries/session-room-queries.ts +++ b/packages/runtime-common/db-queries/session-room-queries.ts @@ -8,12 +8,12 @@ export const REALM_SERVER_REALM = '__realm-server__'; */ export async function fetchSessionRoom( dbAdapter: DBAdapter, - realmURL: string, + realmUserId: string, matrixUserId: string, ) { let rows = await query(dbAdapter, [ - 'SELECT room_id FROM session_rooms WHERE realm_url =', - param(realmURL), + 'SELECT room_id FROM session_rooms WHERE realm_user_id =', + param(realmUserId), 'AND matrix_user_id =', param(matrixUserId), ]); @@ -31,14 +31,16 @@ export async function fetchSessionRoom( */ export async function upsertSessionRoom( dbAdapter: DBAdapter, - realmURL: string, + realmUserId: string, matrixUserId: string, roomId: string, ) { await query(dbAdapter, [ - 'INSERT INTO session_rooms (realm_url, matrix_user_id, room_id, created_at, updated_at)', + 'INSERT INTO session_rooms (realm_url, realm_user_id, matrix_user_id, room_id, created_at, updated_at)', 'VALUES (', - param(realmURL), + param(REALM_SERVER_REALM), + ',', + param(realmUserId), ',', param(matrixUserId), ',', @@ -52,6 +54,9 @@ export async function upsertSessionRoom( 'room_id =', param(roomId), ',', + 'realm_user_id =', + param(realmUserId), + ',', 'updated_at =', dbExpression({ pg: 'NOW()', sqlite: 'CURRENT_TIMESTAMP' }), ]); @@ -63,12 +68,30 @@ export async function upsertSessionRoom( export async function fetchAllSessionRooms( dbAdapter: DBAdapter, realmURL: string, + realmUserId: string, ) { + console.log( + 'Fetching all session rooms for realmURL:', + realmURL, + 'and realmUserId:', + realmUserId, + ); let rows = await query(dbAdapter, [ - 'SELECT matrix_user_id, room_id FROM session_rooms WHERE realm_url =', + 'SELECT sr.matrix_user_id, sr.room_id', + 'FROM session_rooms sr', + 'JOIN realm_user_permissions rup', + 'ON rup.username = sr.matrix_user_id', + 'WHERE rup.realm_url =', param(realmURL), + 'AND (rup.read = true OR rup.write = true)', + 'AND sr.realm_user_id =', + param(realmUserId), + 'AND sr.realm_url =', + param(REALM_SERVER_REALM), ]); + console.log('Fetched session rooms:', rows); + let result: Record = {}; for (let row of rows) { if (row.matrix_user_id && row.room_id) { diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 9aadc58f49d..d9375b415d9 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -318,7 +318,6 @@ export type RequestContext = { realm: Realm; permissions: RealmPermissions }; export class Realm { #startedUp = new Deferred(); #matrixClient: MatrixClient; - #realmServerMatrixClient: MatrixClient; #realmIndexUpdater: RealmIndexUpdater; #realmIndexQueryEngine: RealmIndexQueryEngine; #adapter: RealmAdapter; @@ -332,7 +331,6 @@ export class Realm { #disableModuleCaching = false; #fullIndexOnStartup = false; #fromScratchIndexPriority = systemInitiatedPriority; - #realmServerMatrixUserId: string; #definitionLookup: DefinitionLookup; #copiedFromRealm: URL | undefined; #sourceCache = new AliasCache(); @@ -366,28 +364,25 @@ export class Realm { { url, adapter, - matrix, secretSeed, dbAdapter, queue, virtualNetwork, - realmServerMatrixClient, + matrixClient, definitionLookup, }: { url: string; adapter: RealmAdapter; - matrix: MatrixConfig; secretSeed: string; dbAdapter: DBAdapter; queue: QueuePublisher; virtualNetwork: VirtualNetwork; - realmServerMatrixClient: MatrixClient; + matrixClient: MatrixClient; definitionLookup: DefinitionLookup; }, opts?: Options, ) { this.paths = new RealmPaths(new URL(url)); - let { username, url: matrixURL } = matrix; this.#realmSecretSeed = secretSeed; this.#dbAdapter = dbAdapter; this.#adapter = adapter; @@ -395,16 +390,7 @@ export class Realm { this.#fullIndexOnStartup = opts?.fullIndexOnStartup ?? false; this.#fromScratchIndexPriority = opts?.fromScratchIndexPriority ?? systemInitiatedPriority; - this.#realmServerMatrixClient = realmServerMatrixClient; - this.#realmServerMatrixUserId = userIdFromUsername( - realmServerMatrixClient.username, - realmServerMatrixClient.matrixURL.href, - ); - this.#matrixClient = new MatrixClient({ - matrixURL, - username, - seed: secretSeed, - }); + this.#matrixClient = matrixClient; this.#disableModuleCaching = Boolean(opts?.disableModuleCaching); this.#copiedFromRealm = opts?.copiedFromRealm; let owner: string | undefined; @@ -434,7 +420,7 @@ export class Realm { // server so that we can assume user that owns this realm. refactor this // back to using the realm's own matrix client after running cards in // headless chrome lands. - new RealmAuthDataSource(this.#realmServerMatrixClient, () => _fetch), + new RealmAuthDataSource(this.#matrixClient, () => _fetch), ), ]); @@ -578,18 +564,25 @@ export class Realm { } async ensureSessionRoom(matrixUserId: string): Promise { + console.log('realm.ts - Ensuring session room for user:', matrixUserId); let sessionRoom = await fetchSessionRoom( this.#dbAdapter, - this.url, + this.#matrixClient.getUserId(), matrixUserId, ); + console.log('Fetched session room from DB:', sessionRoom); if (!sessionRoom) { + console.log('No session room, creating one for user:', matrixUserId); await this.#matrixClient.login(); + console.log( + 'Logged into matrix as realm server user', + this.#matrixClient.getUserId(), + ); sessionRoom = await this.#matrixClient.createDM(matrixUserId); await upsertSessionRoom( this.#dbAdapter, - this.url, + this.#matrixClient.getUserId(), matrixUserId, sessionRoom, ); @@ -1306,7 +1299,12 @@ export class Realm { ensureSessionRoom: async (userId: string) => this.ensureSessionRoom(userId), setSessionRoom: (userId: string, roomId: string) => - upsertSessionRoom(this.#dbAdapter, this.url, userId, roomId), + upsertSessionRoom( + this.#dbAdapter, + this.#matrixClient.getUserId(), + userId, + roomId, + ), } as Utils, ); @@ -3751,7 +3749,7 @@ export class Realm { private async createRequestContext(): Promise { let permissions = { - [this.#realmServerMatrixUserId]: ['assume-user'] as RealmAction[], + [this.#matrixClient.getUserId()]: ['assume-user'] as RealmAction[], ...(await fetchRealmPermissions(this.#dbAdapter, new URL(this.url))), }; return { From d920670c2cb2e4b10147333ef9613161eb6da879 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 24 Dec 2025 00:46:40 +0000 Subject: [PATCH 03/48] Add realm url to indexing events --- packages/base/matrix-event.gts | 7 +++-- packages/host/app/services/matrix-service.ts | 31 ++++++------------- packages/host/app/services/message-service.ts | 6 +++- packages/host/tests/helpers/adapter.ts | 7 ++++- .../message-service-subscription-test.gts | 1 + packages/realm-server/node-realm.ts | 10 +++++- .../tests/card-source-endpoints-test.ts | 6 ++++ .../realm-server/tests/helpers/indexing.ts | 2 ++ .../tests/realm-endpoints-test.ts | 4 +++ 9 files changed, 47 insertions(+), 27 deletions(-) diff --git a/packages/base/matrix-event.gts b/packages/base/matrix-event.gts index 9f2b6cca49c..8961f0619ef 100644 --- a/packages/base/matrix-event.gts +++ b/packages/base/matrix-event.gts @@ -372,9 +372,12 @@ export interface RealmEvent extends BaseMatrixEvent { content: RealmEventContent; } -export type RealmEventContent = +export type RealmEventContent = ( | IndexRealmEventContent - | UpdateRealmEventContent; + | UpdateRealmEventContent +) & { + realmURL?: string; +}; export type IndexRealmEventContent = | IncrementalIndexEventContent diff --git a/packages/host/app/services/matrix-service.ts b/packages/host/app/services/matrix-service.ts index d05ade6ddb7..edbe9a1b260 100644 --- a/packages/host/app/services/matrix-service.ts +++ b/packages/host/app/services/matrix-service.ts @@ -1829,30 +1829,17 @@ export default class MatrixService extends Service { return; } - let realmResourceForEvent = this.realm.realmForSessionRoomId( - event.room_id!, - ); - console.log('Trying to figure out realm for event', { - event, - realmResourceForEvent, - }); - if (!realmResourceForEvent) { - console.log('Ignoring realm event because no realm found', event); - } else { - // TODO: CHECK THAT THE SENDER IS THE REALM SERVER? - if (realmResourceForEvent.info?.realmUserId !== event.sender) { - console.log( - `Realm event sender ${event.sender} is not the realm user ${realmResourceForEvent.info?.realmUserId}`, - event, - ); - } - - (event.content as any).origin_server_ts = event.origin_server_ts; - this.messageService.relayRealmEvent( - realmResourceForEvent.url, - event.content as RealmEventContent, + const content = event.content as RealmEventContent; + if (!content.realmURL) { + realmEventsLogger.debug( + 'Ignoring realm event because no realm URL was provided', + event, ); + return; } + + (content as any).origin_server_ts = event.origin_server_ts; + this.messageService.relayRealmEvent(content); } } diff --git a/packages/host/app/services/message-service.ts b/packages/host/app/services/message-service.ts index 52e41ae8e21..85c2df81683 100644 --- a/packages/host/app/services/message-service.ts +++ b/packages/host/app/services/message-service.ts @@ -44,7 +44,11 @@ export default class MessageService extends Service { } } - relayRealmEvent(realmURL: string, event: RealmEventContent) { + relayRealmEvent(event: RealmEventContent) { + const realmURL = event.realmURL; + if (!realmURL) { + return; + } this.listenerCallbacks.get(realmURL)?.forEach((cb) => { cb(event); }); diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 43be7607f88..71cdaa91a18 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -127,8 +127,13 @@ export class TestRealmAdapter implements RealmAdapter { rid.replace('test-session-room-realm-', '').startsWith(realmUrl), ); + const eventWithRealmURL: RealmEventContent = { + ...event, + realmURL: realmUrl, + }; + for (let roomId of targetRoomIds) { - simulateRemoteMessage(roomId, realmMatrixUsername, event, { + simulateRemoteMessage(roomId, realmMatrixUsername, eventWithRealmURL, { type: APP_BOXEL_REALM_EVENT_TYPE, }); } diff --git a/packages/host/tests/integration/message-service-subscription-test.gts b/packages/host/tests/integration/message-service-subscription-test.gts index c5879533ff8..7d60c7783cf 100644 --- a/packages/host/tests/integration/message-service-subscription-test.gts +++ b/packages/host/tests/integration/message-service-subscription-test.gts @@ -107,6 +107,7 @@ module('Integration | message service subscription', function (hooks) { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: 'index.json', + realmURL: testRealmURL, }, }); diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index 3e9ea5d712b..868ad28429a 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -234,6 +234,10 @@ export class NodeAdapter implements RealmAdapter { dbAdapter: DBAdapter, ): Promise { realmEventsLog.debug('Broadcasting realm event', event); + const eventWithRealmURL: RealmEventContent = { + ...event, + realmURL: realmUrl, + }; let realmUserId; if (dbAdapter.isClosed) { realmEventsLog.warn( @@ -268,7 +272,11 @@ export class NodeAdapter implements RealmAdapter { for (let userId of Object.keys(dmRooms)) { let roomId = dmRooms[userId]; try { - await matrixClient.sendEvent(roomId, APP_BOXEL_REALM_EVENT_TYPE, event); + await matrixClient.sendEvent( + roomId, + APP_BOXEL_REALM_EVENT_TYPE, + eventWithRealmURL, + ); } catch (e) { realmEventsLog.error( `Unable to send event in room ${roomId} for user ${userId}`, diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index 7a8b62b4fcc..d8b67962a77 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -882,6 +882,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${testRealmURL}test-card.gts`, + realmURL: testRealmURL, }, }, { @@ -891,6 +892,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [`${testRealmURL}test-card.gts`], clientRequestId: null, + realmURL: testRealmURL, }, }, { @@ -899,6 +901,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${testRealmURL}test-card.gts`, + realmURL: testRealmURL, }, }, { @@ -908,6 +911,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [`${testRealmURL}test-card.gts`, id], clientRequestId: null, + realmURL: testRealmURL, }, }, { @@ -916,6 +920,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${id}.json`, + realmURL: testRealmURL, }, }, { @@ -925,6 +930,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [id], clientRequestId: null, + realmURL: testRealmURL, }, }, ]; diff --git a/packages/realm-server/tests/helpers/indexing.ts b/packages/realm-server/tests/helpers/indexing.ts index 5c8d5f36a3c..0445a452507 100644 --- a/packages/realm-server/tests/helpers/indexing.ts +++ b/packages/realm-server/tests/helpers/indexing.ts @@ -84,12 +84,14 @@ export async function expectIncrementalIndexEvent( eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: targetUrl, + realmURL: realm, }); let expectedIncrementalContent: any = { eventName: 'index', indexType: 'incremental', invalidations: [invalidation], + realmURL: realm, }; let actualContent = { ...incrementalEventContent }; diff --git a/packages/realm-server/tests/realm-endpoints-test.ts b/packages/realm-server/tests/realm-endpoints-test.ts index 30c2a52bc6c..bb2da70171d 100644 --- a/packages/realm-server/tests/realm-endpoints-test.ts +++ b/packages/realm-server/tests/realm-endpoints-test.ts @@ -937,6 +937,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${newCardId}.json`, + realmURL: testRealmHref, }); assert.deepEqual(incrementalEvent?.content, { @@ -944,6 +945,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [newCardId], clientRequestId: null, + realmURL: testRealmHref, }); { @@ -1101,12 +1103,14 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${testRealmHref}person-1.json`, + realmURL: testRealmHref, }); assert.deepEqual(incrementalEvent?.content, { eventName: 'index', indexType: 'incremental', invalidations: [`${testRealmHref}person-1`], + realmURL: testRealmHref, }); { From 7bc0935d60d16673fd06f14881f308975b4befad Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 27 Jan 2026 13:24:41 +0000 Subject: [PATCH 04/48] Remove username from publishing realm --- .../handlers/handle-publish-realm.ts | 21 +------------------ packages/realm-server/routes.ts | 1 - packages/realm-server/server.ts | 7 +------ 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 7e452568edd..c1dfe377f25 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -28,8 +28,6 @@ import { import { createJWT } from '../jwt'; import type { CreateRoutesArgs } from '../routes'; import type { RealmServerTokenClaim } from '../utils/jwt'; -import { registerUser } from '../synapse'; -import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client'; const log = logger('handle-publish'); @@ -99,13 +97,11 @@ function rewriteHostHomeForPublishedRealm( export default function handlePublishRealm({ dbAdapter, - matrixClient, realmSecretSeed, serverURL, virtualNetwork, realms, realmsRootPath, - getMatrixRegistrationSecret, createAndMountRealm, domainsForPublishedRealms, }: CreateRoutesArgs): (ctxt: Koa.Context, next: Koa.Next) => Promise { @@ -246,7 +242,6 @@ export default function handlePublishRealm({ ); let userId; - let realmUsername; let publishedRealmData: PublishedRealmTable | undefined; if (existingPublishedRealm) { let results = (await query(dbAdapter, [ @@ -261,7 +256,6 @@ export default function handlePublishRealm({ | 'last_published_at' >[]; publishedRealmData = results[0]; - realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmData.id}`; let lastPublishedAt = Date.now().toString(); await query(dbAdapter, [ @@ -273,10 +267,9 @@ export default function handlePublishRealm({ publishedRealmData.last_published_at = lastPublishedAt; } else { let publishedRealmId = uuidv4(); - realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmId}`; let { valueExpressions, nameExpressions } = asExpressions({ id: publishedRealmId, - owner_username: realmUsername, + owner_username: 'NONE', source_realm_url: sourceRealmURL, published_realm_url: publishedRealmURL, last_published_at: Date.now().toString(), @@ -294,18 +287,7 @@ export default function handlePublishRealm({ | 'last_published_at' >[]; publishedRealmData = results[0]; - - let { userId: newUserId } = await registerUser({ - matrixURL: matrixClient.matrixURL, - displayname: realmUsername, - username: realmUsername, - password: await passwordFromSeed(realmUsername, realmSecretSeed), - registrationSecret: await getMatrixRegistrationSecret(), - }); - userId = newUserId; - await insertPermissions(dbAdapter, new URL(publishedRealmURL), { - [userId]: ['read', 'realm-owner'], [ownerUserId]: ['read', 'realm-owner'], '*': ['read'], }); @@ -350,7 +332,6 @@ export default function handlePublishRealm({ let realm = createAndMountRealm( publishedRealmPath, publishedRealmURL, - realmUsername, new URL(sourceRealmURL), false, ); diff --git a/packages/realm-server/routes.ts b/packages/realm-server/routes.ts index 4fc5962172f..6e4bdd449b6 100644 --- a/packages/realm-server/routes.ts +++ b/packages/realm-server/routes.ts @@ -59,7 +59,6 @@ export type CreateRoutesArgs = { createAndMountRealm: ( path: string, url: string, - username: string, copiedFromRealm?: URL, enableFileWatcher?: boolean, fromScratchIndexPriority?: number, diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index 9a7ae4bba74..cb004d2feb2 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -936,7 +936,6 @@ export class RealmServer { } let adapter = new NodeAdapter(realmPath, this.enableFileWatcher); - let username = publishedRealmRow.owner_username; let realm = new Realm({ url: publishedRealmUrl, @@ -945,11 +944,7 @@ export class RealmServer { virtualNetwork: this.virtualNetwork, dbAdapter: this.dbAdapter, queue: this.queue, - matrix: { - url: this.matrixClient.matrixURL, - username, - }, - realmServerMatrixClient: this.matrixClient, + matrixClient: this.matrixClient, realmServerURL: this.serverURL.href, definitionLookup: this.definitionLookup, cardSizeLimitBytes: this.cardSizeLimitBytes, From 7cd147b2c3d8bcfd66dfcf088b7ade694522c2bf Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 27 Jan 2026 14:52:32 +0000 Subject: [PATCH 05/48] Remove console logging --- packages/host/app/services/matrix-service.ts | 1 - packages/realm-server/handlers/handle-create-session.ts | 3 --- packages/realm-server/handlers/handle-realm-auth.ts | 6 ------ packages/realm-server/node-realm.ts | 1 - .../runtime-common/db-queries/session-room-queries.ts | 8 -------- packages/runtime-common/realm.ts | 7 ------- 6 files changed, 26 deletions(-) diff --git a/packages/host/app/services/matrix-service.ts b/packages/host/app/services/matrix-service.ts index 8fab7d5a2d4..93eaf840ae0 100644 --- a/packages/host/app/services/matrix-service.ts +++ b/packages/host/app/services/matrix-service.ts @@ -1828,7 +1828,6 @@ export default class MatrixService extends Service { event.type === 'm.room.message' && event.content?.msgtype === APP_BOXEL_REALM_SERVER_EVENT_MSGTYPE ) { - console.log('Received realm server event', event); await this.realmServer.handleEvent(event); } else if ( event.type === APP_BOXEL_REALM_EVENT_TYPE && diff --git a/packages/realm-server/handlers/handle-create-session.ts b/packages/realm-server/handlers/handle-create-session.ts index b95efe051bd..1fb6b147060 100644 --- a/packages/realm-server/handlers/handle-create-session.ts +++ b/packages/realm-server/handlers/handle-create-session.ts @@ -47,16 +47,13 @@ export default function handleCreateSessionRequest({ 'Realm server Matrix user ID is not available, unable to create session room', ); } - console.log('Realm server user ID:', realmServerUserId); let sessionRoom = await fetchSessionRoom( dbAdapter, realmServerUserId, userId, ); - console.log('Fetched session room from DB:', sessionRoom); if (!sessionRoom) { - console.log('No session room???', userId); sessionRoom = await matrixClient.createDM(userId); await upsertSessionRoom( dbAdapter, diff --git a/packages/realm-server/handlers/handle-realm-auth.ts b/packages/realm-server/handlers/handle-realm-auth.ts index 369199e9423..5b67734bbb0 100644 --- a/packages/realm-server/handlers/handle-realm-auth.ts +++ b/packages/realm-server/handlers/handle-realm-auth.ts @@ -51,12 +51,6 @@ export default function handleRealmAuth({ } try { - console.log( - 'Realm auth creating session for realm:', - realmUrl, - 'and user:', - matrixUserId, - ); let sessionRoom = await realm.ensureSessionRoom(matrixUserId); sessions[realmUrl] = createJWT( { diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index 6de2f6b2ec3..3196b893b3d 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -269,7 +269,6 @@ export class NodeAdapter implements RealmAdapter { realmUrl, realmUserId, ); - console.log('Dm rooms for realm: ', realmUrl, dmRooms); realmEventsLog.debug('Sending to dm rooms', Object.values(dmRooms)); diff --git a/packages/runtime-common/db-queries/session-room-queries.ts b/packages/runtime-common/db-queries/session-room-queries.ts index c92fd6211ab..b49fc644a9b 100644 --- a/packages/runtime-common/db-queries/session-room-queries.ts +++ b/packages/runtime-common/db-queries/session-room-queries.ts @@ -70,12 +70,6 @@ export async function fetchAllSessionRooms( realmURL: string, realmUserId: string, ) { - console.log( - 'Fetching all session rooms for realmURL:', - realmURL, - 'and realmUserId:', - realmUserId, - ); let rows = await query(dbAdapter, [ 'SELECT sr.matrix_user_id, sr.room_id', 'FROM session_rooms sr', @@ -90,8 +84,6 @@ export async function fetchAllSessionRooms( param(REALM_SERVER_REALM), ]); - console.log('Fetched session rooms:', rows); - let result: Record = {}; for (let row of rows) { if (row.matrix_user_id && row.room_id) { diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 5c9792a29eb..664ee9223b1 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -671,21 +671,14 @@ export class Realm { } async ensureSessionRoom(matrixUserId: string): Promise { - console.log('realm.ts - Ensuring session room for user:', matrixUserId); let sessionRoom = await fetchSessionRoom( this.#dbAdapter, this.#matrixClient.getUserId(), matrixUserId, ); - console.log('Fetched session room from DB:', sessionRoom); if (!sessionRoom) { - console.log('No session room, creating one for user:', matrixUserId); await this.#matrixClient.login(); - console.log( - 'Logged into matrix as realm server user', - this.#matrixClient.getUserId(), - ); sessionRoom = await this.#matrixClient.createDM(matrixUserId); await upsertSessionRoom( this.#dbAdapter, From 02f9b25a31c6a0895208ec751cfc68a72633b331 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 4 Feb 2026 13:43:28 +0000 Subject: [PATCH 06/48] Pass through matrix client in tests setup too --- packages/host/tests/helpers/index.gts | 6 +----- packages/realm-server/tests/helpers/index.ts | 5 ++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index a5a56aec045..7d5d3dce742 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -787,15 +787,11 @@ async function setupTestRealm({ realm = new Realm({ url: realmURL, adapter, - matrix: { - ...baseTestMatrix, - username: testRealmURLToUsername(realmURL), - }, secretSeed: testRealmSecretSeed, virtualNetwork, dbAdapter, queue, - realmServerMatrixClient: new MatrixClient({ + matrixClient: new MatrixClient({ matrixURL: baseTestMatrix.url, username: testRealmServerMatrixUsername, seed: testRealmSecretSeed, diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index a5efc5dba8a..b50703e8cfd 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -501,7 +501,7 @@ export async function createRealm({ createPrerenderAuth: testCreatePrerenderAuth, }); } - let realmServerMatrixClient = new MatrixClient({ + let matrixClient = new MatrixClient({ matrixURL: realmServerTestMatrix.url, username: realmServerTestMatrix.username, seed: realmSecretSeed, @@ -509,12 +509,11 @@ export async function createRealm({ let realm = new Realm({ url: realmURL, adapter, - matrix: matrixConfig, secretSeed: realmSecretSeed, virtualNetwork, dbAdapter, queue: publisher, - realmServerMatrixClient, + matrixClient, realmServerURL: new URL(new URL(realmURL).origin).href, definitionLookup, cardSizeLimitBytes: From 0d138a1e2384b9d0ec8d7cae4b81b9901097c843 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 9 Feb 2026 15:07:32 +0000 Subject: [PATCH 07/48] Update scheme and move migration to be the last --- .../{1769504850011_schema.sql => 1770648743000_schema.sql} | 7 +++++++ ...=> 1770648743000_add-realm-user-id-to-session-rooms.js} | 0 2 files changed, 7 insertions(+) rename packages/host/config/schema/{1769504850011_schema.sql => 1770648743000_schema.sql} (94%) rename packages/postgres/migrations/{1766509131000_add-realm-user-id-to-session-rooms.js => 1770648743000_add-realm-user-id-to-session-rooms.js} (100%) diff --git a/packages/host/config/schema/1769504850011_schema.sql b/packages/host/config/schema/1770648743000_schema.sql similarity index 94% rename from packages/host/config/schema/1769504850011_schema.sql rename to packages/host/config/schema/1770648743000_schema.sql index 56d3fa5dc79..7fd8ff7367f 100644 --- a/packages/host/config/schema/1769504850011_schema.sql +++ b/packages/host/config/schema/1770648743000_schema.sql @@ -1,6 +1,13 @@ -- This is auto-generated by packages/realm-server/scripts/convert-to-sqlite.ts -- Please don't directly modify this file + CREATE TABLE IF NOT EXISTS bot_registrations ( + id NOT NULL, + username TEXT NOT NULL, + created_at NOT NULL, + PRIMARY KEY ( id ) +); + CREATE TABLE IF NOT EXISTS boxel_index ( url TEXT NOT NULL, file_alias TEXT NOT NULL, diff --git a/packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js b/packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js similarity index 100% rename from packages/postgres/migrations/1766509131000_add-realm-user-id-to-session-rooms.js rename to packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js From 2854b71aa5dbaffa7146c3f7e5a869c5188300be Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 9 Feb 2026 15:55:48 +0000 Subject: [PATCH 08/48] Explicitly expect two files to be attached --- packages/matrix/tests/messages.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/matrix/tests/messages.spec.ts b/packages/matrix/tests/messages.spec.ts index 84ca57e62fa..87a69cc655d 100644 --- a/packages/matrix/tests/messages.spec.ts +++ b/packages/matrix/tests/messages.spec.ts @@ -359,7 +359,7 @@ test.describe('Room messages', () => { await expect( page.locator(`[data-test-attached-card="${appURL}/hassan"]`), ).toHaveCount(1); - await expect(page.locator(`[data-test-attached-file]`)).toHaveCount(1); + await expect(page.locator(`[data-test-attached-file]`)).toHaveCount(2); await expect( page.locator(`[data-test-attached-file="${appURL}/person.gts"]`), ).toHaveCount(1); From cfbbae535a22765299d2068f007bbb04429c286c Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 9 Feb 2026 16:55:25 +0000 Subject: [PATCH 09/48] Don't auto-login to realm --- packages/realm-server/main.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/realm-server/main.ts b/packages/realm-server/main.ts index 3657b981a9f..2e0b2744f77 100644 --- a/packages/realm-server/main.ts +++ b/packages/realm-server/main.ts @@ -241,7 +241,6 @@ const getIndexHTML = async () => { username: REALM_SERVER_MATRIX_USERNAME, seed: REALM_SECRET_SEED, }); - await matrixClient.login(); let prerenderer = createRemotePrerenderer(prerendererUrl); let createPrerenderAuth = buildCreatePrerenderAuth( REALM_SECRET_SEED, From 10aaba682ce14c198dfde0186c125ee2846fca07 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 10 Feb 2026 11:48:23 +0000 Subject: [PATCH 10/48] Add the hard coded realm user to have read permissions --- packages/matrix/helpers/index.ts | 5 +++++ .../tests/card-dependencies-endpoint-test.ts | 1 + .../realm-server/tests/card-source-endpoints-test.ts | 4 ++++ packages/realm-server/tests/helpers/index.ts | 10 ++-------- .../tests/realm-endpoints/directory-test.ts | 1 + .../realm-server/tests/realm-endpoints/info-test.ts | 3 +++ .../realm-server/tests/realm-endpoints/lint-test.ts | 1 + .../realm-server/tests/realm-endpoints/mtimes-test.ts | 1 + .../tests/realm-endpoints/permissions-test.ts | 1 + .../realm-server/tests/realm-endpoints/search-test.ts | 2 ++ .../realm-server/tests/realm-endpoints/user-test.ts | 2 ++ packages/realm-server/tests/search-prerendered-test.ts | 1 + .../realm-server/tests/server-endpoints/helpers.ts | 1 + 13 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/matrix/helpers/index.ts b/packages/matrix/helpers/index.ts index e4ab50f641b..cc9a5e0ddce 100644 --- a/packages/matrix/helpers/index.ts +++ b/packages/matrix/helpers/index.ts @@ -120,6 +120,11 @@ export async function setRealmRedirects(page: Page) { } export async function registerRealmUsers(synapse: SynapseInstance) { + await registerUser( + synapse, + 'node-test_realm', + await realmPassword('node-test_realm', realmSecretSeed), + ); await registerUser( synapse, 'realm_server', diff --git a/packages/realm-server/tests/card-dependencies-endpoint-test.ts b/packages/realm-server/tests/card-dependencies-endpoint-test.ts index 8650a5fcc58..67472566f3f 100644 --- a/packages/realm-server/tests/card-dependencies-endpoint-test.ts +++ b/packages/realm-server/tests/card-dependencies-endpoint-test.ts @@ -90,6 +90,7 @@ module(basename(__filename), function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index 74250befae4..f7d18f29295 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -353,6 +353,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -547,6 +548,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -1022,6 +1024,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -1214,6 +1217,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 7e73225f59b..34ddf564e19 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -449,7 +449,6 @@ export async function createRealm({ runner, publisher, dbAdapter, - matrixConfig = testMatrix, withWorker, enableFileWatcher = false, cardSizeLimitBytes, @@ -494,7 +493,7 @@ export async function createRealm({ dbAdapter, queuePublisher: publisher, virtualNetwork, - matrixURL: matrixConfig.url, + matrixURL: realmServerTestMatrix.url, secretSeed: realmSecretSeed, realmServerMatrixUsername: testRealmServerMatrixUsername, prerenderer, @@ -792,7 +791,6 @@ export function setupPermissionedRealms( // We want 2 different realm users to test authorization between them - these // names are selected because they are already available in the test // environment (via register-realm-users.ts) - let matrixUsers = ['test_realm', 'node-test_realm']; let realms: { realm: Realm; realmPath: string; @@ -807,7 +805,7 @@ export function setupPermissionedRealms( runner: QueueRunner, ) => { _dbAdapter = dbAdapter; - for (let [i, realmArg] of realmsArg.entries()) { + for (let realmArg of realmsArg.values()) { let { testRealmDir: realmPath, testRealm: realm, @@ -821,10 +819,6 @@ export function setupPermissionedRealms( fileSystem: realmArg.fileSystem, permissions: realmArg.permissions, matrixURL, - matrixConfig: { - url: matrixURL, - username: matrixUsers[i] ?? matrixUsers[0], - }, dbAdapter, publisher, runner, diff --git a/packages/realm-server/tests/realm-endpoints/directory-test.ts b/packages/realm-server/tests/realm-endpoints/directory-test.ts index 5c146758bc7..6782d6a3411 100644 --- a/packages/realm-server/tests/realm-endpoints/directory-test.ts +++ b/packages/realm-server/tests/realm-endpoints/directory-test.ts @@ -100,6 +100,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/info-test.ts b/packages/realm-server/tests/realm-endpoints/info-test.ts index 94fffd24a75..d1d59c5171b 100644 --- a/packages/realm-server/tests/realm-endpoints/info-test.ts +++ b/packages/realm-server/tests/realm-endpoints/info-test.ts @@ -93,6 +93,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, realmURL, onRealmSetup, @@ -166,6 +167,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { users: ['read'], + '@node-test_realm:localhost': ['read'], }, realmURL, onRealmSetup, @@ -209,6 +211,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { bob: ['read'], jane: ['read'], john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, realmURL, onRealmSetup, diff --git a/packages/realm-server/tests/realm-endpoints/lint-test.ts b/packages/realm-server/tests/realm-endpoints/lint-test.ts index f7e42bbefda..b5700c13f5e 100644 --- a/packages/realm-server/tests/realm-endpoints/lint-test.ts +++ b/packages/realm-server/tests/realm-endpoints/lint-test.ts @@ -28,6 +28,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/mtimes-test.ts b/packages/realm-server/tests/realm-endpoints/mtimes-test.ts index 0ef403c5a07..ba09a520d4d 100644 --- a/packages/realm-server/tests/realm-endpoints/mtimes-test.ts +++ b/packages/realm-server/tests/realm-endpoints/mtimes-test.ts @@ -30,6 +30,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { mary: ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/permissions-test.ts b/packages/realm-server/tests/realm-endpoints/permissions-test.ts index eac68d6d56c..f194821479c 100644 --- a/packages/realm-server/tests/realm-endpoints/permissions-test.ts +++ b/packages/realm-server/tests/realm-endpoints/permissions-test.ts @@ -43,6 +43,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { permissions: { mary: ['read', 'write', 'realm-owner'], bob: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/search-test.ts b/packages/realm-server/tests/realm-endpoints/search-test.ts index 3f58562f66b..9b27a3610c5 100644 --- a/packages/realm-server/tests/realm-endpoints/search-test.ts +++ b/packages/realm-server/tests/realm-endpoints/search-test.ts @@ -351,6 +351,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], + '@node-test_realm:localhost': ['read'], }, realmURL: new URL('http://127.0.0.1:4444/test/'), onRealmSetup, @@ -407,6 +408,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, realmURL: new URL('http://127.0.0.1:4444/test/'), onRealmSetup, diff --git a/packages/realm-server/tests/realm-endpoints/user-test.ts b/packages/realm-server/tests/realm-endpoints/user-test.ts index 066d7a2d768..35de5d41a05 100644 --- a/packages/realm-server/tests/realm-endpoints/user-test.ts +++ b/packages/realm-server/tests/realm-endpoints/user-test.ts @@ -66,6 +66,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -475,6 +476,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/search-prerendered-test.ts b/packages/realm-server/tests/search-prerendered-test.ts index b0881e80994..9777aa58082 100644 --- a/packages/realm-server/tests/search-prerendered-test.ts +++ b/packages/realm-server/tests/search-prerendered-test.ts @@ -978,6 +978,7 @@ module(basename(__filename), function () { realmURL, permissions: { john: ['read'], + '@node-test_realm:localhost': ['read'], }, fileSystem: { 'person.gts': ` diff --git a/packages/realm-server/tests/server-endpoints/helpers.ts b/packages/realm-server/tests/server-endpoints/helpers.ts index 832ddfbd02c..060d5b63c0a 100644 --- a/packages/realm-server/tests/server-endpoints/helpers.ts +++ b/packages/realm-server/tests/server-endpoints/helpers.ts @@ -73,6 +73,7 @@ export function setupServerEndpointsTest( setupPermissionedRealm(hooks, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); From 07404308050d2838c0d14cc1b4ac0db964b380b8 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 10 Feb 2026 15:36:30 +0000 Subject: [PATCH 11/48] Session rooms are created automatically, do not create them in tests --- packages/realm-server/tests/helpers/index.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 34ddf564e19..95767dab5e4 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -1040,13 +1040,6 @@ export function setupMatrixRoom( } testAuthRoomId = payload.sessionRoom; - - await upsertSessionRoom( - realmSetup.dbAdapter, - realmSetup.testRealm.url, - userId, - payload.sessionRoom, - ); }); return { From 01b7c9f0f32ffe1a70169c44ed070e2e2c34f107 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 10 Feb 2026 16:25:50 +0000 Subject: [PATCH 12/48] Update permissions in tests --- packages/realm-server/tests/card-source-endpoints-test.ts | 1 + packages/realm-server/tests/file-watcher-events-test.ts | 4 ++++ packages/realm-server/tests/helpers/index.ts | 1 - .../tests/server-endpoints/realm-lifecycle-test.ts | 5 ----- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index f7d18f29295..dc76947eb47 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -1078,6 +1078,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/file-watcher-events-test.ts b/packages/realm-server/tests/file-watcher-events-test.ts index 5057b1b6aeb..7ea7583510c 100644 --- a/packages/realm-server/tests/file-watcher-events-test.ts +++ b/packages/realm-server/tests/file-watcher-events-test.ts @@ -59,6 +59,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, subscribeToRealmEvents: true, onRealmSetup, @@ -186,6 +187,7 @@ module(basename(__filename), function () { assert.deepEqual(updateEvent.content, { eventName: 'update', added: basename(newFilePath), + realmURL: realmURL.href, }); }); @@ -221,6 +223,7 @@ module(basename(__filename), function () { assert.deepEqual(updateEvent.content, { eventName: 'update', updated: basename(updatedFilePath), + realmURL: realmURL.href, }); }); @@ -244,6 +247,7 @@ module(basename(__filename), function () { assert.deepEqual(updateEvent.content, { eventName: 'update', removed: basename(deletedFilePath), + realmURL: realmURL.href, }); }); diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 95767dab5e4..e709d67c4c5 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -34,7 +34,6 @@ import { PUBLISHED_DIRECTORY_NAME, DEFAULT_CARD_SIZE_LIMIT_BYTES, clearSessionRooms, - upsertSessionRoom, type MatrixConfig, type QueuePublisher, type QueueRunner, diff --git a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts index 1a964718e1e..cfc49cc1e58 100644 --- a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts +++ b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts @@ -116,11 +116,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { new URL(json.data.id), ); assert.deepEqual(permissions, { - [`@realm/mango_${endpoint}:localhost`]: [ - 'read', - 'write', - 'realm-owner', - ], [ownerUserId]: ['read', 'write', 'realm-owner'], }); From 6a2a5bd566f52dcb0d513eff3f31011a88ab6100 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 10 Feb 2026 16:37:51 +0000 Subject: [PATCH 13/48] Use the realm user id to get the session rooms for sending events --- packages/realm-server/server.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index 11daea212b1..2b37d53bc24 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -1006,11 +1006,11 @@ export class RealmServer { eventType: string, data?: Record, ) => { - let roomId = await fetchSessionRoom( - this.dbAdapter, - REALM_SERVER_REALM, - user, - ); + if (!this.matrixClient.isLoggedIn()) { + await this.matrixClient.login(); + } + let realmUserId = this.matrixClient.getUserId()!; + let roomId = await fetchSessionRoom(this.dbAdapter, realmUserId, user); if (!roomId) { console.error( `Failed to send event: ${eventType}, cannot find session room for user: ${user}`, From e811ac5e4da0223d65e4b3a7438294f832ebbdd9 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 10 Feb 2026 20:33:09 +0000 Subject: [PATCH 14/48] Info overwriting removed, correct realm url --- .../realm-server/tests/card-endpoints-test.ts | 76 ++++++------------- .../tests/card-source-endpoints-test.ts | 18 +++-- packages/realm-server/tests/helpers/index.ts | 2 +- packages/realm-server/tests/indexing-test.ts | 1 + .../realm-server/tests/realm-auth-test.ts | 6 +- .../tests/realm-endpoints-test.ts | 9 +-- .../tests/realm-endpoints/info-test.ts | 4 - .../server-endpoints/realm-lifecycle-test.ts | 3 +- .../server-endpoints/user-and-catalog-test.ts | 1 - .../db-queries/session-room-queries.ts | 2 + 10 files changed, 48 insertions(+), 74 deletions(-) diff --git a/packages/realm-server/tests/card-endpoints-test.ts b/packages/realm-server/tests/card-endpoints-test.ts index 169320be2d7..2a3e7c26fe2 100644 --- a/packages/realm-server/tests/card-endpoints-test.ts +++ b/packages/realm-server/tests/card-endpoints-test.ts @@ -87,6 +87,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -138,11 +139,7 @@ module(basename(__filename), function () { module: `./person`, name: 'Person', }, - // FIXME see elsewhere… global fix? - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -538,6 +535,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, published: true, @@ -587,10 +585,7 @@ module(basename(__filename), function () { module: `./person`, name: 'Person', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, relationships: { @@ -613,6 +608,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -793,6 +789,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -1160,10 +1157,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -1350,10 +1344,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -1476,10 +1467,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo realmURL: testRealmHref, }, links: { @@ -1531,10 +1519,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo realmURL: testRealmHref, }, links: { @@ -1748,10 +1733,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -1844,6 +1826,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -2432,10 +2415,7 @@ module(basename(__filename), function () { name: 'Friend', module: './friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -2622,10 +2602,7 @@ module(basename(__filename), function () { name: 'Friend', module: '../friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -2748,10 +2725,7 @@ module(basename(__filename), function () { name: 'Friend', module: '../friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo realmURL: testRealmHref, }, links: { @@ -2803,10 +2777,7 @@ module(basename(__filename), function () { name: 'Friend', module: '../friend', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo realmURL: testRealmHref, }, links: { @@ -3008,10 +2979,7 @@ module(basename(__filename), function () { module: 'http://localhost:4202/node-test/friend-with-used-link', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -3106,10 +3074,7 @@ module(basename(__filename), function () { module: 'http://localhost:4202/node-test/friend-with-used-link', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -3264,6 +3229,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, cardSizeLimitBytes: 512, onRealmSetup, @@ -3382,6 +3348,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -3534,6 +3501,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, fileSystem: { 'greeting.txt': 'hello', @@ -3600,6 +3568,7 @@ module(basename(__filename), function () { realmURL: providerRealmURL, permissions: { '*': ['read', 'write', 'realm-owner'], + '@node-test_realm:localhost': ['read'], }, fileSystem: { 'person.gts': ` @@ -3629,6 +3598,7 @@ module(basename(__filename), function () { realmURL: consumerRealmURL, permissions: { '*': ['read', 'write', 'realm-owner'], + '@node-test_realm:localhost': ['read'], }, fileSystem: { 'favorite-finder.gts': ` diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index dc76947eb47..2b8b3519797 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -73,6 +73,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -403,6 +404,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -476,6 +478,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -590,6 +593,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup, }); @@ -920,7 +924,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${testRealmURL}test-card.gts`, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, { @@ -930,7 +934,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [`${testRealmURL}test-card.gts`], clientRequestId: null, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, { @@ -939,7 +943,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${testRealmURL}test-card.gts`, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, { @@ -949,7 +953,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [`${testRealmURL}test-card.gts`, id], clientRequestId: null, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, { @@ -958,7 +962,7 @@ module(basename(__filename), function () { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile: `${id}.json`, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, { @@ -968,7 +972,7 @@ module(basename(__filename), function () { indexType: 'incremental', invalidations: [id], clientRequestId: null, - realmURL: testRealmURL, + realmURL: testRealmURL.href, }, }, ]; @@ -990,6 +994,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, cardSizeLimitBytes: 512, onRealmSetup, @@ -1192,6 +1197,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, cardSizeLimitBytes: 512, onRealmSetup, diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index e709d67c4c5..afb80a174f6 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -160,7 +160,7 @@ export const testRealmInfo = { interactHome: null, hostHome: null, visibility: 'public', - realmUserId: testMatrix.username, + realmUserId: testRealmServerMatrixUserId, publishable: null, lastPublishedAt: null, }; diff --git a/packages/realm-server/tests/indexing-test.ts b/packages/realm-server/tests/indexing-test.ts index 5a8a485620c..6c6b7ff5ee9 100644 --- a/packages/realm-server/tests/indexing-test.ts +++ b/packages/realm-server/tests/indexing-test.ts @@ -2051,6 +2051,7 @@ module(basename(__filename), function () { }, consumer: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, }); diff --git a/packages/realm-server/tests/realm-auth-test.ts b/packages/realm-server/tests/realm-auth-test.ts index 94a6629558d..e3cea761222 100644 --- a/packages/realm-server/tests/realm-auth-test.ts +++ b/packages/realm-server/tests/realm-auth-test.ts @@ -12,6 +12,7 @@ import { insertUser, realmSecretSeed, testRealmHref, + testRealmServerMatrixUserId, } from './helpers'; import { createJWT as createRealmServerJWT } from '../utils/jwt'; @@ -25,6 +26,7 @@ module(basename(__filename), function () { permissions: { '*': ['read'], [matrixUserId]: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, onRealmSetup: ({ dbAdapter: adapter, request: req }) => { dbAdapter = adapter; @@ -53,7 +55,7 @@ module(basename(__filename), function () { let existingRoom = await fetchSessionRoom( dbAdapter, - testRealmHref, + testRealmServerMatrixUserId, matrixUserId, ); assert.strictEqual( @@ -88,7 +90,7 @@ module(basename(__filename), function () { let sessionRoom = await fetchSessionRoom( dbAdapter, - testRealmHref, + testRealmServerMatrixUserId, matrixUserId, ); assert.strictEqual( diff --git a/packages/realm-server/tests/realm-endpoints-test.ts b/packages/realm-server/tests/realm-endpoints-test.ts index bbe372964fc..1aaf3f0f13e 100644 --- a/packages/realm-server/tests/realm-endpoints-test.ts +++ b/packages/realm-server/tests/realm-endpoints-test.ts @@ -113,6 +113,7 @@ module(basename(__filename), function () { '*': ['read', 'write'], user: ['read', 'write', 'realm-owner'], carol: ['read', 'write'], + '@node-test_realm:localhost': ['read'], }, realmURL, onRealmSetup, @@ -337,7 +338,6 @@ module(basename(__filename), function () { type: 'realm-config', attributes: { ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', backgroundURL: 'new-bg', }, }, @@ -934,7 +934,7 @@ module(basename(__filename), function () { assert.strictEqual(response.status, 200, 'HTTP 200 status'); }); - test('can index a newly added file', async function (assert) { + test.only('can index a newly added file', async function (assert) { let realmEventTimestampStart = Date.now(); let postResponse = await request @@ -1034,10 +1034,7 @@ module(basename(__filename), function () { module: '../person', name: 'Person', }, - realmInfo: { - ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', - }, + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { diff --git a/packages/realm-server/tests/realm-endpoints/info-test.ts b/packages/realm-server/tests/realm-endpoints/info-test.ts index d1d59c5171b..d77aed49d33 100644 --- a/packages/realm-server/tests/realm-endpoints/info-test.ts +++ b/packages/realm-server/tests/realm-endpoints/info-test.ts @@ -80,7 +80,6 @@ module(`realm-endpoints/${basename(__filename)}`, function () { type: 'realm-info', attributes: { ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', }, }, }, @@ -152,7 +151,6 @@ module(`realm-endpoints/${basename(__filename)}`, function () { attributes: { ...testRealmInfo, visibility: 'private', - realmUserId: '@node-test_realm:localhost', }, }, }, @@ -195,7 +193,6 @@ module(`realm-endpoints/${basename(__filename)}`, function () { attributes: { ...testRealmInfo, visibility: 'shared', - realmUserId: '@node-test_realm:localhost', }, }, }, @@ -239,7 +236,6 @@ module(`realm-endpoints/${basename(__filename)}`, function () { attributes: { ...testRealmInfo, visibility: 'shared', - realmUserId: '@node-test_realm:localhost', }, }, }, diff --git a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts index cfc49cc1e58..00359115136 100644 --- a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts +++ b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts @@ -17,6 +17,7 @@ import { createJWT, realmSecretSeed, testRealmInfo, + testRealmServerMatrixUserId, } from '../helpers'; import { createJWT as createRealmServerJWT } from '../../utils/jwt'; import { setupServerEndpointsTest, testRealm2URL } from './helpers'; @@ -121,7 +122,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { let sessionRoom = await fetchSessionRoom( context.dbAdapter, - json.data.id, + testRealmServerMatrixUserId, ownerUserId, ); assert.ok( diff --git a/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts b/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts index 1aebb19061a..ab0062d4265 100644 --- a/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts +++ b/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts @@ -85,7 +85,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { id: `${testRealm2URL}`, attributes: { ...testRealmInfo, - realmUserId: '@node-test_realm:localhost', }, }, ], diff --git a/packages/runtime-common/db-queries/session-room-queries.ts b/packages/runtime-common/db-queries/session-room-queries.ts index b49fc644a9b..091cac47776 100644 --- a/packages/runtime-common/db-queries/session-room-queries.ts +++ b/packages/runtime-common/db-queries/session-room-queries.ts @@ -14,6 +14,8 @@ export async function fetchSessionRoom( let rows = await query(dbAdapter, [ 'SELECT room_id FROM session_rooms WHERE realm_user_id =', param(realmUserId), + 'AND realm_url = ', + param(REALM_SERVER_REALM), 'AND matrix_user_id =', param(matrixUserId), ]); From cc60f93ce79110e73bdbedbd610c7a5295f65c22 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 11:56:05 +0000 Subject: [PATCH 15/48] Remove accidental test.only --- packages/realm-server/tests/realm-endpoints-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/realm-server/tests/realm-endpoints-test.ts b/packages/realm-server/tests/realm-endpoints-test.ts index 1aaf3f0f13e..c1e33c02bb9 100644 --- a/packages/realm-server/tests/realm-endpoints-test.ts +++ b/packages/realm-server/tests/realm-endpoints-test.ts @@ -934,7 +934,7 @@ module(basename(__filename), function () { assert.strictEqual(response.status, 200, 'HTTP 200 status'); }); - test.only('can index a newly added file', async function (assert) { + test('can index a newly added file', async function (assert) { let realmEventTimestampStart = Date.now(); let postResponse = await request From 1afb5ae70530b05ecb6d27edb9b3550f5af0285b Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 12:15:19 +0000 Subject: [PATCH 16/48] Fix syntax --- packages/realm-server/tests/card-endpoints-test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/realm-server/tests/card-endpoints-test.ts b/packages/realm-server/tests/card-endpoints-test.ts index ef3049b5955..4d1fc410067 100644 --- a/packages/realm-server/tests/card-endpoints-test.ts +++ b/packages/realm-server/tests/card-endpoints-test.ts @@ -1661,7 +1661,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: testRealmInfo + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -1713,7 +1713,7 @@ module(basename(__filename), function () { name: 'Friend', module: 'http://localhost:4202/node-test/friend', }, - realmInfo: testRealmInfo + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -2919,7 +2919,7 @@ module(basename(__filename), function () { name: 'Friend', module: '../friend', }, - realmInfo: testRealmInfo + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { @@ -2971,7 +2971,7 @@ module(basename(__filename), function () { name: 'Friend', module: '../friend', }, - realmInfo: testRealmInfo + realmInfo: testRealmInfo, realmURL: testRealmHref, }, links: { From 5cb89d1c26a9011eb7674a9e00c0dd9d62f55d90 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 13:08:28 +0000 Subject: [PATCH 17/48] node test realm is the owner --- .../tests/card-dependencies-endpoint-test.ts | 2 +- .../realm-server/tests/card-endpoints-test.ts | 28 +++++++++---------- .../tests/card-source-endpoints-test.ts | 22 +++++++-------- .../tests/file-watcher-events-test.ts | 2 +- packages/realm-server/tests/indexing-test.ts | 2 +- .../realm-server/tests/realm-auth-test.ts | 2 +- .../tests/realm-endpoints-test.ts | 2 +- .../tests/search-prerendered-test.ts | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/realm-server/tests/card-dependencies-endpoint-test.ts b/packages/realm-server/tests/card-dependencies-endpoint-test.ts index 67472566f3f..abd11ab2c8d 100644 --- a/packages/realm-server/tests/card-dependencies-endpoint-test.ts +++ b/packages/realm-server/tests/card-dependencies-endpoint-test.ts @@ -90,7 +90,7 @@ module(basename(__filename), function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/card-endpoints-test.ts b/packages/realm-server/tests/card-endpoints-test.ts index 4d1fc410067..3af8017ba77 100644 --- a/packages/realm-server/tests/card-endpoints-test.ts +++ b/packages/realm-server/tests/card-endpoints-test.ts @@ -140,7 +140,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -729,7 +729,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, published: true, @@ -802,7 +802,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -877,7 +877,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -983,7 +983,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -1942,7 +1942,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -2020,7 +2020,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], }, onRealmSetup, }); @@ -3423,7 +3423,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], }, cardSizeLimitBytes: 512, onRealmSetup, @@ -3471,7 +3471,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -3542,7 +3542,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -3653,7 +3653,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -3695,7 +3695,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, fileSystem: { 'greeting.txt': 'hello', @@ -3762,7 +3762,7 @@ module(basename(__filename), function () { realmURL: providerRealmURL, permissions: { '*': ['read', 'write', 'realm-owner'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, fileSystem: { 'person.gts': ` @@ -3792,7 +3792,7 @@ module(basename(__filename), function () { realmURL: consumerRealmURL, permissions: { '*': ['read', 'write', 'realm-owner'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, fileSystem: { 'favorite-finder.gts': ` diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index 2b8b3519797..07b3f0577c7 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -73,7 +73,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -354,7 +354,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -404,7 +404,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], }, onRealmSetup, }); @@ -478,7 +478,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -551,7 +551,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -593,7 +593,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -994,7 +994,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, cardSizeLimitBytes: 512, onRealmSetup, @@ -1029,7 +1029,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -1083,7 +1083,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -1197,7 +1197,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, cardSizeLimitBytes: 512, onRealmSetup, @@ -1224,7 +1224,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/file-watcher-events-test.ts b/packages/realm-server/tests/file-watcher-events-test.ts index 7ea7583510c..2917748af3b 100644 --- a/packages/realm-server/tests/file-watcher-events-test.ts +++ b/packages/realm-server/tests/file-watcher-events-test.ts @@ -59,7 +59,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, subscribeToRealmEvents: true, onRealmSetup, diff --git a/packages/realm-server/tests/indexing-test.ts b/packages/realm-server/tests/indexing-test.ts index fd340cf14b2..637b39da161 100644 --- a/packages/realm-server/tests/indexing-test.ts +++ b/packages/realm-server/tests/indexing-test.ts @@ -2073,7 +2073,7 @@ module(basename(__filename), function () { }, consumer: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, }); diff --git a/packages/realm-server/tests/realm-auth-test.ts b/packages/realm-server/tests/realm-auth-test.ts index e3cea761222..a1eeae582f5 100644 --- a/packages/realm-server/tests/realm-auth-test.ts +++ b/packages/realm-server/tests/realm-auth-test.ts @@ -26,7 +26,7 @@ module(basename(__filename), function () { permissions: { '*': ['read'], [matrixUserId]: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup: ({ dbAdapter: adapter, request: req }) => { dbAdapter = adapter; diff --git a/packages/realm-server/tests/realm-endpoints-test.ts b/packages/realm-server/tests/realm-endpoints-test.ts index c1e33c02bb9..df2a1286525 100644 --- a/packages/realm-server/tests/realm-endpoints-test.ts +++ b/packages/realm-server/tests/realm-endpoints-test.ts @@ -113,7 +113,7 @@ module(basename(__filename), function () { '*': ['read', 'write'], user: ['read', 'write', 'realm-owner'], carol: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL, onRealmSetup, diff --git a/packages/realm-server/tests/search-prerendered-test.ts b/packages/realm-server/tests/search-prerendered-test.ts index 9777aa58082..e58f0654775 100644 --- a/packages/realm-server/tests/search-prerendered-test.ts +++ b/packages/realm-server/tests/search-prerendered-test.ts @@ -978,7 +978,7 @@ module(basename(__filename), function () { realmURL, permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, fileSystem: { 'person.gts': ` From 801d6d131f0a3288eb23e3b0eb46faba22fa297c Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 13:12:51 +0000 Subject: [PATCH 18/48] fix syntax error --- packages/realm-server/tests/card-endpoints-test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/realm-server/tests/card-endpoints-test.ts b/packages/realm-server/tests/card-endpoints-test.ts index 3af8017ba77..7dcd22730b4 100644 --- a/packages/realm-server/tests/card-endpoints-test.ts +++ b/packages/realm-server/tests/card-endpoints-test.ts @@ -2020,7 +2020,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -3423,7 +3423,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, cardSizeLimitBytes: 512, onRealmSetup, From eea7e1f36bd6923b9bb2b4d11c9098e9bac65417 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 13:13:37 +0000 Subject: [PATCH 19/48] syntax error --- packages/realm-server/tests/card-source-endpoints-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/realm-server/tests/card-source-endpoints-test.ts b/packages/realm-server/tests/card-source-endpoints-test.ts index 07b3f0577c7..bf9598edfe7 100644 --- a/packages/realm-server/tests/card-source-endpoints-test.ts +++ b/packages/realm-server/tests/card-source-endpoints-test.ts @@ -404,7 +404,7 @@ module(basename(__filename), function () { setupPermissionedRealmAtURL(hooks, realmURL, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read', 'realm-owner'] 'realm-owner'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); From b3473df2af5301de9de9530e43ed80d84baff397 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 13:39:15 +0000 Subject: [PATCH 20/48] JWTs need to have matching permissions, add test realm user as owner --- .../tests/realm-endpoints/directory-test.ts | 2 +- .../realm-server/tests/realm-endpoints/info-test.ts | 11 +++++------ .../realm-server/tests/realm-endpoints/lint-test.ts | 2 +- .../realm-server/tests/realm-endpoints/mtimes-test.ts | 2 +- .../tests/realm-endpoints/permissions-test.ts | 2 +- .../realm-server/tests/realm-endpoints/search-test.ts | 4 ++-- .../realm-server/tests/realm-endpoints/user-test.ts | 4 ++-- .../realm-server/tests/server-endpoints/helpers.ts | 2 +- 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/realm-server/tests/realm-endpoints/directory-test.ts b/packages/realm-server/tests/realm-endpoints/directory-test.ts index 6782d6a3411..790488bed5b 100644 --- a/packages/realm-server/tests/realm-endpoints/directory-test.ts +++ b/packages/realm-server/tests/realm-endpoints/directory-test.ts @@ -100,7 +100,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/info-test.ts b/packages/realm-server/tests/realm-endpoints/info-test.ts index d77aed49d33..ef28bc60f3a 100644 --- a/packages/realm-server/tests/realm-endpoints/info-test.ts +++ b/packages/realm-server/tests/realm-endpoints/info-test.ts @@ -91,8 +91,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { module('permissioned realm', function (hooks) { setupPermissionedRealm(hooks, { permissions: { - john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL, onRealmSetup, @@ -124,7 +123,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { .post(infoPath) .set('X-HTTP-Method-Override', 'QUERY') .set('Accept', 'application/vnd.api+json') - .set('Authorization', `Bearer ${createJWT(testRealm, 'not-john')}`); + .set('Authorization', `Bearer ${createJWT(testRealm, 'not-a-user')}`); assert.strictEqual(response.status, 403, 'HTTP 403 status'); }); @@ -137,7 +136,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { .set('Accept', 'application/vnd.api+json') .set( 'Authorization', - `Bearer ${createJWT(testRealm, 'john', ['read', 'write'])}`, + `Bearer ${createJWT(testRealm, '@node-test_realm:localhost', ['read', 'realm-owner'])}`, ); assert.strictEqual(response.status, 200, 'HTTP 200 status'); @@ -165,7 +164,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { users: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL, onRealmSetup, @@ -208,7 +207,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { bob: ['read'], jane: ['read'], john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL, onRealmSetup, diff --git a/packages/realm-server/tests/realm-endpoints/lint-test.ts b/packages/realm-server/tests/realm-endpoints/lint-test.ts index b5700c13f5e..6c4ae5d7959 100644 --- a/packages/realm-server/tests/realm-endpoints/lint-test.ts +++ b/packages/realm-server/tests/realm-endpoints/lint-test.ts @@ -28,7 +28,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/mtimes-test.ts b/packages/realm-server/tests/realm-endpoints/mtimes-test.ts index ba09a520d4d..ad3bf180469 100644 --- a/packages/realm-server/tests/realm-endpoints/mtimes-test.ts +++ b/packages/realm-server/tests/realm-endpoints/mtimes-test.ts @@ -30,7 +30,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { mary: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/permissions-test.ts b/packages/realm-server/tests/realm-endpoints/permissions-test.ts index f194821479c..0b1b8f8e8ac 100644 --- a/packages/realm-server/tests/realm-endpoints/permissions-test.ts +++ b/packages/realm-server/tests/realm-endpoints/permissions-test.ts @@ -43,7 +43,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { permissions: { mary: ['read', 'write', 'realm-owner'], bob: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/realm-endpoints/search-test.ts b/packages/realm-server/tests/realm-endpoints/search-test.ts index 52d7b7e000e..83a6a7d87fb 100644 --- a/packages/realm-server/tests/realm-endpoints/search-test.ts +++ b/packages/realm-server/tests/realm-endpoints/search-test.ts @@ -600,7 +600,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL: new URL('http://127.0.0.1:4444/test/'), onRealmSetup, @@ -657,7 +657,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { '*': ['read'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, realmURL: new URL('http://127.0.0.1:4444/test/'), onRealmSetup, diff --git a/packages/realm-server/tests/realm-endpoints/user-test.ts b/packages/realm-server/tests/realm-endpoints/user-test.ts index 35de5d41a05..2a9cb7975bc 100644 --- a/packages/realm-server/tests/realm-endpoints/user-test.ts +++ b/packages/realm-server/tests/realm-endpoints/user-test.ts @@ -66,7 +66,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); @@ -476,7 +476,7 @@ module(`realm-endpoints/${basename(__filename)}`, function () { setupPermissionedRealm(hooks, { permissions: { john: ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); diff --git a/packages/realm-server/tests/server-endpoints/helpers.ts b/packages/realm-server/tests/server-endpoints/helpers.ts index 060d5b63c0a..f213c6e348a 100644 --- a/packages/realm-server/tests/server-endpoints/helpers.ts +++ b/packages/realm-server/tests/server-endpoints/helpers.ts @@ -73,7 +73,7 @@ export function setupServerEndpointsTest( setupPermissionedRealm(hooks, { permissions: { '*': ['read', 'write'], - '@node-test_realm:localhost': ['read'], + '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); From f501fe0d00b0662ea7c96dc585cb5205f77ed860 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 13:46:09 +0000 Subject: [PATCH 21/48] Remove extra user, remove unnecessary filesystem content --- packages/realm-server/tests/realm-endpoints/permissions-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/realm-server/tests/realm-endpoints/permissions-test.ts b/packages/realm-server/tests/realm-endpoints/permissions-test.ts index 0b1b8f8e8ac..75d7a34a5ce 100644 --- a/packages/realm-server/tests/realm-endpoints/permissions-test.ts +++ b/packages/realm-server/tests/realm-endpoints/permissions-test.ts @@ -40,10 +40,10 @@ module(`realm-endpoints/${basename(__filename)}`, function () { module('permissions requests', function (hooks) { setupPermissionedRealm(hooks, { + fileSystem: {}, permissions: { mary: ['read', 'write', 'realm-owner'], bob: ['read', 'write'], - '@node-test_realm:localhost': ['read', 'realm-owner'], }, onRealmSetup, }); From 86664a97ffb1bd18cc3083f62ce28af58205e5ec Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 14:07:30 +0000 Subject: [PATCH 22/48] No longer creating a session room for creating a realm --- .../tests/server-endpoints/realm-lifecycle-test.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts index 00359115136..f4cc825f05a 100644 --- a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts +++ b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts @@ -29,7 +29,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { function (hooks) { let context = setupServerEndpointsTest(hooks); - test('POST /_create-realm', async function (assert) { + test.only('POST /_create-realm', async function (assert) { // we randomize the realm and owner names so that we can isolate matrix // test state--there is no "delete user" matrix API let endpoint = `test-realm-${uuidv4()}`; @@ -120,16 +120,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { [ownerUserId]: ['read', 'write', 'realm-owner'], }); - let sessionRoom = await fetchSessionRoom( - context.dbAdapter, - testRealmServerMatrixUserId, - ownerUserId, - ); - assert.ok( - sessionRoom, - 'session room record was created for the owner after realm creation', - ); - let id: string; let realm = context.testRealmServer2.testingOnlyRealms.find( (r) => r.url === json.data.id, From f966aab67e63a2fc87eacf71c702526adca76cc4 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 14:23:44 +0000 Subject: [PATCH 23/48] Linting and type fixes --- packages/base/matrix-event.gts | 14 ++++++++----- packages/realm-server/server.ts | 1 - packages/realm-server/tests/helpers/index.ts | 7 ++----- .../server-endpoints/realm-lifecycle-test.ts | 4 +--- packages/runtime-common/realm.ts | 21 +++++++++++++------ 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/packages/base/matrix-event.gts b/packages/base/matrix-event.gts index d8e4d6b7244..49f9a29d99f 100644 --- a/packages/base/matrix-event.gts +++ b/packages/base/matrix-event.gts @@ -386,12 +386,9 @@ export interface RealmEvent extends BaseMatrixEvent { content: RealmEventContent; } -export type RealmEventContent = ( +export type RealmEventContent = | IndexRealmEventContent - | UpdateRealmEventContent -) & { - realmURL?: string; -}; + | UpdateRealmEventContent; export type IndexRealmEventContent = | IncrementalIndexEventContent @@ -404,23 +401,27 @@ export interface IncrementalIndexEventContent { indexType: 'incremental'; invalidations: string[]; clientRequestId?: string | null; + realmURL?: string; } interface FullIndexEventContent { eventName: 'index'; indexType: 'full'; + realmURL?: string; } interface CopiedIndexEventContent { eventName: 'index'; indexType: 'copy'; sourceRealmURL: string; + realmURL?: string; } export interface IncrementalIndexInitiationContent { eventName: 'index'; indexType: 'incremental-index-initiation'; updatedFile: string; + realmURL?: string; } export type UpdateRealmEventContent = @@ -431,16 +432,19 @@ export type UpdateRealmEventContent = export interface FileAddedEventContent { eventName: 'update'; added: string; + realmURL?: string; } export interface FileUpdatedEventContent { eventName: 'update'; updated: string; + realmURL?: string; } export interface FileRemovedEventContent { eventName: 'update'; removed: string; + realmURL?: string; } export interface StopGeneratingEvent extends BaseMatrixEvent { diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index b4492791ecd..dceeec50b71 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -19,7 +19,6 @@ import { PUBLISHED_DIRECTORY_NAME, RealmPaths, fetchSessionRoom, - REALM_SERVER_REALM, userInitiatedPriority, hasExtension, } from '@cardstack/runtime-common'; diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index afb80a174f6..33cb18f4d70 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -148,10 +148,7 @@ export const matrixURL = new URL('http://localhost:8008'); const testPrerenderHost = '127.0.0.1'; const testPrerenderPort = 4460; const testPrerenderURL = `http://${testPrerenderHost}:${testPrerenderPort}`; -const testMatrix: MatrixConfig = { - url: matrixURL, - username: 'node-test_realm', -}; + export const testRealmInfo = { name: 'Test Realm', backgroundURL: null, @@ -292,6 +289,7 @@ async function startTestPrerenderServer(): Promise { } let server = createPrerenderHttpServer({ silent: Boolean(process.env.SILENT_PRERENDERER), + maxPages: 1, }); prerenderServer = server; trackServer(server); @@ -1009,7 +1007,6 @@ export function setupMatrixRoom( hooks.beforeEach(async function () { await matrixClient.login(); - let userId = matrixClient.getUserId()!; let realmSetup = getRealmSetup(); let openIdToken = await matrixClient.getOpenIdToken(); diff --git a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts index f4cc825f05a..9f834661198 100644 --- a/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts +++ b/packages/realm-server/tests/server-endpoints/realm-lifecycle-test.ts @@ -11,13 +11,11 @@ import { import type { SingleCardDocument } from '@cardstack/runtime-common'; import type { CardCollectionDocument } from '@cardstack/runtime-common/document-types'; import { cardSrc } from '@cardstack/runtime-common/etc/test-fixtures'; -import { fetchSessionRoom } from '@cardstack/runtime-common/db-queries/session-room-queries'; import { closeServer, createJWT, realmSecretSeed, testRealmInfo, - testRealmServerMatrixUserId, } from '../helpers'; import { createJWT as createRealmServerJWT } from '../../utils/jwt'; import { setupServerEndpointsTest, testRealm2URL } from './helpers'; @@ -29,7 +27,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { function (hooks) { let context = setupServerEndpointsTest(hooks); - test.only('POST /_create-realm', async function (assert) { + test('POST /_create-realm', async function (assert) { // we randomize the realm and owner names so that we can isolate matrix // test state--there is no "delete user" matrix API let endpoint = `test-realm-${uuidv4()}`; diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 6d105335337..ca3d0f660ec 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -70,7 +70,6 @@ import { codeRefWithAbsoluteURL, userInitiatedPriority, systemInitiatedPriority, - userIdFromUsername, isCardDocumentString, isBrowserTestEnv, type IndexedFile, @@ -674,10 +673,18 @@ export class Realm { await this.#matrixClient.login(); } + async getMatrixUserId() { + if (!this.#matrixClient.getUserId()) { + await this.logInToMatrix(); + } + return this.#matrixClient.getUserId()!; + } + async ensureSessionRoom(matrixUserId: string): Promise { + let realmServerMatrixUserId = await this.getMatrixUserId(); let sessionRoom = await fetchSessionRoom( this.#dbAdapter, - this.#matrixClient.getUserId(), + realmServerMatrixUserId, matrixUserId, ); @@ -686,7 +693,7 @@ export class Realm { sessionRoom = await this.#matrixClient.createDM(matrixUserId); await upsertSessionRoom( this.#dbAdapter, - this.#matrixClient.getUserId(), + realmServerMatrixUserId, matrixUserId, sessionRoom, ); @@ -1395,6 +1402,7 @@ export class Realm { request: Request, requestContext: RequestContext, ) { + let realmServerMatrixUserId = await this.getMatrixUserId(); let matrixBackendAuthentication = new MatrixBackendAuthentication( this.#matrixClient, { @@ -1435,7 +1443,7 @@ export class Realm { setSessionRoom: (userId: string, roomId: string) => upsertSessionRoom( this.#dbAdapter, - this.#matrixClient.getUserId(), + realmServerMatrixUserId, userId, roomId, ), @@ -1876,7 +1884,8 @@ export class Realm { } // if the client is the realm matrix user then we permit all actions - if (user === this.#matrixClient.getUserId()) { + let realmServerMatrixUserId = await this.getMatrixUserId(); + if (user === realmServerMatrixUserId) { return; } @@ -4366,7 +4375,7 @@ export class Realm { private async createRequestContext( requiredPermission: RealmAction, ): Promise { - let realmServerMatrixUserId = this.#matrixClient.getUserId(); + let realmServerMatrixUserId = await this.getMatrixUserId(); let permissions: RealmPermissions; let shouldUseWorldReadable = requiredPermission === 'read' && (await this.isWorldReadable()); From a94a476eac86b0c6c6ad574bdf8f56a4f2fd9da6 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 16:15:06 +0000 Subject: [PATCH 24/48] Improve where we get userId to not require login --- packages/runtime-common/helpers/const.ts | 11 +-------- packages/runtime-common/realm.ts | 29 ++++++++++-------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/packages/runtime-common/helpers/const.ts b/packages/runtime-common/helpers/const.ts index f7b7b38fb1e..1ae04ac4b79 100644 --- a/packages/runtime-common/helpers/const.ts +++ b/packages/runtime-common/helpers/const.ts @@ -2,15 +2,6 @@ import type { RealmInfo } from '../index'; export const testRealmURL = `http://test-realm/test/`; export const testHostModeRealmURL = 'http://test-realm/user/test/'; -export function testRealmURLToUsername(realmURLString: string) { - let realmURL = new URL(realmURLString); - let realmUsername = `@realm/${realmURL.host}${realmURL.pathname - .replace('/', '-') - .replace(/\/$/, '')}:localhost`; - - return realmUsername; -} - export const testRealmInfo: RealmInfo = { name: 'Unnamed Workspace', backgroundURL: null, @@ -19,7 +10,7 @@ export const testRealmInfo: RealmInfo = { interactHome: null, hostHome: null, visibility: 'public', - realmUserId: testRealmURLToUsername(testRealmURL), + realmUserId: '@realm_server:localhost', publishable: null, lastPublishedAt: null, }; diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index ca3d0f660ec..c74783a279b 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -153,6 +153,7 @@ import { type PublishabilityWarningType, type ResourceIndexEntry, } from './publishability'; +import { userIdFromUsername } from 'matrix-client'; export const REALM_ROOM_RETENTION_POLICY_MAX_LIFETIME = 60 * 60 * 1000; @@ -395,6 +396,7 @@ export type RequestContext = { realm: Realm; permissions: RealmPermissions }; export class Realm { #startedUp = new Deferred(); #matrixClient: MatrixClient; + #matrixClientUserId: string; #realmServerURL: string; #realmIndexUpdater: RealmIndexUpdater; #realmIndexQueryEngine: RealmIndexQueryEngine; @@ -487,6 +489,10 @@ export class Realm { this.#fromScratchIndexPriority = opts?.fromScratchIndexPriority ?? systemInitiatedPriority; this.#matrixClient = matrixClient; + this.#matrixClientUserId = userIdFromUsername( + this.#matrixClient.username, + this.#matrixClient.matrixURL.href, + ); this.#realmServerURL = ensureTrailingSlash(realmServerURL); this.#cardSizeLimitBytes = cardSizeLimitBytes ?? DEFAULT_CARD_SIZE_LIMIT_BYTES; @@ -673,18 +679,10 @@ export class Realm { await this.#matrixClient.login(); } - async getMatrixUserId() { - if (!this.#matrixClient.getUserId()) { - await this.logInToMatrix(); - } - return this.#matrixClient.getUserId()!; - } - async ensureSessionRoom(matrixUserId: string): Promise { - let realmServerMatrixUserId = await this.getMatrixUserId(); let sessionRoom = await fetchSessionRoom( this.#dbAdapter, - realmServerMatrixUserId, + this.#matrixClientUserId, matrixUserId, ); @@ -693,7 +691,7 @@ export class Realm { sessionRoom = await this.#matrixClient.createDM(matrixUserId); await upsertSessionRoom( this.#dbAdapter, - realmServerMatrixUserId, + this.#matrixClientUserId, matrixUserId, sessionRoom, ); @@ -1402,7 +1400,6 @@ export class Realm { request: Request, requestContext: RequestContext, ) { - let realmServerMatrixUserId = await this.getMatrixUserId(); let matrixBackendAuthentication = new MatrixBackendAuthentication( this.#matrixClient, { @@ -1443,7 +1440,7 @@ export class Realm { setSessionRoom: (userId: string, roomId: string) => upsertSessionRoom( this.#dbAdapter, - realmServerMatrixUserId, + this.#matrixClientUserId, userId, roomId, ), @@ -1884,8 +1881,7 @@ export class Realm { } // if the client is the realm matrix user then we permit all actions - let realmServerMatrixUserId = await this.getMatrixUserId(); - if (user === realmServerMatrixUserId) { + if (user === this.#matrixClientUserId) { return; } @@ -4375,19 +4371,18 @@ export class Realm { private async createRequestContext( requiredPermission: RealmAction, ): Promise { - let realmServerMatrixUserId = await this.getMatrixUserId(); let permissions: RealmPermissions; let shouldUseWorldReadable = requiredPermission === 'read' && (await this.isWorldReadable()); if (shouldUseWorldReadable) { permissions = { - [realmServerMatrixUserId]: ['assume-user'], + [this.#matrixClientUserId]: ['assume-user'], '*': ['read'], }; } else { permissions = { - [realmServerMatrixUserId]: ['assume-user'], + [this.#matrixClientUserId]: ['assume-user'], ...(await fetchRealmPermissions(this.#dbAdapter, new URL(this.url))), }; } From c467c0466db4dcb2db0a94d4ec4013f781f505bf Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 16:15:29 +0000 Subject: [PATCH 25/48] Use test realm info for id --- packages/host/tests/acceptance/query-fields-test.gts | 6 +++--- packages/host/tests/helpers/index.gts | 1 - .../tests/integration/message-service-subscription-test.gts | 4 ++-- packages/host/tests/integration/realm-test.gts | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/host/tests/acceptance/query-fields-test.gts b/packages/host/tests/acceptance/query-fields-test.gts index 7a8c5bd7784..f0e99068f14 100644 --- a/packages/host/tests/acceptance/query-fields-test.gts +++ b/packages/host/tests/acceptance/query-fields-test.gts @@ -14,7 +14,7 @@ import { module, test } from 'qunit'; import type { Loader } from '@cardstack/runtime-common'; import { SupportedMimeType } from '@cardstack/runtime-common'; -import { testRealmURLToUsername } from '@cardstack/runtime-common/helpers/const'; +import { testRealmInfo } from '@cardstack/runtime-common/helpers/const'; import { APP_BOXEL_REALM_EVENT_TYPE } from '@cardstack/runtime-common/matrix-constants'; import type NetworkService from '@cardstack/host/services/network'; @@ -361,7 +361,7 @@ module( 'no query runs while hydrating server-provided results', ); - let realmMatrixUsername = testRealmURLToUsername(testRealmURL); + let realmMatrixUsername = testRealmInfo.realmUserId; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, '@testuser:localhost', @@ -476,7 +476,7 @@ module( (store as any).store.sweep(cardAPI); await settled(); - let realmMatrixUsername = testRealmURLToUsername(testRealmURL); + let realmMatrixUsername = testRealmInfo.realmUserId; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, '@testuser:localhost', diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 22ec4035f1c..3fd21f624f5 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -27,7 +27,6 @@ import { testHostModeRealmURL, testRealmInfo, testRealmURL, - testRealmURLToUsername, Worker, DEFAULT_CARD_SIZE_LIMIT_BYTES, type DefinitionLookup, diff --git a/packages/host/tests/integration/message-service-subscription-test.gts b/packages/host/tests/integration/message-service-subscription-test.gts index 7d60c7783cf..b2bbcc26c8a 100644 --- a/packages/host/tests/integration/message-service-subscription-test.gts +++ b/packages/host/tests/integration/message-service-subscription-test.gts @@ -10,7 +10,7 @@ import { getService } from '@universal-ember/test-support'; import { module, test } from 'qunit'; import { baseRealm } from '@cardstack/runtime-common'; -import { testRealmURLToUsername } from '@cardstack/runtime-common/helpers/const'; +import { testRealmInfo } from '@cardstack/runtime-common/helpers/const'; import type { Loader } from '@cardstack/runtime-common/loader'; import { APP_BOXEL_REALM_EVENT_TYPE } from '@cardstack/runtime-common/matrix-constants'; @@ -45,7 +45,7 @@ module('Integration | message service subscription', function (hooks) { autostart: true, }); - let realmMatrixUsername = testRealmURLToUsername(testRealmURL); + let realmMatrixUsername = testRealmInfo.realmUserId; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, diff --git a/packages/host/tests/integration/realm-test.gts b/packages/host/tests/integration/realm-test.gts index d59fe452868..621b7a9563b 100644 --- a/packages/host/tests/integration/realm-test.gts +++ b/packages/host/tests/integration/realm-test.gts @@ -3575,7 +3575,7 @@ posts/ignore-me.gts name: 'Example Workspace', backgroundURL: 'https://example-background-url.com', iconURL: 'https://example-icon-url.com', - realmUserId: '@realm/test-realm-test:localhost', + realmUserId: '@realm_server:localhost', showAsCatalog: null, visibility: 'public', publishable: null, From a495154bd037bf5c9bfa5ad33d07752115b543eb Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 16:23:34 +0000 Subject: [PATCH 26/48] Import fix --- packages/runtime-common/realm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index c74783a279b..eda248814cc 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -110,6 +110,7 @@ import { MatrixClient, ensureFullMatrixUserId, getMatrixUsername, + userIdFromUsername, } from './matrix-client'; import { PACKAGES_FAKE_ORIGIN } from './package-shim-handler'; @@ -153,7 +154,6 @@ import { type PublishabilityWarningType, type ResourceIndexEntry, } from './publishability'; -import { userIdFromUsername } from 'matrix-client'; export const REALM_ROOM_RETENTION_POLICY_MAX_LIFETIME = 60 * 60 * 1000; From fb458c49a1a6862c9cf77488d7b93b026f525d15 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 16:25:24 +0000 Subject: [PATCH 27/48] Restore import as it was earlier --- packages/runtime-common/realm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index eda248814cc..fa9d676f159 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -70,6 +70,7 @@ import { codeRefWithAbsoluteURL, userInitiatedPriority, systemInitiatedPriority, + userIdFromUsername, isCardDocumentString, isBrowserTestEnv, type IndexedFile, @@ -110,7 +111,6 @@ import { MatrixClient, ensureFullMatrixUserId, getMatrixUsername, - userIdFromUsername, } from './matrix-client'; import { PACKAGES_FAKE_ORIGIN } from './package-shim-handler'; From a231047f2329174537069a7f39d2d8ca6f8c64f6 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 16:59:31 +0000 Subject: [PATCH 28/48] Index events contain realm url --- packages/host/tests/acceptance/query-fields-test.gts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/host/tests/acceptance/query-fields-test.gts b/packages/host/tests/acceptance/query-fields-test.gts index f0e99068f14..b80ecf1a986 100644 --- a/packages/host/tests/acceptance/query-fields-test.gts +++ b/packages/host/tests/acceptance/query-fields-test.gts @@ -379,6 +379,7 @@ module( eventName: 'index', indexType: 'incremental', invalidations: [`${testRealmURL}Person/new-match`], + realmURL: testRealmURL, }, { type: APP_BOXEL_REALM_EVENT_TYPE }, ); @@ -494,6 +495,7 @@ module( eventName: 'index', indexType: 'incremental', invalidations: [`${testRealmURL}Person/new-match`], + realmURL: testRealmURL, }, { type: APP_BOXEL_REALM_EVENT_TYPE }, ); From 1974d262c9912148567c3d491c826da21efbefcb Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 17:01:16 +0000 Subject: [PATCH 29/48] Realm server is realm user --- packages/host/tests/integration/realm-test.gts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/host/tests/integration/realm-test.gts b/packages/host/tests/integration/realm-test.gts index 621b7a9563b..f2794734e71 100644 --- a/packages/host/tests/integration/realm-test.gts +++ b/packages/host/tests/integration/realm-test.gts @@ -385,7 +385,7 @@ module('Integration | realm', function (hooks) { backgroundURL: 'https://i.postimg.cc/tgRHRV8C/pawel-czerwinski-h-Nrd99q5pe-I-unsplash.jpg', iconURL: 'https://boxel-images.boxel.ai/icons/cardstack.png', - realmUserId: '@test_realm:localhost', + realmUserId: '@realm_server:localhost', showAsCatalog: null, visibility: 'public', publishable: null, @@ -3288,7 +3288,7 @@ module('Integration | realm', function (hooks) { backgroundURL: 'https://i.postimg.cc/tgRHRV8C/pawel-czerwinski-h-Nrd99q5pe-I-unsplash.jpg', iconURL: 'https://boxel-images.boxel.ai/icons/cardstack.png', - realmUserId: '@test_realm:localhost', + realmUserId: '@realm_server:localhost', showAsCatalog: null, visibility: 'public', publishable: null, From 6a5402ea8264210b146bdfcc10711fbc5b8ea0a0 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Wed, 11 Feb 2026 17:01:54 +0000 Subject: [PATCH 30/48] Lint --- packages/runtime-common/realm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index fa9d676f159..7ffc35784e3 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -108,7 +108,7 @@ import { createResponse } from './create-response'; import { mergeRelationships } from './merge-relationships'; import { getCardDirectoryName } from './helpers/card-directory-name'; import { - MatrixClient, + type MatrixClient, ensureFullMatrixUserId, getMatrixUsername, } from './matrix-client'; From 5ff6b808cc0d560e898180d61e76eb8caf5921d5 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 16:24:50 +0000 Subject: [PATCH 31/48] Move the session room to the users table now that it is 1:1 --- packages/billing/billing-queries.ts | 3 + ...771000000000_move-session-room-to-users.js | 51 +++++++++++++++ .../handlers/handle-create-session.ts | 19 +----- packages/realm-server/node-realm.ts | 16 ++--- packages/realm-server/server.ts | 3 +- .../runtime-common/db-queries/db-types.ts | 1 + .../db-queries/session-room-queries.ts | 63 +++++-------------- packages/runtime-common/realm.ts | 13 +--- 8 files changed, 78 insertions(+), 91 deletions(-) create mode 100644 packages/postgres/migrations/1771000000000_move-session-room-to-users.js diff --git a/packages/billing/billing-queries.ts b/packages/billing/billing-queries.ts index bc768264b4f..baf7fe71ab1 100644 --- a/packages/billing/billing-queries.ts +++ b/packages/billing/billing-queries.ts @@ -138,6 +138,7 @@ export async function getUserById( stripeCustomerId: results[0].stripe_customer_id, stripeCustomerEmail: results[0].stripe_customer_email, matrixRegistrationToken: results[0].matrix_registration_token, + sessionRoomId: results[0].session_room_id ?? null, } as User; } @@ -159,6 +160,7 @@ export async function getUserByStripeId( matrixUserId: results[0].matrix_user_id, stripeCustomerId: results[0].stripe_customer_id, matrixRegistrationToken: results[0].matrix_registration_token, + sessionRoomId: results[0].session_room_id ?? null, } as User; } @@ -181,6 +183,7 @@ export async function getUserByMatrixUserId( stripeCustomerId: results[0].stripe_customer_id, stripeCustomerEmail: results[0].stripe_customer_email, matrixRegistrationToken: results[0].matrix_registration_token, + sessionRoomId: results[0].session_room_id ?? null, } as User; } diff --git a/packages/postgres/migrations/1771000000000_move-session-room-to-users.js b/packages/postgres/migrations/1771000000000_move-session-room-to-users.js new file mode 100644 index 00000000000..c0967080908 --- /dev/null +++ b/packages/postgres/migrations/1771000000000_move-session-room-to-users.js @@ -0,0 +1,51 @@ +exports.up = (pgm) => { + pgm.addColumns('users', { + session_room_id: { type: 'varchar' }, + }); + + pgm.sql(` + UPDATE users + SET session_room_id = sr.room_id + FROM session_rooms sr + WHERE users.matrix_user_id = sr.matrix_user_id + AND sr.realm_url = '__realm-server__' + `); + + pgm.dropTable('session_rooms'); +}; + +exports.down = (pgm) => { + pgm.createTable( + 'session_rooms', + { + realm_url: { type: 'varchar', notNull: true }, + realm_user_id: { type: 'varchar' }, + matrix_user_id: { type: 'varchar', notNull: true }, + room_id: { type: 'varchar', notNull: true }, + created_at: { + type: 'timestamp', + notNull: true, + default: pgm.func('current_timestamp'), + }, + updated_at: { + type: 'timestamp', + notNull: true, + default: pgm.func('current_timestamp'), + }, + }, + { + constraints: { + primaryKey: ['realm_url', 'matrix_user_id'], + }, + }, + ); + + pgm.sql(` + INSERT INTO session_rooms (realm_url, matrix_user_id, room_id) + SELECT '__realm-server__', matrix_user_id, session_room_id + FROM users + WHERE session_room_id IS NOT NULL + `); + + pgm.dropColumns('users', ['session_room_id']); +}; diff --git a/packages/realm-server/handlers/handle-create-session.ts b/packages/realm-server/handlers/handle-create-session.ts index 1fb6b147060..840adbf7a49 100644 --- a/packages/realm-server/handlers/handle-create-session.ts +++ b/packages/realm-server/handlers/handle-create-session.ts @@ -41,26 +41,11 @@ export default function handleCreateSessionRequest({ createJWT: async (user: string, sessionRoom: string) => createJWT({ user, sessionRoom }, realmSecretSeed), ensureSessionRoom: async (userId: string) => { - const realmServerUserId = matrixClient.getUserId(); - if (!realmServerUserId) { - throw new Error( - 'Realm server Matrix user ID is not available, unable to create session room', - ); - } - let sessionRoom = await fetchSessionRoom( - dbAdapter, - realmServerUserId, - userId, - ); + let sessionRoom = await fetchSessionRoom(dbAdapter, userId); if (!sessionRoom) { sessionRoom = await matrixClient.createDM(userId); - await upsertSessionRoom( - dbAdapter, - realmServerUserId, - userId, - sessionRoom, - ); + await upsertSessionRoom(dbAdapter, userId, sessionRoom); } return sessionRoom; }, diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index cecb13e0bbc..b319b9c03df 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -10,7 +10,7 @@ import { unixTime, type ResponseWithNodeStream, type TokenClaims, - fetchAllSessionRooms, + fetchRealmSessionRooms, } from '@cardstack/runtime-common'; import type { MatrixClient } from '@cardstack/runtime-common/matrix-client'; import type { LocalPath } from '@cardstack/runtime-common/paths'; @@ -245,7 +245,6 @@ export class NodeAdapter implements RealmAdapter { ...event, realmURL: realmUrl, }; - let realmUserId; if (dbAdapter.isClosed) { realmEventsLog.warn( `Database adapter is closed, skipping sending realm event`, @@ -254,8 +253,7 @@ export class NodeAdapter implements RealmAdapter { } try { await matrixClient.login(); - realmUserId = matrixClient.getUserId(); - if (!realmUserId) { + if (!matrixClient.getUserId()) { realmEventsLog.error( 'Matrix client has no user ID after login, unable to broadcast realm event', event, @@ -267,11 +265,7 @@ export class NodeAdapter implements RealmAdapter { return; } - let dmRooms = await this.waitForSessionRooms( - dbAdapter, - realmUrl, - realmUserId, - ); + let dmRooms = await this.waitForSessionRooms(dbAdapter, realmUrl); realmEventsLog.debug('Sending to dm rooms', Object.values(dmRooms)); @@ -296,7 +290,6 @@ export class NodeAdapter implements RealmAdapter { private async waitForSessionRooms( dbAdapter: DBAdapter, realmUrl: string, - realmUserId: string, attempts = 3, delayMs = 50, ): Promise> { @@ -306,7 +299,7 @@ export class NodeAdapter implements RealmAdapter { let dmRooms: Record = {}; try { - dmRooms = await fetchAllSessionRooms(dbAdapter, realmUrl, realmUserId); + dmRooms = await fetchRealmSessionRooms(dbAdapter, realmUrl); } catch (e) { realmEventsLog.error('Error getting account data', e); return {}; // bail immediately on errors instead of retrying @@ -324,7 +317,6 @@ export class NodeAdapter implements RealmAdapter { return await this.waitForSessionRooms( dbAdapter, realmUrl, - realmUserId, attempts - 1, delayMs, ); diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index dceeec50b71..e51b96a761e 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -1012,8 +1012,7 @@ export class RealmServer { if (!this.matrixClient.isLoggedIn()) { await this.matrixClient.login(); } - let realmUserId = this.matrixClient.getUserId()!; - let roomId = await fetchSessionRoom(this.dbAdapter, realmUserId, user); + let roomId = await fetchSessionRoom(this.dbAdapter, user); if (!roomId) { console.error( `Failed to send event: ${eventType}, cannot find session room for user: ${user}`, diff --git a/packages/runtime-common/db-queries/db-types.ts b/packages/runtime-common/db-queries/db-types.ts index 37396c1cb26..6cce00cdf7b 100644 --- a/packages/runtime-common/db-queries/db-types.ts +++ b/packages/runtime-common/db-queries/db-types.ts @@ -4,6 +4,7 @@ export interface User { stripeCustomerId: string; stripeCustomerEmail: string | null; matrixRegistrationToken: string | null; + sessionRoomId: string | null; } export interface Plan { diff --git a/packages/runtime-common/db-queries/session-room-queries.ts b/packages/runtime-common/db-queries/session-room-queries.ts index 091cac47776..2bca2541dfe 100644 --- a/packages/runtime-common/db-queries/session-room-queries.ts +++ b/packages/runtime-common/db-queries/session-room-queries.ts @@ -1,22 +1,15 @@ import type { DBAdapter } from '../db'; -import { query, param, dbExpression } from '../expression'; - -export const REALM_SERVER_REALM = '__realm-server__'; +import { query, param } from '../expression'; /** * Returns the stored session room id for the given matrix user or null when none exists. */ export async function fetchSessionRoom( dbAdapter: DBAdapter, - realmUserId: string, matrixUserId: string, ) { let rows = await query(dbAdapter, [ - 'SELECT room_id FROM session_rooms WHERE realm_user_id =', - param(realmUserId), - 'AND realm_url = ', - param(REALM_SERVER_REALM), - 'AND matrix_user_id =', + 'SELECT session_room_id FROM users WHERE matrix_user_id =', param(matrixUserId), ]); @@ -25,76 +18,48 @@ export async function fetchSessionRoom( } let [row] = rows; - return (row.room_id as string) ?? null; + return (row.session_room_id as string) ?? null; } /** - * Upserts the session room id for the given matrix user and updates the timestamp. + * Updates the session room id for the given matrix user. */ export async function upsertSessionRoom( dbAdapter: DBAdapter, - realmUserId: string, matrixUserId: string, roomId: string, ) { await query(dbAdapter, [ - 'INSERT INTO session_rooms (realm_url, realm_user_id, matrix_user_id, room_id, created_at, updated_at)', - 'VALUES (', - param(REALM_SERVER_REALM), - ',', - param(realmUserId), - ',', - param(matrixUserId), - ',', - param(roomId), - ',', - dbExpression({ pg: 'NOW()', sqlite: 'CURRENT_TIMESTAMP' }), - ',', - dbExpression({ pg: 'NOW()', sqlite: 'CURRENT_TIMESTAMP' }), - ')', - 'ON CONFLICT (realm_url, matrix_user_id) DO UPDATE SET', - 'room_id =', + 'UPDATE users SET session_room_id =', param(roomId), - ',', - 'realm_user_id =', - param(realmUserId), - ',', - 'updated_at =', - dbExpression({ pg: 'NOW()', sqlite: 'CURRENT_TIMESTAMP' }), + 'WHERE matrix_user_id =', + param(matrixUserId), ]); } /** * Returns a mapping of matrix user id to session room id for all known sessions. */ -export async function fetchAllSessionRooms( +export async function fetchRealmSessionRooms( dbAdapter: DBAdapter, realmURL: string, - realmUserId: string, ) { let rows = await query(dbAdapter, [ - 'SELECT sr.matrix_user_id, sr.room_id', - 'FROM session_rooms sr', + 'SELECT u.matrix_user_id, u.session_room_id', + 'FROM users u', 'JOIN realm_user_permissions rup', - 'ON rup.username = sr.matrix_user_id', + 'ON rup.username = u.matrix_user_id', 'WHERE rup.realm_url =', param(realmURL), 'AND (rup.read = true OR rup.write = true)', - 'AND sr.realm_user_id =', - param(realmUserId), - 'AND sr.realm_url =', - param(REALM_SERVER_REALM), + 'AND u.session_room_id IS NOT NULL', ]); let result: Record = {}; for (let row of rows) { - if (row.matrix_user_id && row.room_id) { - result[row.matrix_user_id as string] = row.room_id as string; + if (row.matrix_user_id && row.session_room_id) { + result[row.matrix_user_id as string] = row.session_room_id as string; } } return result; } - -export async function clearSessionRooms(dbAdapter: DBAdapter) { - await query(dbAdapter, ['DELETE FROM session_rooms']); -} diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 7ffc35784e3..b0475bb990b 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -680,21 +680,12 @@ export class Realm { } async ensureSessionRoom(matrixUserId: string): Promise { - let sessionRoom = await fetchSessionRoom( - this.#dbAdapter, - this.#matrixClientUserId, - matrixUserId, - ); + let sessionRoom = await fetchSessionRoom(this.#dbAdapter, matrixUserId); if (!sessionRoom) { await this.#matrixClient.login(); sessionRoom = await this.#matrixClient.createDM(matrixUserId); - await upsertSessionRoom( - this.#dbAdapter, - this.#matrixClientUserId, - matrixUserId, - sessionRoom, - ); + await upsertSessionRoom(this.#dbAdapter, matrixUserId, sessionRoom); } return sessionRoom; From 5ada8be35c67621a87ff2adad2ce5fc35aa04665 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 16:28:14 +0000 Subject: [PATCH 32/48] Restore realm bot user for published realms --- .../handlers/handle-publish-realm.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 5f7529e821d..710932a9ea5 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -30,6 +30,8 @@ import { import { createJWT } from '../jwt'; import type { CreateRoutesArgs } from '../routes'; import type { RealmServerTokenClaim } from '../utils/jwt'; +import { registerUser } from '../synapse'; +import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client'; const log = logger('handle-publish'); @@ -126,11 +128,13 @@ function rewriteHostHomeForPublishedRealm( export default function handlePublishRealm({ dbAdapter, + matrixClient, realmSecretSeed, serverURL, virtualNetwork, realms, realmsRootPath, + getMatrixRegistrationSecret, createAndMountRealm, domainsForPublishedRealms, }: CreateRoutesArgs): (ctxt: Koa.Context, next: Koa.Next) => Promise { @@ -280,6 +284,7 @@ export default function handlePublishRealm({ ); let userId; + let realmUsername; let publishedRealmData: PublishedRealmTable | undefined; if (existingPublishedRealm) { let results = (await query(dbAdapter, [ @@ -294,6 +299,7 @@ export default function handlePublishRealm({ | 'last_published_at' >[]; publishedRealmData = results[0]; + realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmData.id}`; let lastPublishedAt = Date.now().toString(); await query(dbAdapter, [ @@ -305,9 +311,10 @@ export default function handlePublishRealm({ publishedRealmData.last_published_at = lastPublishedAt; } else { let publishedRealmId = uuidv4(); + realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmId}`; let { valueExpressions, nameExpressions } = asExpressions({ id: publishedRealmId, - owner_username: 'NONE', + owner_username: realmUsername, source_realm_url: sourceRealmURL, published_realm_url: publishedRealmURL, last_published_at: Date.now().toString(), @@ -325,7 +332,18 @@ export default function handlePublishRealm({ | 'last_published_at' >[]; publishedRealmData = results[0]; + + let { userId: newUserId } = await registerUser({ + matrixURL: matrixClient.matrixURL, + displayname: realmUsername, + username: realmUsername, + password: await passwordFromSeed(realmUsername, realmSecretSeed), + registrationSecret: await getMatrixRegistrationSecret(), + }); + userId = newUserId; + await insertPermissions(dbAdapter, new URL(publishedRealmURL), { + [userId]: ['read', 'realm-owner'], [ownerUserId]: ['read', 'realm-owner'], '*': ['read'], }); From d676caa92624f2f954502a5b013b9f267307ce3e Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 16:29:03 +0000 Subject: [PATCH 33/48] Require realm urls in events, add new ones for file watching --- packages/base/matrix-event.gts | 20 ++++++++++----- packages/realm-server/node-realm.ts | 4 +-- packages/realm-server/tests/helpers/index.ts | 5 +--- packages/runtime-common/realm.ts | 27 ++++++++++++-------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/packages/base/matrix-event.gts b/packages/base/matrix-event.gts index 49f9a29d99f..90c415b687a 100644 --- a/packages/base/matrix-event.gts +++ b/packages/base/matrix-event.gts @@ -401,27 +401,27 @@ export interface IncrementalIndexEventContent { indexType: 'incremental'; invalidations: string[]; clientRequestId?: string | null; - realmURL?: string; + realmURL: string; } interface FullIndexEventContent { eventName: 'index'; indexType: 'full'; - realmURL?: string; + realmURL: string; } interface CopiedIndexEventContent { eventName: 'index'; indexType: 'copy'; sourceRealmURL: string; - realmURL?: string; + realmURL: string; } export interface IncrementalIndexInitiationContent { eventName: 'index'; indexType: 'incremental-index-initiation'; updatedFile: string; - realmURL?: string; + realmURL: string; } export type UpdateRealmEventContent = @@ -432,21 +432,27 @@ export type UpdateRealmEventContent = export interface FileAddedEventContent { eventName: 'update'; added: string; - realmURL?: string; + realmURL: string; } export interface FileUpdatedEventContent { eventName: 'update'; updated: string; - realmURL?: string; + realmURL: string; } export interface FileRemovedEventContent { eventName: 'update'; removed: string; - realmURL?: string; + realmURL: string; } +// File watcher events don't include realmURL - it gets added by the Realm +export type FileWatcherEventContent = + | Omit + | Omit + | Omit; + export interface StopGeneratingEvent extends BaseMatrixEvent { type: typeof APP_BOXEL_STOP_GENERATING_EVENT_TYPE; } diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index b319b9c03df..b4bdab161ab 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -35,8 +35,8 @@ import type { AdapterWriteResult, } from '@cardstack/runtime-common/realm'; import type { + FileWatcherEventContent, RealmEventContent, - UpdateRealmEventContent, } from 'https://cardstack.com/base/matrix-event'; import { APP_BOXEL_REALM_EVENT_TYPE } from '@cardstack/runtime-common/matrix-constants'; import { createJWT, verifyJWT } from './jwt'; @@ -80,7 +80,7 @@ export class NodeAdapter implements RealmAdapter { private watcher: Watcher | undefined = undefined; async subscribe( - cb: (message: UpdateRealmEventContent) => void, + cb: (message: FileWatcherEventContent) => void, ): Promise { if (this.watcher) { throw new Error(`tried to subscribe to watcher twice`); diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 33cb18f4d70..a07cbcbff3d 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -33,7 +33,6 @@ import { RealmPaths, PUBLISHED_DIRECTORY_NAME, DEFAULT_CARD_SIZE_LIMIT_BYTES, - clearSessionRooms, type MatrixConfig, type QueuePublisher, type QueueRunner, @@ -381,9 +380,6 @@ export function setupDB( if (runner) { trackedQueueRunners.delete(runner); } - if (dbAdapter) { - await clearSessionRooms(dbAdapter); - } await dbAdapter?.close(); if (dbAdapter) { trackedDbAdapters.delete(dbAdapter); @@ -864,6 +860,7 @@ export async function insertUser( matrixUserId: result[0].matrix_user_id, stripeCustomerId: result[0].stripe_customer_id, stripeCustomerEmail: result[0].stripe_customer_email, + sessionRoomId: result[0].session_room_id ?? null, } as User; } diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index b0475bb990b..43506096e14 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -131,6 +131,7 @@ import type { Utils } from './matrix-backend-authentication'; import { MatrixBackendAuthentication } from './matrix-backend-authentication'; import type { + FileWatcherEventContent, RealmEventContent, UpdateRealmEventContent, } from 'https://cardstack.com/base/matrix-event'; @@ -356,7 +357,7 @@ export interface RealmAdapter { fileWatcherEnabled: boolean; - subscribe(cb: (message: UpdateRealmEventContent) => void): Promise; + subscribe(cb: (message: FileWatcherEventContent) => void): Promise; unsubscribe(): void; @@ -860,6 +861,7 @@ export class Realm { indexType: 'incremental', invalidations: [...invalidations], clientRequestId, + realmURL: this.url, }); return results.map(({ path, lastModified }) => ({ path, @@ -1181,7 +1183,7 @@ export class Realm { } private getTrackedWrite( - data: UpdateRealmEventContent, + data: FileWatcherEventContent, ): { isTracked: boolean; url: URL } | undefined { let file: string; let type: string | undefined; @@ -1229,6 +1231,7 @@ export class Realm { eventName: 'index', indexType: 'incremental', invalidations: invalidatedURLs.map((u) => u.href), + realmURL: this.url, }); }, }); @@ -1263,6 +1266,7 @@ export class Realm { eventName: 'index', indexType: 'incremental', invalidations: invalidatedURLs.map((u) => u.href), + realmURL: this.url, }); }, }); @@ -1283,6 +1287,7 @@ export class Realm { this.broadcastRealmEvent({ eventName: 'index', indexType: 'full', + realmURL: this.url, }); } @@ -1295,6 +1300,7 @@ export class Realm { eventName: 'index', indexType: 'copy', sourceRealmURL: this.#copiedFromRealm.href, + realmURL: this.url, }); } else { let isNewIndex = await this.#realmIndexUpdater.isNewIndex(); @@ -1311,6 +1317,7 @@ export class Realm { this.broadcastRealmEvent({ eventName: 'index', indexType: 'full', + realmURL: this.url, }); } } @@ -1359,6 +1366,8 @@ export class Realm { return userId; } // hard coded test URLs + + // TODO::`( this should be removed. if ((globalThis as any).__environment === 'test') { let url = new URL(this.url); if (url.hostname === '127.0.0.1') { @@ -1428,13 +1437,6 @@ export class Realm { }, ensureSessionRoom: async (userId: string) => this.ensureSessionRoom(userId), - setSessionRoom: (userId: string, roomId: string) => - upsertSessionRoom( - this.#dbAdapter, - this.#matrixClientUserId, - userId, - roomId, - ), } as Utils, ); @@ -4281,7 +4283,10 @@ export class Realm { await this.#definitionLookup.invalidate(tracked.url.href); } - this.broadcastRealmEvent(data); + this.broadcastRealmEvent({ + ...data, + realmURL: this.url, + } as UpdateRealmEventContent); this.#updateItems.push({ operation: ('added' in data ? 'add' @@ -4313,6 +4318,7 @@ export class Realm { eventName: 'index', indexType: 'incremental', invalidations: invalidatedURLs.map((u) => u.href), + realmURL: this.url, }); }, ...(operation === 'removed' ? { delete: true } : {}), @@ -4326,6 +4332,7 @@ export class Realm { eventName: 'index', indexType: 'incremental-index-initiation', updatedFile, + realmURL: this.url, }); } From ce8f3d3d6db7ae9c89e0fa48eb48c313a8c2b3e1 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 16:29:21 +0000 Subject: [PATCH 34/48] Event test updates --- packages/host/tests/helpers/adapter.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 3cd13eef2c8..27ce550e568 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -30,8 +30,8 @@ import type { import type { FileAddedEventContent, FileUpdatedEventContent, + FileWatcherEventContent, RealmEventContent, - UpdateRealmEventContent, } from 'https://cardstack.com/base/matrix-event'; import { WebMessageStream, messageCloseHandler } from './stream'; @@ -66,7 +66,9 @@ export class TestRealmAdapter implements RealmAdapter { #files: Dir = { kind: 'directory', contents: {} }; #lastModified: Map = new Map(); #paths: RealmPaths; - #subscriber: ((message: UpdateRealmEventContent) => void) | undefined; + #subscriber: + | ((message: FileWatcherEventContent) => void) + | undefined; #loader: Loader | undefined; // Will be set in the realm's constructor - needed for openFile for shimming purposes #ready = new Deferred(); #potentialModulesAndInstances: { content: any; url: URL }[] = []; @@ -348,7 +350,7 @@ export class TestRealmAdapter implements RealmAdapter { }; } - postUpdateEvent(data: UpdateRealmEventContent) { + postUpdateEvent(data: FileWatcherEventContent) { this.#subscriber?.(data); } @@ -444,7 +446,7 @@ export class TestRealmAdapter implements RealmAdapter { } async subscribe( - cb: (message: UpdateRealmEventContent) => void, + cb: (message: FileWatcherEventContent) => void, ): Promise { this.#subscriber = cb; } From 1a4c9dcbbac1b0db09689632166144b8bc4fbecb Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 16:29:36 +0000 Subject: [PATCH 35/48] Update session room work in tests --- packages/realm-server/tests/realm-auth-test.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/realm-server/tests/realm-auth-test.ts b/packages/realm-server/tests/realm-auth-test.ts index a1eeae582f5..122a7ed7fb3 100644 --- a/packages/realm-server/tests/realm-auth-test.ts +++ b/packages/realm-server/tests/realm-auth-test.ts @@ -12,7 +12,6 @@ import { insertUser, realmSecretSeed, testRealmHref, - testRealmServerMatrixUserId, } from './helpers'; import { createJWT as createRealmServerJWT } from '../utils/jwt'; @@ -53,11 +52,7 @@ module(basename(__filename), function () { }); sinon.stub(MatrixClient.prototype, 'joinRoom').resolves(); - let existingRoom = await fetchSessionRoom( - dbAdapter, - testRealmServerMatrixUserId, - matrixUserId, - ); + let existingRoom = await fetchSessionRoom(dbAdapter, matrixUserId); assert.strictEqual( existingRoom, null, @@ -88,11 +83,7 @@ module(basename(__filename), function () { 'realm created the DM room for the requesting user', ); - let sessionRoom = await fetchSessionRoom( - dbAdapter, - testRealmServerMatrixUserId, - matrixUserId, - ); + let sessionRoom = await fetchSessionRoom(dbAdapter, matrixUserId); assert.strictEqual( sessionRoom, expectedRoomId, From 9c7ef141a59d80f3f559c78c8e60af2bbe7fd286 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 17:37:29 +0000 Subject: [PATCH 36/48] Require that sessions are only created for users that exist and that users are created in the test setup --- packages/realm-server/tests/helpers/index.ts | 18 ++++++++++++++++++ .../db-queries/session-room-queries.ts | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index a07cbcbff3d..ca7f763d942 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -465,6 +465,12 @@ export async function createRealm({ }): Promise<{ realm: Realm; adapter: RealmAdapter }> { await insertPermissions(dbAdapter, new URL(realmURL), permissions); + for (let username of Object.keys(permissions)) { + if (username !== '*') { + await ensureTestUser(dbAdapter, username); + } + } + for (let [filename, contents] of Object.entries(fileSystem)) { if (typeof contents === 'string') { writeFileSync(join(dir, filename), contents); @@ -668,6 +674,7 @@ export async function runTestRealmServerWithRealms({ }; }) { ensureDirSync(realmsRootPath); + let prerenderer = await getTestPrerenderer(); let definitionLookup = new CachingDefinitionLookup( dbAdapter, @@ -864,6 +871,16 @@ export async function insertUser( } as User; } +export async function ensureTestUser( + dbAdapter: PgAdapter, + matrixUserId: string, +) { + await dbAdapter.execute( + `INSERT INTO users (matrix_user_id) VALUES ($1) ON CONFLICT (matrix_user_id) DO NOTHING`, + { bind: [matrixUserId] }, + ); +} + export async function insertPlan( dbAdapter: PgAdapter, name: string, @@ -1025,6 +1042,7 @@ export function setupMatrixRoom( let payload = JSON.parse( Buffer.from(jwt.split('.')[1], 'base64').toString('utf8'), ) as { sessionRoom: string }; + console.log('Session room', payload.sessionRoom); let { joined_rooms: rooms } = await matrixClient.getJoinedRooms(); diff --git a/packages/runtime-common/db-queries/session-room-queries.ts b/packages/runtime-common/db-queries/session-room-queries.ts index 2bca2541dfe..7b03afe84bd 100644 --- a/packages/runtime-common/db-queries/session-room-queries.ts +++ b/packages/runtime-common/db-queries/session-room-queries.ts @@ -23,18 +23,26 @@ export async function fetchSessionRoom( /** * Updates the session room id for the given matrix user. + * Throws if the user does not exist in the users table. */ export async function upsertSessionRoom( dbAdapter: DBAdapter, matrixUserId: string, roomId: string, ) { - await query(dbAdapter, [ + let rows = await query(dbAdapter, [ 'UPDATE users SET session_room_id =', param(roomId), 'WHERE matrix_user_id =', param(matrixUserId), + 'RETURNING id', ]); + + if (rows.length === 0) { + throw new Error( + `Cannot set session room for user ${matrixUserId}: user does not exist in the users table`, + ); + } } /** From ed163c71e4893efe52bd24128e9b6f0dee4cb192 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 18:00:19 +0000 Subject: [PATCH 37/48] Update schema --- .../schema/{1770648743000_schema.sql => 1771000000000_schema.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/host/config/schema/{1770648743000_schema.sql => 1771000000000_schema.sql} (100%) diff --git a/packages/host/config/schema/1770648743000_schema.sql b/packages/host/config/schema/1771000000000_schema.sql similarity index 100% rename from packages/host/config/schema/1770648743000_schema.sql rename to packages/host/config/schema/1771000000000_schema.sql From 1fc0b8c377292b6e3e4b2f37ade90892fe71681a Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 18:03:08 +0000 Subject: [PATCH 38/48] Can't have too many 0s in your migration filename --- .../schema/{1771000000000_schema.sql => 1771264925000_schema.sql} | 0 ...om-to-users.js => 1771264925000_move-session-room-to-users.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/host/config/schema/{1771000000000_schema.sql => 1771264925000_schema.sql} (100%) rename packages/postgres/migrations/{1771000000000_move-session-room-to-users.js => 1771264925000_move-session-room-to-users.js} (100%) diff --git a/packages/host/config/schema/1771000000000_schema.sql b/packages/host/config/schema/1771264925000_schema.sql similarity index 100% rename from packages/host/config/schema/1771000000000_schema.sql rename to packages/host/config/schema/1771264925000_schema.sql diff --git a/packages/postgres/migrations/1771000000000_move-session-room-to-users.js b/packages/postgres/migrations/1771264925000_move-session-room-to-users.js similarity index 100% rename from packages/postgres/migrations/1771000000000_move-session-room-to-users.js rename to packages/postgres/migrations/1771264925000_move-session-room-to-users.js From f0ed61b5233efa045e98aa8f0a18f9cb8318ded0 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 21:00:53 +0000 Subject: [PATCH 39/48] Don't login without the user existing --- .../server-endpoints/stripe-session-test.ts | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts index 2c59ba8c5f1..17780b30504 100644 --- a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts +++ b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts @@ -7,14 +7,13 @@ import { getStripe } from '@cardstack/billing/stripe-webhook-handlers/stripe'; import type { PgAdapter } from '@cardstack/postgres'; import { getUserByMatrixUserId } from '@cardstack/billing/billing-queries'; import { + createJWT, insertPlan, insertUser, - realmSecretSeed, - realmServerTestMatrix, setupPermissionedRealm, } from '../helpers'; -import { createRealmServerSession } from './helpers'; import '@cardstack/runtime-common/helpers/code-equality-assertion'; +import { Realm } from '@cardstack/runtime-common'; module(`server-endpoints/${basename(__filename)}`, function () { module('Realm Server Endpoints (not specific to one realm)', function () { @@ -24,7 +23,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { let listSubscriptionsStub: sinon.SinonStub; let retrieveProductStub: sinon.SinonStub; let createBillingPortalSessionStub: sinon.SinonStub; - let matrixClient: MatrixClient; let userId = '@test_realm:localhost'; let jwtToken: string; let request: SuperTest; @@ -33,9 +31,11 @@ module(`server-endpoints/${basename(__filename)}`, function () { function onRealmSetup(args: { request: SuperTest; dbAdapter: PgAdapter; + testRealm: Realm; }) { request = args.request; dbAdapter = args.dbAdapter; + jwtToken = createJWT(args.testRealm, userId); } setupPermissionedRealm(hooks, { @@ -58,25 +58,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { stripe.billingPortal.sessions, 'create', ); - - matrixClient = new MatrixClient({ - matrixURL: realmServerTestMatrix.url, - username: 'test_realm', - seed: realmSecretSeed, - }); - await matrixClient.login(); - let { sessionRoom, jwt } = await createRealmServerSession( - matrixClient, - request, - ); - - let { joined_rooms: rooms } = await matrixClient.getJoinedRooms(); - - if (!rooms.includes(sessionRoom)) { - await matrixClient.joinRoom(sessionRoom); - } - - jwtToken = jwt; }); hooks.afterEach(async function () { From 822c36ca8ed46c95c1074f2b59743bd89f7184f5 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 21:31:40 +0000 Subject: [PATCH 40/48] Make sure users exist at the correct points in tests --- .../realm-server/tests/realm-auth-test.ts | 5 ---- .../server-endpoints/authentication-test.ts | 3 +++ .../tests/server-endpoints/info-test.ts | 2 -- .../search-prerendered-test.ts | 6 ----- .../tests/server-endpoints/search-test.ts | 8 ------- .../server-endpoints/stripe-webhook-test.ts | 24 ++++--------------- .../server-endpoints/user-and-catalog-test.ts | 2 +- .../realm-server/tests/types-endpoint-test.ts | 1 + 8 files changed, 9 insertions(+), 42 deletions(-) diff --git a/packages/realm-server/tests/realm-auth-test.ts b/packages/realm-server/tests/realm-auth-test.ts index 122a7ed7fb3..4bccbe75954 100644 --- a/packages/realm-server/tests/realm-auth-test.ts +++ b/packages/realm-server/tests/realm-auth-test.ts @@ -9,7 +9,6 @@ import { fetchSessionRoom } from '@cardstack/runtime-common/db-queries/session-r import { setupPermissionedRealm, - insertUser, realmSecretSeed, testRealmHref, } from './helpers'; @@ -33,10 +32,6 @@ module(basename(__filename), function () { }, }); - hooks.beforeEach(async function () { - await insertUser(dbAdapter, matrixUserId, 'cus_test', null); - }); - hooks.afterEach(function () { sinon.restore(); }); diff --git a/packages/realm-server/tests/server-endpoints/authentication-test.ts b/packages/realm-server/tests/server-endpoints/authentication-test.ts index 9b883336cb9..e2efe7cc90a 100644 --- a/packages/realm-server/tests/server-endpoints/authentication-test.ts +++ b/packages/realm-server/tests/server-endpoints/authentication-test.ts @@ -42,6 +42,9 @@ module(`server-endpoints/${basename(__filename)}`, function () { testRealmDir, realmsRootPath: join(dir.name, 'realm_server_5'), realmURL: testRealmURL, + permissions: { + test_realm: ['read', 'realm-owner'], + }, dbAdapter, publisher, runner, diff --git a/packages/realm-server/tests/server-endpoints/info-test.ts b/packages/realm-server/tests/server-endpoints/info-test.ts index 6c4975b0cf5..2b5c9fa8706 100644 --- a/packages/realm-server/tests/server-endpoints/info-test.ts +++ b/packages/realm-server/tests/server-endpoints/info-test.ts @@ -103,8 +103,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_info federates info across realms and includes public list header', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, diff --git a/packages/realm-server/tests/server-endpoints/search-prerendered-test.ts b/packages/realm-server/tests/server-endpoints/search-prerendered-test.ts index 476457323f0..9ad241f0174 100644 --- a/packages/realm-server/tests/server-endpoints/search-prerendered-test.ts +++ b/packages/realm-server/tests/server-endpoints/search-prerendered-test.ts @@ -17,7 +17,6 @@ import { closeServer, createVirtualNetwork, setupDB, - insertUser, matrixURL, realmSecretSeed, runTestRealmServerWithRealms, @@ -140,8 +139,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_search-prerendered federates results across realms', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, @@ -194,8 +191,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('GET /_search-prerendered returns 400 for unsupported method', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, @@ -294,7 +289,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_search-prerendered returns 400 for invalid query', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, diff --git a/packages/realm-server/tests/server-endpoints/search-test.ts b/packages/realm-server/tests/server-endpoints/search-test.ts index af9f8dcaa24..53f87fc74a5 100644 --- a/packages/realm-server/tests/server-endpoints/search-test.ts +++ b/packages/realm-server/tests/server-endpoints/search-test.ts @@ -18,7 +18,6 @@ import { closeServer, createVirtualNetwork, setupDB, - insertUser, matrixURL, realmSecretSeed, runTestRealmServerWithRealms, @@ -141,8 +140,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_search federates results across realms', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, @@ -184,8 +181,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_search supports query body', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, @@ -214,8 +209,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('GET /_search returns 400 for unsupported method', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); - let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, @@ -305,7 +298,6 @@ module(`server-endpoints/${basename(__filename)}`, function (_hooks) { }); test('QUERY /_search returns 400 for invalid query', async function (assert) { - await insertUser(dbAdapter, ownerUserId, 'stripe-test-user', null); let realmServerToken = createRealmServerJWT( { user: ownerUserId, sessionRoom: 'session-room-test' }, realmSecretSeed, diff --git a/packages/realm-server/tests/server-endpoints/stripe-webhook-test.ts b/packages/realm-server/tests/server-endpoints/stripe-webhook-test.ts index e731aceceb3..423330186be 100644 --- a/packages/realm-server/tests/server-endpoints/stripe-webhook-test.ts +++ b/packages/realm-server/tests/server-endpoints/stripe-webhook-test.ts @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { basename } from 'path'; import type { Test, SuperTest } from 'supertest'; -import type { Realm } from '@cardstack/runtime-common'; +import type { Realm, User } from '@cardstack/runtime-common'; import { Deferred } from '@cardstack/runtime-common'; import { MatrixClient } from '@cardstack/runtime-common/matrix-client'; import Stripe from 'stripe'; @@ -36,6 +36,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { let matrixClient: MatrixClient; let roomId: string; let userId = '@test_realm:localhost'; + let user: User; let originalLowCreditThreshold: string | undefined; let waitForBillingNotification = async function ( assert: Assert, @@ -78,6 +79,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { let stripe = getStripe(); createSubscriptionStub = sinon.stub(stripe.subscriptions, 'create'); fetchPriceListStub = sinon.stub(stripe.prices, 'list'); + user = await insertUser(dbAdapter, userId!, 'cus_123', 'user@test.com'); matrixClient = new MatrixClient({ matrixURL: realmServerTestMatrix.url, @@ -111,12 +113,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { test('subscribes user back to free plan when the current subscription is expired', async function (assert) { const secret = process.env.STRIPE_WEBHOOK_SECRET; - let user = await insertUser( - dbAdapter, - userId, - 'cus_123', - 'user@test.com', - ); let freePlan = await insertPlan( dbAdapter, 'Free plan', @@ -347,12 +343,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { test('ensures the current subscription expires when free plan subscription fails', async function (assert) { const secret = process.env.STRIPE_WEBHOOK_SECRET; - let user = await insertUser( - dbAdapter, - userId, - 'cus_123', - 'user@test.com', - ); await insertPlan(dbAdapter, 'Free plan', 0, 100, 'prod_free'); let creatorPlan = await insertPlan( dbAdapter, @@ -547,7 +537,6 @@ module(`server-endpoints/${basename(__filename)}`, function () { test('sends billing notification on invoice payment succeeded event', async function (assert) { const secret = process.env.STRIPE_WEBHOOK_SECRET; - await insertUser(dbAdapter, userId!, 'cus_123', 'user@test.com'); await insertPlan(dbAdapter, 'Free plan', 0, 100, 'prod_free'); if (!secret) { throw new Error('STRIPE_WEBHOOK_SECRET is not set'); @@ -600,12 +589,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { test('sends billing notification on checkout session completed event', async function (assert) { const secret = process.env.STRIPE_WEBHOOK_SECRET; - let user = await insertUser( - dbAdapter, - userId!, - 'cus_123', - 'user@test.com', - ); + await insertPlan(dbAdapter, 'Free plan', 0, 100, 'prod_free'); if (!secret) { throw new Error('STRIPE_WEBHOOK_SECRET is not set'); diff --git a/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts b/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts index ab0062d4265..605944e36ec 100644 --- a/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts +++ b/packages/realm-server/tests/server-endpoints/user-and-catalog-test.ts @@ -27,7 +27,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { }); test('can create a user', async function (assert) { - let ownerUserId = '@mango:localhost'; + let ownerUserId = '@mango-new:localhost'; let response = await context.request2 .post('/_user') .set('Accept', 'application/json') diff --git a/packages/realm-server/tests/types-endpoint-test.ts b/packages/realm-server/tests/types-endpoint-test.ts index e0e339d13ba..b8d56aa7213 100644 --- a/packages/realm-server/tests/types-endpoint-test.ts +++ b/packages/realm-server/tests/types-endpoint-test.ts @@ -73,6 +73,7 @@ module(basename(__filename), function () { setupPermissionedRealm(hooks, { permissions: { '*': ['read', 'write'], + '@node-test_realm:localhost': ['read', 'write', 'realm-owner'], }, realmURL, onRealmSetup, From 5418d39849184bc0669917a4011661da45fc013e Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 21:54:50 +0000 Subject: [PATCH 41/48] Add user in CLI tests --- .../tests/helpers/start-test-realm.ts | 42 ++++++++++++++++++- .../tests/integration-test.ts | 4 ++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/workspace-sync-cli/tests/helpers/start-test-realm.ts b/packages/workspace-sync-cli/tests/helpers/start-test-realm.ts index e019b43cf19..36a8ebd25e5 100644 --- a/packages/workspace-sync-cli/tests/helpers/start-test-realm.ts +++ b/packages/workspace-sync-cli/tests/helpers/start-test-realm.ts @@ -9,6 +9,7 @@ export interface TestRealmServer { realmProcess: ChildProcess; workerProcess: ChildProcess; stop: () => Promise; + executeSQL: (sql: string) => Promise[]>; } export async function startTestRealmServer( @@ -81,7 +82,6 @@ export async function startTestRealmServer( } }); }); - // Start worker manager first const workerArgs = [ '--transpileOnly', @@ -214,6 +214,30 @@ export async function startTestRealmServer( }); }); + let sqlResults: ((results: string) => void) | undefined; + let sqlError: ((error: string) => void) | undefined; + + realmProcess.on('message', (message) => { + if (typeof message === 'string' && message.startsWith('sql-results:')) { + let results = message.substring('sql-results:'.length); + if (!sqlResults) { + console.error(`received unprompted SQL: ${results}`); + return; + } + sqlResults(results); + } else if ( + typeof message === 'string' && + message.startsWith('sql-error:') + ) { + let error = message.substring('sql-error:'.length); + if (!sqlError) { + console.error(`received unprompted SQL error: ${error}`); + return; + } + sqlError(error); + } + }); + // Create stop function const stop = async () => { const realmServerStopped = new Promise((resolve) => { @@ -244,8 +268,22 @@ export async function startTestRealmServer( prerenderServer.close(() => resolve()), ); }; + const executeSQL = async (sql: string): Promise[]> => { + let execute = new Promise( + (resolve, reject: (reason: string) => void) => { + sqlResults = resolve; + sqlError = reject; + }, + ); + console.log('Executing SQL in realm server:', sql); + realmProcess.send(`execute-sql:${sql}`); + let resultsStr = await execute; + sqlResults = undefined; + sqlError = undefined; + return JSON.parse(resultsStr); + }; - return { realmProcess, workerProcess, stop }; + return { realmProcess, workerProcess, stop, executeSQL }; } export async function waitForServer( diff --git a/packages/workspace-sync-cli/tests/integration-test.ts b/packages/workspace-sync-cli/tests/integration-test.ts index 08d18ad826c..a61d2c7a3a8 100644 --- a/packages/workspace-sync-cli/tests/integration-test.ts +++ b/packages/workspace-sync-cli/tests/integration-test.ts @@ -172,6 +172,9 @@ module('Workspace Sync CLI Integration Tests', function (hooks) { console.error('❌ Failed to start shared realm server:', error); throw error; } + await sharedRealmServer.executeSQL( + `INSERT INTO users (matrix_user_id) VALUES ('@test_realm:localhost') ON CONFLICT (matrix_user_id) DO NOTHING`, + ); }); hooks.after(async function () { @@ -203,6 +206,7 @@ module('Workspace Sync CLI Integration Tests', function (hooks) { // Reset realm content between tests (safely) await clearRealmContent(sharedRealmDir); await createRealmContent(sharedRealmDir); + console.log('✅ Test environment is ready!\n'); }); hooks.afterEach(async function () { From c088fa72618462810ec753e87ade5b319557bef0 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 21:56:35 +0000 Subject: [PATCH 42/48] Specify username --- .../realm-server/tests/server-endpoints/authentication-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/realm-server/tests/server-endpoints/authentication-test.ts b/packages/realm-server/tests/server-endpoints/authentication-test.ts index e2efe7cc90a..69e0d03b9c6 100644 --- a/packages/realm-server/tests/server-endpoints/authentication-test.ts +++ b/packages/realm-server/tests/server-endpoints/authentication-test.ts @@ -43,7 +43,7 @@ module(`server-endpoints/${basename(__filename)}`, function () { realmsRootPath: join(dir.name, 'realm_server_5'), realmURL: testRealmURL, permissions: { - test_realm: ['read', 'realm-owner'], + '@test_realm:localhost': ['read', 'realm-owner'], }, dbAdapter, publisher, From 18a8d61a4d763ef9d6b243b6ddfc00fe1872d00e Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Mon, 16 Feb 2026 22:01:53 +0000 Subject: [PATCH 43/48] Linting --- .../realm-server/tests/server-endpoints/stripe-session-test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts index 17780b30504..589db3165f7 100644 --- a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts +++ b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts @@ -1,7 +1,6 @@ import { module, test } from 'qunit'; import { basename } from 'path'; import type { Test, SuperTest } from 'supertest'; -import { MatrixClient } from '@cardstack/runtime-common/matrix-client'; import sinon from 'sinon'; import { getStripe } from '@cardstack/billing/stripe-webhook-handlers/stripe'; import type { PgAdapter } from '@cardstack/postgres'; From abfe92976813744f9baaadbce643f99549adab8a Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 17 Feb 2026 14:34:46 +0000 Subject: [PATCH 44/48] Only create dm rooms for users that exist in the table already --- .../handlers/handle-create-session.ts | 6 ++++++ .../runtime-common/db-queries/user-queries.ts | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/realm-server/handlers/handle-create-session.ts b/packages/realm-server/handlers/handle-create-session.ts index 840adbf7a49..7b5589fcf12 100644 --- a/packages/realm-server/handlers/handle-create-session.ts +++ b/packages/realm-server/handlers/handle-create-session.ts @@ -3,6 +3,7 @@ import { logger, SupportedMimeType, upsertSessionRoom, + userExists, } from '@cardstack/runtime-common'; import type { Utils } from '@cardstack/runtime-common/matrix-backend-authentication'; import { MatrixBackendAuthentication } from '@cardstack/runtime-common/matrix-backend-authentication'; @@ -44,6 +45,11 @@ export default function handleCreateSessionRequest({ let sessionRoom = await fetchSessionRoom(dbAdapter, userId); if (!sessionRoom) { + let userExistsInDB = await userExists(dbAdapter, userId); + if (!userExistsInDB) { + // TODO: should we create it if it doesn't exist? + return undefined; + } sessionRoom = await matrixClient.createDM(userId); await upsertSessionRoom(dbAdapter, userId, sessionRoom); } diff --git a/packages/runtime-common/db-queries/user-queries.ts b/packages/runtime-common/db-queries/user-queries.ts index b31d56e434d..8ea1ab74b5e 100644 --- a/packages/runtime-common/db-queries/user-queries.ts +++ b/packages/runtime-common/db-queries/user-queries.ts @@ -1,6 +1,6 @@ import type { DBAdapter } from '../db'; -import { query, asExpressions, insert } from '../expression'; +import { query, asExpressions, insert, param } from '../expression'; import type { User } from './db-types'; export async function insertUser( @@ -20,3 +20,16 @@ export async function insertUser( return result[0] as unknown as User; } + +export async function userExists( + dbAdapter: DBAdapter, + matrixUserId: string, +): Promise { + let [row] = await query(dbAdapter, [ + 'SELECT EXISTS (SELECT 1 FROM users WHERE matrix_user_id =', + param(matrixUserId), + ') AS user_exists', + ]); + + return Boolean(row.user_exists); +} From 289cf14ced75b25a9abe7c31f1ab0aa351701272 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 17 Feb 2026 15:16:44 +0000 Subject: [PATCH 45/48] Linting --- packages/host/tests/acceptance/query-fields-test.gts | 4 ++-- packages/host/tests/helpers/adapter.ts | 8 ++------ .../integration/message-service-subscription-test.gts | 2 +- packages/realm-server/tests/server-endpoints/info-test.ts | 1 - .../tests/server-endpoints/stripe-session-test.ts | 2 +- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/host/tests/acceptance/query-fields-test.gts b/packages/host/tests/acceptance/query-fields-test.gts index b80ecf1a986..bc017b544b1 100644 --- a/packages/host/tests/acceptance/query-fields-test.gts +++ b/packages/host/tests/acceptance/query-fields-test.gts @@ -361,7 +361,7 @@ module( 'no query runs while hydrating server-provided results', ); - let realmMatrixUsername = testRealmInfo.realmUserId; + let realmMatrixUsername = testRealmInfo.realmUserId!; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, '@testuser:localhost', @@ -477,7 +477,7 @@ module( (store as any).store.sweep(cardAPI); await settled(); - let realmMatrixUsername = testRealmInfo.realmUserId; + let realmMatrixUsername = testRealmInfo.realmUserId!; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, '@testuser:localhost', diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 27ce550e568..5a45814004a 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -28,8 +28,6 @@ import type { } from '@cardstack/runtime-common/realm'; import type { - FileAddedEventContent, - FileUpdatedEventContent, FileWatcherEventContent, RealmEventContent, } from 'https://cardstack.com/base/matrix-event'; @@ -66,9 +64,7 @@ export class TestRealmAdapter implements RealmAdapter { #files: Dir = { kind: 'directory', contents: {} }; #lastModified: Map = new Map(); #paths: RealmPaths; - #subscriber: - | ((message: FileWatcherEventContent) => void) - | undefined; + #subscriber: ((message: FileWatcherEventContent) => void) | undefined; #loader: Loader | undefined; // Will be set in the realm's constructor - needed for openFile for shimming purposes #ready = new Deferred(); #potentialModulesAndInstances: { content: any; url: URL }[] = []; @@ -315,7 +311,7 @@ export class TestRealmAdapter implements RealmAdapter { ); } - let updateEvent: FileAddedEventContent | FileUpdatedEventContent; + let updateEvent: FileWatcherEventContent; let lastModified = unixTime(Date.now()); this.#lastModified.set(this.#paths.fileURL(path).href, lastModified); diff --git a/packages/host/tests/integration/message-service-subscription-test.gts b/packages/host/tests/integration/message-service-subscription-test.gts index b2bbcc26c8a..41875b9283d 100644 --- a/packages/host/tests/integration/message-service-subscription-test.gts +++ b/packages/host/tests/integration/message-service-subscription-test.gts @@ -45,7 +45,7 @@ module('Integration | message service subscription', function (hooks) { autostart: true, }); - let realmMatrixUsername = testRealmInfo.realmUserId; + let realmMatrixUsername = testRealmInfo.realmUserId!; let realmRoomId = mockMatrixUtils.getRoomIdForRealmAndUser( testRealmURL, diff --git a/packages/realm-server/tests/server-endpoints/info-test.ts b/packages/realm-server/tests/server-endpoints/info-test.ts index 2b5c9fa8706..61cf7c57877 100644 --- a/packages/realm-server/tests/server-endpoints/info-test.ts +++ b/packages/realm-server/tests/server-endpoints/info-test.ts @@ -14,7 +14,6 @@ import { closeServer, createVirtualNetwork, setupDB, - insertUser, matrixURL, realmSecretSeed, runTestRealmServerWithRealms, diff --git a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts index 589db3165f7..b63132a3d95 100644 --- a/packages/realm-server/tests/server-endpoints/stripe-session-test.ts +++ b/packages/realm-server/tests/server-endpoints/stripe-session-test.ts @@ -12,7 +12,7 @@ import { setupPermissionedRealm, } from '../helpers'; import '@cardstack/runtime-common/helpers/code-equality-assertion'; -import { Realm } from '@cardstack/runtime-common'; +import type { Realm } from '@cardstack/runtime-common'; module(`server-endpoints/${basename(__filename)}`, function () { module('Realm Server Endpoints (not specific to one realm)', function () { From 9086d4fe13df71014fe2e8589375078fa1d76965 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Tue, 17 Feb 2026 20:16:55 +0000 Subject: [PATCH 46/48] Only create session rooms when users exist for now --- packages/runtime-common/realm.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 43506096e14..716a180a1c7 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -149,6 +149,7 @@ import { fetchSessionRoom, upsertSessionRoom, } from './db-queries/session-room-queries'; +import { userExists } from './db-queries/user-queries'; import { analyzeRealmPublishability, type PublishabilityViolation, @@ -289,7 +290,7 @@ async function computeContentHashFromRef( export interface TokenClaims { user: string; realm: string; - sessionRoom: string; + sessionRoom: string | undefined; // TODO: remove when we create users on demand in ensureSessionRoom permissions: RealmPermissions['user']; realmServerURL: string; } @@ -680,11 +681,16 @@ export class Realm { await this.#matrixClient.login(); } - async ensureSessionRoom(matrixUserId: string): Promise { + async ensureSessionRoom(matrixUserId: string): Promise { let sessionRoom = await fetchSessionRoom(this.#dbAdapter, matrixUserId); if (!sessionRoom) { await this.#matrixClient.login(); + let userExistsInDB = await userExists(this.#dbAdapter, matrixUserId); + if (!userExistsInDB) { + // TODO: should we create it if it doesn't exist? + return undefined; + } sessionRoom = await this.#matrixClient.createDM(matrixUserId); await upsertSessionRoom(this.#dbAdapter, matrixUserId, sessionRoom); } From 5b3d296aad96c93ef1b945151b0ea95f5acd4634 Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Thu, 19 Feb 2026 15:23:21 +0000 Subject: [PATCH 47/48] Don't remove the sessions table --- ...771264925000_move-session-room-to-users.js | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/packages/postgres/migrations/1771264925000_move-session-room-to-users.js b/packages/postgres/migrations/1771264925000_move-session-room-to-users.js index c0967080908..e902c78d019 100644 --- a/packages/postgres/migrations/1771264925000_move-session-room-to-users.js +++ b/packages/postgres/migrations/1771264925000_move-session-room-to-users.js @@ -15,37 +15,5 @@ exports.up = (pgm) => { }; exports.down = (pgm) => { - pgm.createTable( - 'session_rooms', - { - realm_url: { type: 'varchar', notNull: true }, - realm_user_id: { type: 'varchar' }, - matrix_user_id: { type: 'varchar', notNull: true }, - room_id: { type: 'varchar', notNull: true }, - created_at: { - type: 'timestamp', - notNull: true, - default: pgm.func('current_timestamp'), - }, - updated_at: { - type: 'timestamp', - notNull: true, - default: pgm.func('current_timestamp'), - }, - }, - { - constraints: { - primaryKey: ['realm_url', 'matrix_user_id'], - }, - }, - ); - - pgm.sql(` - INSERT INTO session_rooms (realm_url, matrix_user_id, room_id) - SELECT '__realm-server__', matrix_user_id, session_room_id - FROM users - WHERE session_room_id IS NOT NULL - `); - pgm.dropColumns('users', ['session_room_id']); }; From daa217a00c56ac3f05c4cb1ca831bf589195183d Mon Sep 17 00:00:00 2001 From: Ian Calvert Date: Thu, 19 Feb 2026 15:24:34 +0000 Subject: [PATCH 48/48] Delete packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js --- .../1770648743000_add-realm-user-id-to-session-rooms.js | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js diff --git a/packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js b/packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js deleted file mode 100644 index f28057745f5..00000000000 --- a/packages/postgres/migrations/1770648743000_add-realm-user-id-to-session-rooms.js +++ /dev/null @@ -1,9 +0,0 @@ -exports.up = (pgm) => { - pgm.addColumns('session_rooms', { - realm_user_id: { type: 'varchar' }, - }); -}; - -exports.down = (pgm) => { - pgm.dropColumns('session_rooms', ['realm_user_id']); -};