From 35f68b32a56cd8071f951ba5daa88702bb1dbb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20M=C3=A4mecke?= Date: Tue, 20 Feb 2024 10:33:02 +0100 Subject: [PATCH] Improve ConnectSession argument --- lib/PortingEmbed/__tests__/index.test.tsx | 10 ++++++++- lib/PortingEmbed/index.tsx | 27 ++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/PortingEmbed/__tests__/index.test.tsx b/lib/PortingEmbed/__tests__/index.test.tsx index 72452a0..1eb1cab 100644 --- a/lib/PortingEmbed/__tests__/index.test.tsx +++ b/lib/PortingEmbed/__tests__/index.test.tsx @@ -89,11 +89,19 @@ describe('initialization', () => { it('throws without a project', async () => { const csn = await createFixtures() - // @ts-expect-error Assume a JS-developer forgets the project + // @ts-expect-error Assume the project is missing in a non-typechecked usage const init = PortingEmbed(csn, {}) expect(init).rejects.toThrow(/NO_PROJECT/) }) + it('throws with the wrong ConnectSession', async () => { + expect(PortingEmbed(null, { project })).rejects.toThrow(/WRONG_SESSION/i) + expect(PortingEmbed({}, { project })).rejects.toThrow(/WRONG_SESSION/i) + expect(PortingEmbed({ secret: 'foo' }, { project })).rejects.toThrow( + /WRONG_SESSION/i, + ) + }) + it('throws with a wrong intent', async () => { const csn = connectSessionFactory // @ts-expect-error Unsupported intent type diff --git a/lib/PortingEmbed/index.tsx b/lib/PortingEmbed/index.tsx index 7986cc1..ff5f042 100644 --- a/lib/PortingEmbed/index.tsx +++ b/lib/PortingEmbed/index.tsx @@ -16,25 +16,42 @@ export type PortingEmbedOptions = CustomizableEmbedProps type Events = never export async function PortingEmbed( - session: ConnectSession, + initConnectSession: unknown, { options: initialOptions, project, }: { options?: PortingEmbedOptions } & PortingEmbedInit, ) { - // Ensure embed was initialized with proper options - const { intent } = session + // Ensure embed was initialized with proper options. assert( project, 'NO_PROJECT: Cannot initialize PortingEmbed without a project.', ) + + // Ensure a valid ConnectSession object. + // The initConnectSession argument passed into this function is intentionally + // not typed as a ConnectSession. It's more convenient in combination with + // fetch() which is also not typed. Otherwise a developer would need to cast + // the response just to be able to initialize the embed. + assert( + initConnectSession && + typeof initConnectSession === 'object' && + 'object' in initConnectSession && + 'intent' in initConnectSession && + 'url' in initConnectSession && + initConnectSession.object === 'connectSession', + 'WRONG_SESSION: The object you passed in is not a ConnectSession resoure. Make sure to pass in the complete resource.', + ) + const csn = initConnectSession as ConnectSession + const { intent } = csn + assert( intent.type === 'completePorting', `WRONG_INTENT: PortingEmbed must be initialized with the "completePorting" intent, but got "${intent.type}" instead.`, ) - // Get a user token and ensure that the ConnectSession is valid. - const token = await exchangeSessionWithToken(session) + // Obtain a user token and ensure that the ConnectSession is valid. + const token = await exchangeSessionWithToken(csn) let element: Element | null = null let options = initialOptions