import assert from 'node:assert/strict' import { createPackageAppAuth, parsePackageAppAuthIdentityFromHostedUrl, readPackageAppVisitorHeader, } from '../src/auth.ts' assert.deepEqual( parsePackageAppAuthIdentityFromHostedUrl( 'https://kentcdodds.kody.run/packages/package-app-kit/', ), { app: 'package-app-kit', org: 'kentcdodds', appOriginMount: false }, ) assert.deepEqual( parsePackageAppAuthIdentityFromHostedUrl( 'https://kody.codes/@KentCDodds/packages/Demo/notes', ), { app: 'demo', org: 'kentcdodds', appOriginMount: true }, ) assert.deepEqual(parsePackageAppAuthIdentityFromHostedUrl('https://custom.example/'), { app: null, org: null, appOriginMount: false, }) const calls = [] const auth = createPackageAppAuth({ mode: 'required', scopes: ['email', 'email'], hostedUrl: 'https://notes.kody.run/notes-app', fetch: async (request) => { calls.push(request) if (!request.headers.get('Cookie')?.includes('__Host-kody_pkg_session=ok')) { return new Response('{}', { status: 401 }) } return Response.json({ userId: 'u1', username: 'kent', displayName: 'Kent', role: 'admin' }) }, }) const req = (cookie) => new Request('https://notes.kody.run/notes?tab=1', cookie ? { headers: { Cookie: cookie } } : {}) // Subdomain host: app only (org lives in the Host label) assert.equal(auth.loginUrl(), 'https://notes.kody.run/-/auth/login?app=notes-app&scope=email') assert.equal( auth.loginUrl({ request: req(), returnTo: '/notes?tab=1' }), 'https://notes.kody.run/-/auth/login?app=notes-app&return_to=%2Fnotes%3Ftab%3D1&scope=email', ) assert.equal(auth.loginUrl({ scopes: [] }), 'https://notes.kody.run/-/auth/login?app=notes-app') assert.equal( auth.logoutUrl({ returnTo: '/' }), 'https://notes.kody.run/-/auth/logout?app=notes-app&return_to=%2F', ) assert.equal(auth.meUrl(), 'https://notes.kody.run/-/auth/me?app=notes-app') const withHosted = createPackageAppAuth({ hostedUrl: 'https://x.kody.run/x/' }) assert.equal(withHosted.meUrl(), 'https://x.kody.run/-/auth/me?app=x') const legacyHosted = createPackageAppAuth({ hostedUrl: 'https://x.kody.run/packages/x/' }) assert.equal(legacyHosted.meUrl(), 'https://x.kody.run/-/auth/me?app=x') const withOrigin = createPackageAppAuth({ origin: 'https://a.test', hostedUrl: 'https://b.test' }) assert.equal(withOrigin.logoutUrl(), 'https://a.test/-/auth/logout') const withOriginAndApp = createPackageAppAuth({ origin: 'https://a.test', hostedUrl: 'https://owner.kody.run/leaf', }) assert.equal( withOriginAndApp.logoutUrl({ returnTo: '/' }), 'https://a.test/-/auth/logout?app=leaf&org=owner&return_to=%2F', ) // Preview / app-origin: app + org const preview = createPackageAppAuth({ hostedUrl: 'https://kody.codes/@acme/packages/demo', }) assert.equal( preview.loginUrl({ returnTo: '/notes' }), 'https://kody.codes/-/auth/login?app=demo&org=acme&return_to=%2Fnotes', ) assert.equal( preview.logoutUrl({ returnTo: '/' }), 'https://kody.codes/-/auth/logout?app=demo&org=acme&return_to=%2F', ) assert.equal(preview.meUrl(), 'https://kody.codes/-/auth/me?app=demo&org=acme') // Explicit options win over hostedUrl parse const explicit = createPackageAppAuth({ hostedUrl: 'https://kody.codes/@acme/packages/demo', app: 'other', org: 'beta', }) assert.equal(explicit.meUrl(), 'https://kody.codes/-/auth/me?app=other&org=beta') // username alias const viaUsername = createPackageAppAuth({ origin: 'https://preview.example', app: 'leaf', username: 'Owner', }) assert.equal( viaUsername.loginUrl(), 'https://preview.example/-/auth/login?app=leaf&org=owner', ) assert.equal(await auth.getUser(req()), null) assert.equal(calls.length, 0, 'no cookie → no fetch') assert.equal(await auth.getUser(req('a=b')), null) assert.equal(calls[0].url, 'https://notes.kody.run/-/auth/me?app=notes-app') const user = await auth.getUser(req('__Host-kody_pkg_session=ok')) assert.equal(user?.userId, 'u1') let thrown try { await auth.resolveUser(req('a=b')) } catch (e) { thrown = e } assert.ok(thrown instanceof Response) assert.equal(thrown.status, 302) assert.equal( thrown.headers.get('Location'), 'https://notes.kody.run/-/auth/login?app=notes-app&return_to=%2Fnotes%3Ftab%3D1&scope=email', ) assert.equal((await auth.resolveUser(req('__Host-kody_pkg_session=ok')))?.username, 'kent') // Package-app server code: the platform strips Cookie and sets the verified // X-Kody-Visitor header. getUser reads it without any network call. const visitorReq = (value) => new Request('https://notes.kody.run/notes', { headers: { 'X-Kody-Visitor': value } }) const callsBeforeHeader = calls.length assert.deepEqual( await auth.getUser(visitorReq(JSON.stringify({ userId: 'u2', username: 'outside', role: null }))), { userId: 'u2', username: 'outside', displayName: 'outside', role: 'user' }, ) assert.deepEqual( await auth.resolveUser(visitorReq(JSON.stringify({ userId: 'u1', username: 'kent', role: 'owner' }))), { userId: 'u1', username: 'kent', displayName: 'kent', role: 'owner' }, ) assert.equal(calls.length, callsBeforeHeader, 'visitor header → no fetch') assert.equal(await auth.getUser(visitorReq('not json')), null) assert.equal(calls.length, callsBeforeHeader, 'malformed header → null, still no fetch') assert.equal(readPackageAppVisitorHeader(req()), null) const optional = createPackageAppAuth({ fetch: async () => new Response('x', { status: 500 }) }) assert.equal(optional.mode, 'optional') assert.equal(await optional.resolveUser(req()), null) await assert.rejects(() => optional.getUser(req('a=b')), { name: 'PackageAppAuthError', status: 500 }) console.log('smoke-auth ok')