@gigscom/embeds-js
Version:
prebuilt embeddable UI components on top of the Gigs API for the Web
77 lines (67 loc) • 2.49 kB
text/typescript
import { ConnectSession, ConnectSessionIntent } from '../types'
import { assert } from './assert'
type Tokens = {
access_token: string
}
/**
* Exchange an authenticated ConnectSession with a user token.
* Returns the token, together with the validated ConnectSession for the sake
* of easier type-safety.
*/
export async function exchangeSessionWithToken(
session: unknown,
type: ConnectSessionIntent['type'],
) {
const { connectSession, token } = parseConnectSession(session, type)
const res = await fetch(`https://connect.gigs.com/api/embeds/auth`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ secret: token }),
})
const body: { token?: Tokens; error?: string } = await res
.json()
.catch(async () => ({ error: await res.text() }))
assert(res.status !== 422, 'INVALID_SESSION: Session is expired.')
assert(res.ok, `FETCH_FAILED: ${body.error}`)
assert(
body.token?.access_token,
'Expected user token to be returned in response of token exchange, but was not found.',
)
return { connectSession, token: body.token.access_token }
}
function parseConnectSession(
session: unknown,
type: ConnectSessionIntent['type'],
) {
// The session which is used to initilialize an embed is intentionally typed
// as unknown.
// 1. For non-typescript usage, we need to ensure that the passed in object is
// correct anyways.
// 2. To not require the caller to cast the response as a ConnectSession.
// Especially since fetch returns any. Makes it a little easier to use.
assert(
session &&
typeof session === 'object' &&
'object' in session &&
'intent' in session &&
'url' in session &&
session.object === 'connectSession',
'INVALID_SESSION: The object you passed in is not a ConnectSession resoure. Make sure to pass in the complete resource.',
)
const connectSession = session as ConnectSession
assert(
connectSession.intent.type === type,
`INVALID_SESSION: PortingEmbed must be initialized with the "${type}" intent, but got "${connectSession.intent.type}" instead.`,
)
assert(
connectSession.url,
'INVALID_SESSION: Session has no URL. Did you pass in the created session?',
)
const url = new URL(connectSession.url)
const token = url.searchParams.get('token')
assert(
token,
'INVALID_SESSION: Session has no token. Is it an authenticated session?',
)
return { connectSession, token }
}