import assert from 'node:assert/strict' import test from 'node:test' import { accessTokenIdentity, ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, REMEMBERED_LOGIN_ID_KEY, clearSessionTokens, getRememberedLoginId, persistRememberedLoginId, persistTokenPair, } from './session.ts' function storage() { const values = new Map() return { getItem: (key) => values.get(key) ?? null, setItem: (key, value) => values.set(key, String(value)), removeItem: (key) => values.delete(key), } } function installStorage() { globalThis.localStorage = storage() globalThis.sessionStorage = storage() } test('persists the normal rotating session independently of remembered account preference', () => { installStorage() persistTokenPair({ tokenType: 'Bearer', accessToken: 'access-token', expiresIn: 1440, refreshToken: 'refresh-token', refreshExpiresIn: 604800, }) assert.equal(localStorage.getItem(ACCESS_TOKEN_KEY), 'access-token') assert.equal(localStorage.getItem(REFRESH_TOKEN_KEY), 'refresh-token') assert.equal(sessionStorage.getItem(ACCESS_TOKEN_KEY), null) assert.equal(sessionStorage.getItem(REFRESH_TOKEN_KEY), null) }) test('remembers only the login id and keeps it when session tokens are cleared', () => { installStorage() persistRememberedLoginId('merchant-user', true) localStorage.setItem(ACCESS_TOKEN_KEY, 'access-token') localStorage.setItem(REFRESH_TOKEN_KEY, 'refresh-token') clearSessionTokens() assert.equal(getRememberedLoginId(), 'merchant-user') assert.equal(localStorage.getItem(REMEMBERED_LOGIN_ID_KEY), 'merchant-user') assert.equal(localStorage.getItem(ACCESS_TOKEN_KEY), null) assert.equal(localStorage.getItem(REFRESH_TOKEN_KEY), null) persistRememberedLoginId('merchant-user', false) assert.equal(getRememberedLoginId(), '') }) test('normal token rotation never removes either shared token between writes', () => { installStorage() localStorage.setItem(ACCESS_TOKEN_KEY, 'old-access') localStorage.setItem(REFRESH_TOKEN_KEY, 'old-refresh') const removed = [] const remove = localStorage.removeItem localStorage.removeItem = key => { removed.push(key); remove(key) } persistTokenPair({ accessToken: 'new-access', refreshToken: 'new-refresh' }) assert.ok(!removed.includes(ACCESS_TOKEN_KEY)) assert.ok(!removed.includes(REFRESH_TOKEN_KEY)) }) function rawIdentity(overrides = '') { return `test.${Buffer.from(`{"user_id":2107003446494334978,"tenant_id":2107003446494334978,"membership_id":2107003446494334978,"app_code":"MERCHANT"${overrides}}`).toString('base64url')}.test` } test('identity preserves low digits of numeric 19 digit user customer and membership',()=>{ const original=rawIdentity();const json=Buffer.from(original.split('.')[1],'base64url').toString(); for(const field of ['user_id','tenant_id','membership_id']){ const changed=json.replace(`"${field}":2107003446494334978`,`"${field}":2107003446494334979`) assert.notEqual(accessTokenIdentity(original),accessTokenIdentity(`test.${Buffer.from(changed).toString('base64url')}.test`)) } }) test('identity string and numeric integers are equivalent without changing other strings',()=>{ const a=rawIdentity();const raw=Buffer.from(a.split('.')[1],'base64url').toString(); const b=`test.${Buffer.from(raw.replaceAll(':2107003446494334978',':"2107003446494334978"')).toString('base64url')}.test` assert.equal(accessTokenIdentity(a),accessTokenIdentity(b)) const decorated=rawIdentity(',"username":'+JSON.stringify('number 2107003446494334979 and "tenant_id":2107003446494334979')+',"note":"1234567890123456789"') assert.equal(accessTokenIdentity(a),accessTokenIdentity(decorated)) assert.ok(accessTokenIdentity(a).includes('2107003446494334978')) })