From ae7f05786d103ea2a36ea346dda900578b5dc8fd Mon Sep 17 00:00:00 2001 From: igor Date: Fri, 13 Feb 2026 10:40:32 +0100 Subject: [PATCH] upgrade APIlite and change build backend use TypeScript instead of JavaScript --- backend/composer.lock | 7 +- backend/scripts/buildTypeScript.php | 2 +- frontend/src/BackendAPI.js | 161 ---------------------- frontend/src/BackendAPI.ts | 205 ++++++++++++++++++++++++++++ frontend/src/views/AuthView.vue | 2 +- 5 files changed, 211 insertions(+), 166 deletions(-) delete mode 100644 frontend/src/BackendAPI.js create mode 100644 frontend/src/BackendAPI.ts diff --git a/backend/composer.lock b/backend/composer.lock index e028210..2ca67a6 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -8,11 +8,11 @@ "packages": [ { "name": "tpsoft/apilite", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://gitea.tpsoft.org/TPsoft.org/APIlite.git", - "reference": "fab8efd780ede046ced076f237351cdba5a8a51f" + "reference": "d258bcc91948424711dd79fde57254e1384d0091" }, "require": { "php": ">=8.2" @@ -41,6 +41,7 @@ "description": "A set of tools to simplify the work of creating backend APIs for your frontend projects.", "keywords": [ "api", + "javascript", "json", "php", "rest", @@ -52,7 +53,7 @@ "type": "other" } ], - "time": "2026-02-09T06:33:17+00:00" + "time": "2026-02-13T08:54:08+00:00" }, { "name": "tpsoft/dbmodel", diff --git a/backend/scripts/buildTypeScript.php b/backend/scripts/buildTypeScript.php index 6dbc168..173043e 100644 --- a/backend/scripts/buildTypeScript.php +++ b/backend/scripts/buildTypeScript.php @@ -9,7 +9,7 @@ $backend_api = new TPsoft\Nutrio\API('typescript', 'import.meta.env.VITE_BACKEND $output = ob_get_contents(); ob_end_clean(); -$ts_path = realpath(__DIR__ . '/../../frontend/src').'/BackendAPI.js'; +$ts_path = realpath(__DIR__ . '/../../frontend/src').'/BackendAPI.ts'; $suc = file_put_contents($ts_path, $output); if ($suc === false) { echo "✗ TypeScript store into file failed\n"; diff --git a/frontend/src/BackendAPI.js b/frontend/src/BackendAPI.js deleted file mode 100644 index 860f154..0000000 --- a/frontend/src/BackendAPI.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Generated by APIlite - * https://gitea.tpsoft.org/TPsoft.org/APIlite - * - * 2026-02-13 06:55:45 */ - -class BackendAPI { - endpoint = import.meta.env.VITE_BACKENDAPI_URL; - - /* ---------------------------------------------------- - * General API call - */ - call(method, data, callback) { - var xhttp = new XMLHttpRequest(); - xhttp.withCredentials = true; - xhttp.onreadystatechange = function() { - if (this.readyState == 4) { - if (this.status == 200) { - if (callback != null) callback(JSON.parse(this.responseText)); - } else { - if (callback != null) callback({'status': 'ERROR', 'message': 'HTTP STATUS ' + this.status}); - } - } - } - var form_data = new FormData(); - Object.keys(data).forEach(key => { - let val = data[key]; - if (typeof val == 'object') val = JSON.stringify(val); - form_data.append(key, val); - }); - xhttp.open('POST', this.endpoint + '?action=' + method); - xhttp.send(form_data); - } - - callPromise(method, data) { - return new Promise((resolve, reject) => { - this.call(method, data, function(response) { - if (method == '__HELP__') { - resolve(response); - return; - } - if (response.status == 'OK') { - resolve(response.data); - } else { - reject(response.msg); - } - }); - }) - } - - /* ---------------------------------------------------- - * API actions - */ - help() { - return this.callPromise('__HELP__', {}); - } - - health() { - return this.callPromise('health', {}); - } - - userRegistration(email, password) { - return this.callPromise('userRegistration', {email: email, password: password}); - } - - userLogin(email, password) { - return this.callPromise('userLogin', {email: email, password: password}); - } - - userDelete(email, password) { - return this.callPromise('userDelete', {email: email, password: password}); - } - - userLogout(token) { - return this.callPromise('userLogout', {token: token}); - } - - ingredientList(token, query, include_global) { - return this.callPromise('ingredientList', {token: token, query: query, include_global: include_global}); - } - - ingredientGet(token, ingredient_id) { - return this.callPromise('ingredientGet', {token: token, ingredient_id: ingredient_id}); - } - - ingredientCreate(token, name, protein_g_100, carbs_g_100, sugar_g_100, fat_g_100, fiber_g_100, kcal_100) { - return this.callPromise('ingredientCreate', {token: token, name: name, protein_g_100: protein_g_100, carbs_g_100: carbs_g_100, sugar_g_100: sugar_g_100, fat_g_100: fat_g_100, fiber_g_100: fiber_g_100, kcal_100: kcal_100}); - } - - ingredientUpdate(token, ingredient_id, name, protein_g_100, carbs_g_100, sugar_g_100, fat_g_100, fiber_g_100, kcal_100) { - return this.callPromise('ingredientUpdate', {token: token, ingredient_id: ingredient_id, name: name, protein_g_100: protein_g_100, carbs_g_100: carbs_g_100, sugar_g_100: sugar_g_100, fat_g_100: fat_g_100, fiber_g_100: fiber_g_100, kcal_100: kcal_100}); - } - - ingredientDelete(token, ingredient_id) { - return this.callPromise('ingredientDelete', {token: token, ingredient_id: ingredient_id}); - } - - mealList(token, meal_type, with_items, with_totals) { - return this.callPromise('mealList', {token: token, meal_type: meal_type, with_items: with_items, with_totals: with_totals}); - } - - mealGet(token, meal_id, with_items, with_totals) { - return this.callPromise('mealGet', {token: token, meal_id: meal_id, with_items: with_items, with_totals: with_totals}); - } - - mealCreate(token, name, meal_type) { - return this.callPromise('mealCreate', {token: token, name: name, meal_type: meal_type}); - } - - mealUpdate(token, meal_id, name, meal_type) { - return this.callPromise('mealUpdate', {token: token, meal_id: meal_id, name: name, meal_type: meal_type}); - } - - mealDelete(token, meal_id) { - return this.callPromise('mealDelete', {token: token, meal_id: meal_id}); - } - - mealItemList(token, meal_id, with_calculated) { - return this.callPromise('mealItemList', {token: token, meal_id: meal_id, with_calculated: with_calculated}); - } - - mealItemAdd(token, meal_id, ingredient_id, grams, position) { - return this.callPromise('mealItemAdd', {token: token, meal_id: meal_id, ingredient_id: ingredient_id, grams: grams, position: position}); - } - - mealItemUpdate(token, meal_item_id, ingredient_id, grams, position) { - return this.callPromise('mealItemUpdate', {token: token, meal_item_id: meal_item_id, ingredient_id: ingredient_id, grams: grams, position: position}); - } - - mealItemDelete(token, meal_item_id) { - return this.callPromise('mealItemDelete', {token: token, meal_item_id: meal_item_id}); - } - - mealItemReorder(token, meal_id, ordered_item_ids) { - return this.callPromise('mealItemReorder', {token: token, meal_id: meal_id, ordered_item_ids: ordered_item_ids}); - } - - mealTotals(token, meal_id) { - return this.callPromise('mealTotals', {token: token, meal_id: meal_id}); - } - - diaryDayGet(token, day_date, with_totals) { - return this.callPromise('diaryDayGet', {token: token, day_date: day_date, with_totals: with_totals}); - } - - diaryDaySetMeal(token, day_date, meal_type, meal_id) { - return this.callPromise('diaryDaySetMeal', {token: token, day_date: day_date, meal_type: meal_type, meal_id: meal_id}); - } - - diaryDayUnsetMeal(token, day_date, meal_type) { - return this.callPromise('diaryDayUnsetMeal', {token: token, day_date: day_date, meal_type: meal_type}); - } - - diaryRange(token, date_from, date_to) { - return this.callPromise('diaryRange', {token: token, date_from: date_from, date_to: date_to}); - } - - -}; - -export default new BackendAPI(); diff --git a/frontend/src/BackendAPI.ts b/frontend/src/BackendAPI.ts new file mode 100644 index 0000000..b818d97 --- /dev/null +++ b/frontend/src/BackendAPI.ts @@ -0,0 +1,205 @@ +/** + * Generated by APIlite + * https://gitea.tpsoft.org/TPsoft.org/APIlite + * + * 2026-02-13 10:00:58 */ + +export interface APIliteActionResponse { + status: 'OK'; + data: T; +} + +export interface APIliteErrorResponse { + status: 'ERROR'; + msg: string; +} + +export interface APIliteMethodParam { + name: string; + type: string | null; + optional: boolean; + default: unknown; + doc: string | null; +} + +export interface APIliteMethodDoc { + name: string; + doc: string | null; + description: string | null; + params: APIliteMethodParam[]; + return: string | string[] | null; +} + +export interface APIliteHelpResponse { + name: string; + html_version: string; + javascript_version: string; + typescript_version: string; + actions: APIliteMethodDoc[]; +} + +class BackendAPI { + endpoint: string = import.meta.env.VITE_BACKENDAPI_URL; + + private call( + method: string, + data: Record, + callback: (response: APIliteHelpResponse | APIliteActionResponse | APIliteErrorResponse) => void + ): void { + const xhttp = new XMLHttpRequest(); + xhttp.withCredentials = true; + xhttp.onreadystatechange = function() { + if (this.readyState === 4) { + if (this.status === 200) { + const response = JSON.parse(this.responseText) as APIliteHelpResponse | APIliteActionResponse | APIliteErrorResponse; + callback(response); + } else { + callback({ status: 'ERROR', msg: 'HTTP STATUS ' + this.status }); + } + } + }; + + const formData = new FormData(); + Object.keys(data).forEach((key) => { + const rawValue = data[key]; + if (typeof rawValue === 'undefined') { + return; + } + let value: string | Blob; + if (rawValue instanceof Blob) { + value = rawValue; + } else if (typeof rawValue === 'object' && rawValue !== null) { + value = JSON.stringify(rawValue); + } else { + value = String(rawValue); + } + formData.append(key, value); + }); + + xhttp.open('POST', this.endpoint + '?action=' + method); + xhttp.send(formData); + } + + private callPromise(method: string, data: Record): Promise { + return new Promise((resolve, reject) => { + this.call(method, data, (response) => { + if (method === '__HELP__') { + resolve(response as T); + return; + } + if (response.status === 'OK') { + resolve(response.data as T); + return; + } + reject(response.msg); + }); + }); + } + + help(): Promise { + return this.callPromise('__HELP__', {}); + } + + health(): Promise> { + return this.callPromise>('health', { }); + } + + userRegistration(email: string, password: string): Promise> { + return this.callPromise>('userRegistration', { email, password }); + } + + userLogin(email: string, password: string): Promise> { + return this.callPromise>('userLogin', { email, password }); + } + + userDelete(email: string, password: string): Promise> { + return this.callPromise>('userDelete', { email, password }); + } + + userLogout(token: string): Promise> { + return this.callPromise>('userLogout', { token }); + } + + ingredientList(token: string, query?: string, include_global?: boolean): Promise> { + return this.callPromise>('ingredientList', { token, query, include_global }); + } + + ingredientGet(token: string, ingredient_id: number): Promise> { + return this.callPromise>('ingredientGet', { token, ingredient_id }); + } + + ingredientCreate(token: string, name: string, protein_g_100: number, carbs_g_100: number, sugar_g_100: number, fat_g_100: number, fiber_g_100?: number, kcal_100?: number): Promise> { + return this.callPromise>('ingredientCreate', { token, name, protein_g_100, carbs_g_100, sugar_g_100, fat_g_100, fiber_g_100, kcal_100 }); + } + + ingredientUpdate(token: string, ingredient_id: number, name: string, protein_g_100: number, carbs_g_100: number, sugar_g_100: number, fat_g_100: number, fiber_g_100?: number, kcal_100?: number): Promise> { + return this.callPromise>('ingredientUpdate', { token, ingredient_id, name, protein_g_100, carbs_g_100, sugar_g_100, fat_g_100, fiber_g_100, kcal_100 }); + } + + ingredientDelete(token: string, ingredient_id: number): Promise> { + return this.callPromise>('ingredientDelete', { token, ingredient_id }); + } + + mealList(token: string, meal_type?: string, with_items?: boolean, with_totals?: boolean): Promise> { + return this.callPromise>('mealList', { token, meal_type, with_items, with_totals }); + } + + mealGet(token: string, meal_id: number, with_items?: boolean, with_totals?: boolean): Promise> { + return this.callPromise>('mealGet', { token, meal_id, with_items, with_totals }); + } + + mealCreate(token: string, name: string, meal_type: string): Promise> { + return this.callPromise>('mealCreate', { token, name, meal_type }); + } + + mealUpdate(token: string, meal_id: number, name: string, meal_type: string): Promise> { + return this.callPromise>('mealUpdate', { token, meal_id, name, meal_type }); + } + + mealDelete(token: string, meal_id: number): Promise> { + return this.callPromise>('mealDelete', { token, meal_id }); + } + + mealItemList(token: string, meal_id: number, with_calculated?: boolean): Promise> { + return this.callPromise>('mealItemList', { token, meal_id, with_calculated }); + } + + mealItemAdd(token: string, meal_id: number, ingredient_id: number, grams: number, position?: number): Promise> { + return this.callPromise>('mealItemAdd', { token, meal_id, ingredient_id, grams, position }); + } + + mealItemUpdate(token: string, meal_item_id: number, ingredient_id: number, grams: number, position: number): Promise> { + return this.callPromise>('mealItemUpdate', { token, meal_item_id, ingredient_id, grams, position }); + } + + mealItemDelete(token: string, meal_item_id: number): Promise> { + return this.callPromise>('mealItemDelete', { token, meal_item_id }); + } + + mealItemReorder(token: string, meal_id: number, ordered_item_ids: unknown[]): Promise> { + return this.callPromise>('mealItemReorder', { token, meal_id, ordered_item_ids }); + } + + mealTotals(token: string, meal_id: number): Promise> { + return this.callPromise>('mealTotals', { token, meal_id }); + } + + diaryDayGet(token: string, day_date: string, with_totals?: boolean): Promise> { + return this.callPromise>('diaryDayGet', { token, day_date, with_totals }); + } + + diaryDaySetMeal(token: string, day_date: string, meal_type: string, meal_id: number): Promise> { + return this.callPromise>('diaryDaySetMeal', { token, day_date, meal_type, meal_id }); + } + + diaryDayUnsetMeal(token: string, day_date: string, meal_type: string): Promise> { + return this.callPromise>('diaryDayUnsetMeal', { token, day_date, meal_type }); + } + + diaryRange(token: string, date_from: string, date_to: string): Promise> { + return this.callPromise>('diaryRange', { token, date_from, date_to }); + } + +} + +export default new BackendAPI(); diff --git a/frontend/src/views/AuthView.vue b/frontend/src/views/AuthView.vue index 1127152..3c42238 100644 --- a/frontend/src/views/AuthView.vue +++ b/frontend/src/views/AuthView.vue @@ -12,7 +12,7 @@ import { faSun, } from '@fortawesome/free-solid-svg-icons' -import BackendAPI from '@/BackendAPI.js' +import BackendAPI from '@/BackendAPI.ts' import i18n from '@/i18n' import { SUPPORTED_LOCALES, type AppLocale } from '@/i18n'