diff --git a/matrix/api.js b/matrix/api.js index 5bbafffb..74357d49 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -121,7 +121,8 @@ async function sendState(roomID, type, stateKey, content, mxid) { assert.ok(type) assert.ok(typeof stateKey === "string") /** @type {Ty.R.EventSent} */ - const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/state/${type}/${stateKey}`, mxid), content) + // encodeURIComponent is necessary because state key can contain some special characters like / but you must encode them so they fit in a single component of the URI + const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/state/${type}/${encodeURIComponent(stateKey)}`, mxid), content) return root.event_id } diff --git a/matrix/kstate.js b/matrix/kstate.js index e8402543..e37fb963 100644 --- a/matrix/kstate.js +++ b/matrix/kstate.js @@ -19,9 +19,10 @@ function kstateToState(kstate) { const events = [] kstateStripConditionals(kstate) for (const [k, content] of Object.entries(kstate)) { - const [type, state_key] = k.split("/") - assert.ok(typeof type === "string") - assert.ok(typeof state_key === "string") + const slashIndex = k.indexOf("/") + assert(slashIndex > 0) + const type = k.slice(0, slashIndex) + const state_key = k.slice(slashIndex + 1) events.push({type, state_key, content}) } return events @@ -43,7 +44,7 @@ function diffKState(actual, target) { const diff = {} // go through each key that it should have for (const key of Object.keys(target)) { - if (!key.includes("/")) throw new Error(`target kstate's key "${key}" does not contain a slash separator; if a blank state_key was intended, add a trailing slash to the kstate key.`) + if (!key.includes("/")) throw new Error(`target kstate's key "${key}" does not contain a slash separator; if a blank state_key was intended, add a trailing slash to the kstate key.\ncontext: ${JSON.stringify(target)}`) if (key === "m.room.power_levels/") { // Special handling for power levels, we want to deep merge the actual and target into the final state. diff --git a/matrix/kstate.test.js b/matrix/kstate.test.js index 11d51312..7ab52db8 100644 --- a/matrix/kstate.test.js +++ b/matrix/kstate.test.js @@ -23,7 +23,8 @@ test("kstate strip: keeps true conditions while removing $if", t => { test("kstate2state: general", t => { t.deepEqual(kstateToState({ "m.room.name/": {name: "test name"}, - "m.room.member/@cadence:cadence.moe": {membership: "join"} + "m.room.member/@cadence:cadence.moe": {membership: "join"}, + "uk.half-shot.bridge/org.matrix.appservice-irc://irc/epicord.net/#general": {creator: "@cadence:cadence.moe"} }), [ { type: "m.room.name", @@ -38,6 +39,13 @@ test("kstate2state: general", t => { content: { membership: "join" } + }, + { + type: "uk.half-shot.bridge", + state_key: "org.matrix.appservice-irc://irc/epicord.net/#general", + content: { + creator: "@cadence:cadence.moe" + } } ]) }) @@ -57,10 +65,18 @@ test("state2kstate: general", t => { content: { membership: "join" } + }, + { + type: "uk.half-shot.bridge", + state_key: "org.matrix.appservice-irc://irc/epicord.net/#general", + content: { + creator: "@cadence:cadence.moe" + } } ]), { "m.room.name/": {name: "test name"}, - "m.room.member/@cadence:cadence.moe": {membership: "join"} + "m.room.member/@cadence:cadence.moe": {membership: "join"}, + "uk.half-shot.bridge/org.matrix.appservice-irc://irc/epicord.net/#general": {creator: "@cadence:cadence.moe"} }) })