diff options
| author | aura <nw@moneybot.cc> | 2026-02-17 22:39:42 +0100 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-02-17 22:39:42 +0100 |
| commit | 636b0323075225c584b62719ed51e75521bb7ffb (patch) | |
| tree | 61b02271b6d0695a4beffc23fb6eb062a7da22c3 /backend/api-test.ts | |
push source
Diffstat (limited to 'backend/api-test.ts')
| -rw-r--r-- | backend/api-test.ts | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/backend/api-test.ts b/backend/api-test.ts new file mode 100644 index 0000000..3a6344b --- /dev/null +++ b/backend/api-test.ts @@ -0,0 +1,446 @@ +const BASE_URL = "https://api.axonbox.net"; +const LOGIN_EMAIL = "support@axonbox.net"; + +import { readFile } from 'fs/promises'; +const Imap = require( 'imap' ); + +const messages = [ { + role: "user", + content: "can you write 3 sorting algorithms for arrays of strings in c?", + timestamp: new Date( ).toISOString( ) + }, { + role: "user", + content: "can you modify that to be for an array of floats?", + timestamp: new Date( ).toISOString( ) + }, { + role: "user", + content: "what are the fastest sorting algorithms?", + timestamp: new Date( ).toISOString( ) + } +]; + +function getUrl( endpoint_name: string ): string { return `${ BASE_URL }${ endpoint_name }`; } +function getRandomIndex( length: number ): number { return Math.floor( Math.random( ) * length ); } +async function logErrorResponse( res: Response ): Promise<boolean> { + console.error( await res.json( ) ); + return false; +} + +async function apiCall( endpoint: string, method: string, payload: object = { } ) { + return await fetch( getUrl( endpoint ), { + method, + headers: { "Content-Type": "application/json" }, + body: JSON.stringify( payload ) + } + ); +} + +async function searchAndFetchNewEmail( mail: any ): Promise<string> { + return new Promise( ( resolve, reject ) => { + let retries = 4; + + function attemptSearch( ) { + mail.search( [ 'UNSEEN' ], ( err, results ) => { + if ( err ) + return reject( err ); + + if ( !results.length ) { + if ( retries > 0 ) { + --retries; + console.log( `No unseen emails yet. Retrying in 25 seconds ( ${retries} retries left )...` ); + setTimeout( attemptSearch, 25000 ); + } else { + mail.end( ); + return reject( new Error( 'no unread emails after 100 seconds' ) ); + } + return; + } + + const latest_email = results[ results.length - 1 ]; + const f = mail.fetch( latest_email, { bodies: "" } ); + let body = ""; + + f.on( "message", msg => { + msg.on( "body", ( stream, info ) => { + stream.on( "data", ( chunk ) => { + body += chunk.toString( 'utf8' ); + }); + }); + + msg.on( 'end', ( ) => { } ); + }); + + f.on( 'end', ( ) => { + mail.end( ); + resolve( body ); + }); + + f.on( 'error', ( fetcherr ) => { + mail.end( ); + reject( fetcherr ); + }); + }); + } + + attemptSearch( ); + }); +} + +async function getNewEmailBody( mail: any ): Promise<string> { + return new Promise( ( resolve, reject ) => { + const timeout = setTimeout( ( ) => { + mail.end( ); + reject( new Error( 'Timeout waiting for email connection' ) ); + }, 180000 ); + + mail.once( "ready", ( ) => { + mail.openBox( "INBOX", false, ( err, mailbox ) => { + if ( err ) { + clearTimeout( timeout ); + mail.end( ); + return reject( err ); + } + + mail.on( "mail", async ( ) => { + try { + let emailBody = await searchAndFetchNewEmail( mail ); + clearTimeout( timeout ); + resolve( emailBody ); + } catch( e ) { + clearTimeout( timeout ); + mail.end( ); + reject( e ); + } + }); + }); + }); + + mail.once( "error", ( err ) => { + clearTimeout( timeout ); + reject( err ); + }); + + mail.connect( ); + }); +} + +async function getSiteToken( ) { + const password: string = ( await readFile( './data/mail_password.txt', 'utf8' ) ).trim( ); + + console.log( `\n\nsigning into email with ${ LOGIN_EMAIL }:${ password }\n\n` ); + + let mail = new Imap({ + user: LOGIN_EMAIL, password, + host: "imappro.zoho.com", + port: 993, + tls: true + }); + + let email_body: string = ""; + try { + const result = await getNewEmailBody( mail ); + + if ( typeof result !== "string" ) + throw new Error( "invalid email body" ); + + email_body = result; + } catch ( err ) { + console.error( "failed to fetch email: ", err ); + return null; + } + + const login_token: string = email_body.split( "?token=" )[ 1 ]; + if ( !login_token ) { + console.log( `failed to find token in ${ email_body }` ); + return null; + } + + const login_res = await fetch( getUrl( `/login?token=${ login_token }` ), { method: "GET" } ); + + if ( !login_res.ok ) { + console.error( "login request failed" ); + await logErrorResponse( login_res ); + return null; + } + + const login_data = await login_res.json( ); + return login_data.session; +} + +const delay = ( ms: number ) => new Promise( r => setTimeout( r, ms ) ); + +const endpoints = { + "/get-tokens": async ( token: string ) => await apiCall( "/get-tokens", "POST", { token } ), + "/create-token": async ( token: string ) => await apiCall( "/create-token", "POST", { token } ), + "/delete-token": async ( token: string, id: number ) => await apiCall( "/delete-token", "POST", { token, id } ), + "/delete-tokens": async ( token: string ) => await apiCall( "/delete-tokens", "POST", { token } ), + "/send-login-link": async ( ) => await apiCall( "/send-login-link", "POST", { email: `${ LOGIN_EMAIL }` } ), + "/invalidate-session": async ( token: string ) => await apiCall( "/invalidate-session", "POST", { token } ), + "/invalidate-all-sessions": async ( token: string ) => await apiCall( "/invalidate-all-sessions", "POST", { token } ), + "/settings": async ( token: string ) => await apiCall( "/settings", "POST", { token } ), + "/get-notes": async ( token: string ) => await apiCall( "/get-notes", "POST", { token } ), + "/getalldata": async ( token: string ) => await apiCall( "/getalldata", "POST", { token } ), + "/delete-note": async ( token: string, noteId: string ) => await apiCall( "/delete-note", "POST", { token, noteId } ), + "/delete-notes": async ( token: string ) => await apiCall( "/delete-notes", "POST", { token } ), + "/models": async ( ) => await apiCall( "/models", "POST" ), + "/get-chat": async ( token: string, chatId: string ) => await apiCall( "/get-chat", "POST", { token, chatId } ), + "/create-chat": async ( token: string ) => await apiCall( "/create-chat", "POST", { token } ), + "/generate": async ( token: string, model: string, prompt: string = "write fibonacci in c99 please" ) => await apiCall( "/generate", "POST", { token, model, prompt, suffix: "" } ), + "/delete-chat": async ( token: string, chatId: string ) => await apiCall( "/delete-chat", "POST", { token, chatId } ), + "/update-settings": async ( token: string, free: boolean, models: any[ ] ) => { + const available_models = models.filter( ( m ) => m.free === ( free ? 1 : 0 ) ); + + return await apiCall( "/update-settings", "POST", { + token, prefs: { + nickname: ( Math.floor( Math.random( ) * 90000000 ) + 10000000 ).toString( ), + prompt_data: { + system: "explain everything to me like i am " + getRandomIndex( 100 ).toString( ) + " years old.", + }, + site_prefs: { + model: available_models[ getRandomIndex( available_models.length ) ].name, + }, + }, + }); + }, + "/chat": async ( token: string, chatfile: string, system: string, model: string, message: any ) => + await apiCall( "/chat", "POST", { + token, model, chatfile, system, + options: { seed: 123, temperature: 0.5 }, + messages: [ message ] + }) +}; + +async function test( ): Promise<boolean> { + let login_link_res = await endpoints[ "/send-login-link" ]( ); + if ( !login_link_res.ok ) + return await logErrorResponse( login_link_res ); + else + console.log( `sent login url to: '${ LOGIN_EMAIL }'!` ); + + let site_token = await getSiteToken( ) || ""; + if ( !site_token ) { + console.log( "failed to get site tokens", site_token ); + return false; + } + + let settings_res = await endpoints[ "/settings" ]( site_token ); + if ( !settings_res.ok ) + return await logErrorResponse( settings_res ); + + const models_res = await endpoints[ "/models" ]( ); + if ( !models_res.ok ) + return await logErrorResponse( models_res ); + const models = await models_res.json( ); + console.log( "\ngot models: " ); + models.models.forEach( m => console.log( m.name ) ); + console.log( "\n" ); + + let settings = await settings_res.json( ); + console.log( settings ); + console.log( "\n" ); + + const is_free_tier: boolean = settings.userprefs.plan.endTime <= Date.now( ); + const update_settings_res = await endpoints[ "/update-settings" ]( site_token, is_free_tier, models.models ); + if ( !update_settings_res.ok ) + return await logErrorResponse( update_settings_res ); + + settings_res = await endpoints[ "/settings" ]( site_token ); + if ( !settings_res.ok ) + return await logErrorResponse( settings_res ); + settings = await settings_res.json( ); + console.log( "updated settings: " ); + console.log( settings ); + console.log( "\n" ); + + let get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); + if ( !get_tokens_res.ok ) + return await logErrorResponse( get_tokens_res ); + console.log( "tokens:", await get_tokens_res.json( ) ); + + let create_token_res = await endpoints[ "/create-token" ]( site_token ); + if ( !create_token_res.ok ) + return await logErrorResponse( create_token_res ); + let create_token_res_json = await create_token_res.json( ); + let new_token = create_token_res_json.token; + console.log( "\ncreated new token: " + new_token + '\n' ); + + get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); + if ( !get_tokens_res.ok ) + return await logErrorResponse( get_tokens_res ); + let tokens_res_json = await get_tokens_res.json( ); + console.log( "tokens:", tokens_res_json ); + + const generate_res = await endpoints[ "/generate" ]( new_token, settings.userprefs.site_prefs.model ); + if ( !generate_res.ok ) + return await logErrorResponse( generate_res ); + console.log( "generated:", await generate_res.text( ) ); + + const create_chat_res = await endpoints[ "/create-chat" ]( site_token ); + if ( !create_chat_res.ok ) + return await logErrorResponse( create_chat_res ); + const create_chat_res_json = await create_chat_res.json( ); + const chat_id = create_chat_res_json.chatId; + + // TODO : fix this so messages are sent back to model properly + // WARNING : this will break in the future when backend behaves as expected, managing message storage by itself + for ( let idx = 0; idx < messages.length; ++idx ) { + const chat_res = await endpoints[ "/chat" ]( + new_token, chat_id, + settings.userprefs.prompt_data.system, + settings.userprefs.site_prefs.model, { + role: messages[ idx ].role, + content: messages[ idx ].content, + timestamp: new Date( ).toISOString( ) + } + ); + + if ( !chat_res.ok ) + return await logErrorResponse( chat_res ); + + const chat_res_text = await chat_res.text( ); + const chunks = chat_res_text.split( "\n" ); + const last = chunks[ chunks.length - 2 ]; + + console.log( "chat response: ", last ); + await delay( 1000 ); + } + + const get_chat_res = await endpoints[ "/get-chat" ]( site_token, chat_id ); + if ( !get_chat_res.ok ) + return await logErrorResponse( get_chat_res ); + const get_chat_res_json = await get_chat_res.json( ); + console.log( `\nchat id: ${ chat_id }` ); + console.log( `chat name: ${ get_chat_res_json.name }` ); + console.log( `chat contents: ${ await get_chat_res_json.contents }` ); + + const delete_chat_res = await endpoints[ "/delete-chat" ]( site_token, chat_id ); + if ( !delete_chat_res.ok ) + return await logErrorResponse( delete_chat_res ); + console.log( `\nchat ${ chat_id } deleted` ); + + let get_notes_res = await endpoints[ "/get-notes" ]( site_token ); + if ( !get_notes_res.ok ) + return await logErrorResponse( get_notes_res ); + let get_notes_res_json = await get_notes_res.json( ); + console.log( "found notes:", get_notes_res_json ); + + if ( get_notes_res_json.notes.length > 1 ) { + const random_note = get_notes_res_json.notes[ getRandomIndex( get_notes_res_json.notes.length ) ]; + const delete_note_res = await endpoints[ "/delete-note" ]( site_token, random_note.id ); + if ( !delete_note_res.ok ) + return await logErrorResponse( delete_note_res ); + console.log( `deleted note[ ${ random_note.id } ]: ${ random_note.content }` ); + + get_notes_res = await endpoints[ "/get-notes" ]( site_token ); + if ( !get_notes_res.ok ) + return await logErrorResponse( get_notes_res ); + get_notes_res_json = await get_notes_res.json( ); + console.log( "found notes:", get_notes_res_json ); + + if ( get_notes_res_json.notes.length > 2 ) { + const delete_notes_res = await endpoints[ "/delete-notes" ]( site_token ); + if ( !delete_notes_res.ok ) + return await logErrorResponse( delete_notes_res ); + console.log( "deleted all notes:", await delete_notes_res.json( ) ); + } + + get_notes_res = await endpoints[ "/get-notes" ]( site_token ); + if ( !get_notes_res.ok ) + return await logErrorResponse( get_notes_res ); + get_notes_res_json = await get_notes_res.json( ); + console.log( "found notes:", get_notes_res_json ); + } else + console.log( "0 ( zero ) notes to delete, skipping step" ); + + const token_idx = getRandomIndex( tokens_res_json.tokens.length ); + if ( !!tokens_res_json.tokens.length ) { + const delete_token_res = await endpoints[ "/delete-token" ]( site_token, token_idx ); + if ( !delete_token_res.ok ) + return await logErrorResponse( delete_token_res ); + console.log( "deleted token: ", await delete_token_res.json( ) ); + + try { + const chat_res = await endpoints[ "/chat" ]( + new_token, chat_id, + settings.userprefs.prompt_data.system, + settings.userprefs.site_prefs.model, + messages[ 0 ] + ); + + if ( chat_res.ok ) + return await logErrorResponse( chat_res ); + } catch ( error ) { + console.log( "chat with deleted token failed as expected" ); + } + + get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); + if ( !get_tokens_res.ok ) + return await logErrorResponse( get_tokens_res ); + console.log( "remaining tokens:", await get_tokens_res.json( ) ); + } else + console.log( `failed to find token ${ new_token }` ); + + if ( tokens_res_json.tokens.length > 1 ) { + const delete_tokens_res = await endpoints[ "/delete-tokens" ]( site_token ); + if ( !delete_tokens_res.ok ) + return await logErrorResponse( delete_tokens_res ); + console.log( "deleted all tokens: ", await delete_tokens_res.json( ) ); + + get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); + if ( !get_tokens_res.ok ) + return await logErrorResponse( get_tokens_res ); + console.log( "remaining tokens:", await get_tokens_res.json( ) ); + } else + console.log( `'${ tokens_res_json.tokens.length - 1 }' tokens, not enough to delete` ); + + const getalldata_res = await endpoints[ "/getalldata" ]( site_token ); + if ( !getalldata_res.ok ) + return await logErrorResponse( getalldata_res ); + console.log( `getalldata returned: ${ getalldata_res.headers.get( 'Content-Length' ) } bytes of data` ); + + create_token_res = await endpoints[ "/create-token" ]( site_token ); + if ( !create_token_res.ok ) + return await logErrorResponse( create_token_res ); + create_token_res_json = await create_token_res.json( ); + new_token = create_token_res_json.token; + console.log( "\ncreated new token: " + new_token + '\n' ); + + const invalidate_session_res = await endpoints[ "/invalidate-session" ]( site_token ); + if ( !invalidate_session_res.ok ) + return await logErrorResponse( invalidate_session_res ); + console.log( "invalidated session: ", await invalidate_session_res.json( ) ); + + settings_res = await endpoints[ "/settings" ]( site_token ); + if ( settings_res.ok ) + return await logErrorResponse( settings_res ); + + login_link_res = await endpoints[ "/send-login-link" ]( ); + if ( !login_link_res.ok ) + return await logErrorResponse( login_link_res ); + else + console.log( `sent login url to: '${ LOGIN_EMAIL }'!` ); + + site_token = await getSiteToken( ) || ""; + if ( !site_token ) { + console.log( "failed to get post-login token", site_token ); + return false; + } + + const invalidate_all_sessions_res = await endpoints[ "/invalidate-all-sessions" ]( site_token ); + if ( !invalidate_all_sessions_res.ok ) + return await logErrorResponse( invalidate_all_sessions_res ); + console.log( "invalidated all sessions: ", await invalidate_all_sessions_res.json( ) ); + + settings_res = await endpoints[ "/settings" ]( "site_token" ); + if ( settings_res.ok ) + return await logErrorResponse( settings_res ); + + return true; +} + +( async function( ) { + if ( !await test( ) ) + console.error( "tests failed\n" ); + else + console.log( "tests passed\n" ); +} ) ( );
\ No newline at end of file |
