web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

commit 28a6d36db150ffa883a7cca9585c39a03105f299
parent d4725c2ebdba5a06d3d9ac51c131d39f3ca686b4
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sat, 16 Nov 2024 06:00:05 +0000

client: update iclientdatabase add `media_upload` methods. add user agent header to http api. update handle error utils

Diffstat:
Mclient/src/database/tauri.ts | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mclient/src/database/types.ts | 6+++++-
Mclient/src/geolocation/tauri.ts | 8++++----
Mclient/src/http/tauri.ts | 52+++++++++++++++++++++++-----------------------------
Mclient/src/http/types.ts | 7+++++++
5 files changed, 132 insertions(+), 35 deletions(-)

diff --git a/client/src/database/tauri.ts b/client/src/database/tauri.ts @@ -1,5 +1,5 @@ -import { LocationGcsSchema, LocationGcsUpdateSchema, NostrProfileSchema, NostrProfileUpdateSchema, NostrRelaySchema, NostrRelayUpdateSchema, TradeProductSchema, TradeProductUpdateSchema, parse_location_gcs, parse_location_gcs_form_fields, parse_location_gcs_get_composite_list, parse_location_gcs_list, parse_nostr_profile, parse_nostr_profile_form_fields, parse_nostr_profile_get_composite_list, parse_nostr_profile_list, parse_nostr_profile_relay_list, parse_nostr_relay, parse_nostr_relay_form_fields, parse_nostr_relay_get_composite_list, parse_nostr_relay_list, parse_trade_product, parse_trade_product_form_fields, parse_trade_product_get_composite_list, parse_trade_product_list, parse_trade_product_location_list, type ILocationGcsAdd, type ILocationGcsAddResolve, type ILocationGcsDelete, type ILocationGcsDeleteResolve, type ILocationGcsGet, type ILocationGcsGetOne, type ILocationGcsGetOneResolve, type ILocationGcsGetResolve, type ILocationGcsUpdate, type ILocationGcsUpdateResolve, type IModelsQueryBindValueTuple, type IModelsQueryValue, type INostrProfileAdd, type INostrProfileAddResolve, type INostrProfileDelete, type INostrProfileDeleteResolve, type INostrProfileGet, type INostrProfileGetOne, type INostrProfileGetOneResolve, type INostrProfileGetResolve, type INostrProfileRelayRelation, type INostrProfileRelayRelationResolve, type INostrProfileRelayRelationResolveGetAll, type INostrProfileUpdate, type INostrProfileUpdateResolve, type INostrRelayAdd, type INostrRelayAddResolve, type INostrRelayDelete, type INostrRelayDeleteResolve, type INostrRelayGet, type INostrRelayGetOne, type INostrRelayGetOneResolve, type INostrRelayGetResolve, type INostrRelayUpdate, type INostrRelayUpdateResolve, type ITradeProductAdd, type ITradeProductAddResolve, type ITradeProductDelete, type ITradeProductDeleteResolve, type ITradeProductGet, type ITradeProductGetOne, type ITradeProductGetOneResolve, type ITradeProductGetResolve, type ITradeProductLocationRelation, type ITradeProductLocationRelationResolve, type ITradeProductLocationRelationResolveGetAll, type ITradeProductUpdate, type ITradeProductUpdateResolve, type LocationGcsFields, type LocationGcsFormFields, type NostrProfileFields, type NostrProfileFormFields, type NostrRelayFields, type NostrRelayFormFields, type TradeProductFields, type TradeProductFormFields } from "@radroots/models"; +import { LocationGcsSchema, LocationGcsUpdateSchema, MediaUploadSchema, MediaUploadUpdateSchema, NostrProfileSchema, NostrProfileUpdateSchema, NostrRelaySchema, NostrRelayUpdateSchema, TradeProductSchema, TradeProductUpdateSchema, parse_location_gcs, parse_location_gcs_form_fields, parse_location_gcs_get_composite_list, parse_location_gcs_list, parse_media_upload, parse_media_upload_form_fields, parse_media_upload_get_composite_list, parse_media_upload_list, parse_nostr_profile, parse_nostr_profile_form_fields, parse_nostr_profile_get_composite_list, parse_nostr_profile_list, parse_nostr_profile_relay_list, parse_nostr_relay, parse_nostr_relay_form_fields, parse_nostr_relay_get_composite_list, parse_nostr_relay_list, parse_trade_product, parse_trade_product_form_fields, parse_trade_product_get_composite_list, parse_trade_product_list, parse_trade_product_location_list, type ILocationGcsAdd, type ILocationGcsAddResolve, type ILocationGcsDelete, type ILocationGcsDeleteResolve, type ILocationGcsGet, type ILocationGcsGetOne, type ILocationGcsGetOneResolve, type ILocationGcsGetResolve, type ILocationGcsUpdate, type ILocationGcsUpdateResolve, type IMediaUploadAdd, type IMediaUploadAddResolve, type IMediaUploadDelete, type IMediaUploadDeleteResolve, type IMediaUploadGet, type IMediaUploadGetOne, type IMediaUploadGetOneResolve, type IMediaUploadGetResolve, type IMediaUploadUpdate, type IMediaUploadUpdateResolve, type IModelsQueryBindValueTuple, type IModelsQueryValue, type INostrProfileAdd, type INostrProfileAddResolve, type INostrProfileDelete, type INostrProfileDeleteResolve, type INostrProfileGet, type INostrProfileGetOne, type INostrProfileGetOneResolve, type INostrProfileGetResolve, type INostrProfileRelayRelation, type INostrProfileRelayRelationResolve, type INostrProfileRelayRelationResolveGetAll, type INostrProfileUpdate, type INostrProfileUpdateResolve, type INostrRelayAdd, type INostrRelayAddResolve, type INostrRelayDelete, type INostrRelayDeleteResolve, type INostrRelayGet, type INostrRelayGetOne, type INostrRelayGetOneResolve, type INostrRelayGetResolve, type INostrRelayUpdate, type INostrRelayUpdateResolve, type ITradeProductAdd, type ITradeProductAddResolve, type ITradeProductDelete, type ITradeProductDeleteResolve, type ITradeProductGet, type ITradeProductGetOne, type ITradeProductGetOneResolve, type ITradeProductGetResolve, type ITradeProductLocationRelation, type ITradeProductLocationRelationResolve, type ITradeProductLocationRelationResolveGetAll, type ITradeProductUpdate, type ITradeProductUpdateResolve, type LocationGcsFields, type LocationGcsFormFields, type MediaUploadFields, type MediaUploadFormFields, type NostrProfileFields, type NostrProfileFormFields, type NostrRelayFields, type NostrRelayFormFields, type TradeProductFields, type TradeProductFormFields } from "@radroots/models"; import { err_msg, type ErrorMessage } from "@radroots/utils"; import { invoke } from "@tauri-apps/api/core"; import type { IClientDatabase, IClientDatabaseMessage } from "./types"; @@ -390,6 +390,98 @@ export class TauriClientDatabase implements IClientDatabase { return this.handle_errors("model_nostr_relay_update", opts, e); }; } + private media_upload_add_validate(fields: MediaUploadFormFields): MediaUploadFields | string[] { + const fields_r = Object.entries(fields).filter(([_, v]) => !!v).reduce((acc: Record<string, IModelsQueryValue>, i) => { + const [key, val] = parse_media_upload_form_fields(i); + acc[key] = val; + return acc; + }, {}); + const schema = MediaUploadSchema; + const parsed_schema = schema.safeParse(fields_r); + if (!parsed_schema.success) return parsed_schema.error.issues.map(i => i.message); + else return { + ...parsed_schema.data + }; + } + + public async media_upload_add(opts: IMediaUploadAdd): Promise<IMediaUploadAddResolve<IClientDatabaseMessage>> { + const err_s = this.media_upload_add_validate(opts); + if (Array.isArray(err_s)) return { err_s }; + const fields = this.filter_bind_value_fields(Object.entries(err_s)); + if (!fields.length) return err_msg("*-fields"); + try { + const response = await invoke<any>("model_media_upload_add", { opts }); + if ("id" in response && typeof response.id === "string") return { id: response.id }; + else if (typeof response === "string") return err_msg(response); + return err_msg("*-result"); + } catch (e) { + return this.handle_errors("model_media_upload_add", opts, e); + }; + } + + public async media_upload_get(opts: IMediaUploadGet): Promise<IMediaUploadGetResolve<IClientDatabaseMessage>> { + try { + const response = await invoke<any>("model_media_upload_get", { opts: "list" in opts ? { list: { of: parse_media_upload_get_composite_list(opts.list), sort: opts.sort } } : { on: opts } }); + if (typeof response === "string") return err_msg(response); + else if ("results" in response && Array.isArray(response.results)) return { results: parse_media_upload_list(response.results) }; + return err_msg("*-result"); + } catch (e) { + return this.handle_errors("model_media_upload_get", opts, e); + }; + } + + public async media_upload_get_one(opts: IMediaUploadGetOne): Promise<IMediaUploadGetOneResolve<IClientDatabaseMessage>> { + try { + const response = await invoke<any>("model_media_upload_get", { opts: { on: opts } }); + if (typeof response === "string") return err_msg(response); + else if ("results" in response && Array.isArray(response.results) && response.results.length === 1) { + const result = parse_media_upload(response.results[0]); + if (result) return { result }; + } + return err_msg("*-result"); + } catch (e) { + return this.handle_errors("model_media_upload_get", opts, e); + }; + } + + public async media_upload_delete(opts: IMediaUploadDelete): Promise<IMediaUploadDeleteResolve<IClientDatabaseMessage>> { + try { + const response = await invoke<any>("model_media_upload_delete", { opts }); + if (response === null) return { pass: true }; + else if (typeof response === "string") return err_msg(response); + return err_msg("*-result"); + } catch (e) { + return this.handle_errors("model_media_upload_delete", opts, e); + }; + } + private media_upload_update_validate(fields: Partial<MediaUploadFormFields>): Partial<MediaUploadFields> | string[] { + const fields_r = Object.entries(fields).filter(([_, v]) => !!v).reduce((acc: Record<string, IModelsQueryValue>, i) => { + const [key, val] = parse_media_upload_form_fields(i); + acc[key] = val; + return acc; + }, {}); + const schema = MediaUploadUpdateSchema; + const parsed_schema = schema.safeParse(fields_r); + if (!parsed_schema.success) return parsed_schema.error.issues.map(i => i.message); + else return { + ...parsed_schema.data + }; + } + + public async media_upload_update(opts: IMediaUploadUpdate): Promise<IMediaUploadUpdateResolve<IClientDatabaseMessage>> { + const err_s = this.media_upload_update_validate(opts.fields); + if (Array.isArray(err_s)) return { err_s }; + const fields = this.filter_bind_value_fields(Object.entries(err_s)); + if (!fields.length) return err_msg("*-fields"); + try { + const response = await invoke<any>("model_media_upload_update", { opts }); + if (response === null) return { pass: true }; + else if (typeof response === "string") return err_msg(response); + return err_msg("*-result"); + } catch (e) { + return this.handle_errors("model_media_upload_update", opts, e); + }; + } public async nostr_profile_relay_set(opts: INostrProfileRelayRelation): Promise<INostrProfileRelayRelationResolve<IClientDatabaseMessage>> { try { diff --git a/client/src/database/types.ts b/client/src/database/types.ts @@ -1,4 +1,4 @@ -import type { ILocationGcsAdd, ILocationGcsAddResolve, ILocationGcsDelete, ILocationGcsDeleteResolve, ILocationGcsGet, ILocationGcsGetResolve, ILocationGcsUpdate, ILocationGcsUpdateResolve, INostrProfileAdd, INostrProfileAddResolve, INostrProfileDelete, INostrProfileDeleteResolve, INostrProfileGet, INostrProfileGetResolve, INostrProfileRelayRelation, INostrProfileRelayRelationResolve, INostrProfileRelayRelationResolveGetAll, INostrProfileUpdate, INostrProfileUpdateResolve, INostrRelayAdd, INostrRelayAddResolve, INostrRelayDelete, INostrRelayDeleteResolve, INostrRelayGet, INostrRelayGetResolve, INostrRelayUpdate, INostrRelayUpdateResolve, ITradeProductAdd, ITradeProductAddResolve, ITradeProductDelete, ITradeProductDeleteResolve, ITradeProductGet, ITradeProductGetResolve, ITradeProductLocationRelation, ITradeProductLocationRelationResolve, ITradeProductLocationRelationResolveGetAll, ITradeProductUpdate, ITradeProductUpdateResolve } from "@radroots/models"; +import type { ILocationGcsAdd, ILocationGcsAddResolve, ILocationGcsDelete, ILocationGcsDeleteResolve, ILocationGcsGet, ILocationGcsGetResolve, ILocationGcsUpdate, ILocationGcsUpdateResolve, IMediaUploadAdd, IMediaUploadAddResolve, IMediaUploadDelete, IMediaUploadDeleteResolve, IMediaUploadGet, IMediaUploadGetResolve, IMediaUploadUpdate, IMediaUploadUpdateResolve, INostrProfileAdd, INostrProfileAddResolve, INostrProfileDelete, INostrProfileDeleteResolve, INostrProfileGet, INostrProfileGetResolve, INostrProfileRelayRelation, INostrProfileRelayRelationResolve, INostrProfileRelayRelationResolveGetAll, INostrProfileUpdate, INostrProfileUpdateResolve, INostrRelayAdd, INostrRelayAddResolve, INostrRelayDelete, INostrRelayDeleteResolve, INostrRelayGet, INostrRelayGetResolve, INostrRelayUpdate, INostrRelayUpdateResolve, ITradeProductAdd, ITradeProductAddResolve, ITradeProductDelete, ITradeProductDeleteResolve, ITradeProductGet, ITradeProductGetResolve, ITradeProductLocationRelation, ITradeProductLocationRelationResolve, ITradeProductLocationRelationResolveGetAll, ITradeProductUpdate, ITradeProductUpdateResolve } from "@radroots/models"; export type IClientDatabaseMessage = | string @@ -22,6 +22,10 @@ export type IClientDatabase = { nostr_relay_get(opts: INostrRelayGet): Promise<INostrRelayGetResolve<IClientDatabaseMessage>>; nostr_relay_delete(opts: INostrRelayDelete): Promise<INostrRelayDeleteResolve<IClientDatabaseMessage>>; nostr_relay_update(opts: INostrRelayUpdate): Promise<INostrRelayUpdateResolve<IClientDatabaseMessage>>; + media_upload_add(opts: IMediaUploadAdd): Promise<IMediaUploadAddResolve<IClientDatabaseMessage>>; + media_upload_get(opts: IMediaUploadGet): Promise<IMediaUploadGetResolve<IClientDatabaseMessage>>; + media_upload_delete(opts: IMediaUploadDelete): Promise<IMediaUploadDeleteResolve<IClientDatabaseMessage>>; + media_upload_update(opts: IMediaUploadUpdate): Promise<IMediaUploadUpdateResolve<IClientDatabaseMessage>>; nostr_profile_relay_set(opts: INostrProfileRelayRelation): Promise<INostrProfileRelayRelationResolve<IClientDatabaseMessage>>; nostr_profile_relay_unset(opts: INostrProfileRelayRelation): Promise<INostrProfileRelayRelationResolve<IClientDatabaseMessage>>; nostr_profile_relay_get_all(opts: INostrProfileRelayRelation): Promise<INostrProfileRelayRelationResolveGetAll<IClientDatabaseMessage>>; diff --git a/client/src/geolocation/tauri.ts b/client/src/geolocation/tauri.ts @@ -46,8 +46,8 @@ export class TauriClientGeolocation implements IClientGeolocation { const position = await getCurrentPosition() return this.parse_geolocation_position(position); } catch (e) { - const { error } = handle_error(e); - if (error.includes(`The operation couldn’t be completed`)) return err_msg(`*-permissions`); + const { err } = handle_error(e); + if (err.includes(`The operation couldn’t be completed`)) return err_msg(`*-permissions`); return err_msg(`*`); }; } @@ -64,8 +64,8 @@ export class TauriClientGeolocation implements IClientGeolocation { ) return position_w; } catch (e) { - const { error } = handle_error(e); - if (error.includes(`The operation couldn’t be completed`)) err_msg(`*-permissions`); + const { err } = handle_error(e); + if (err.includes(`The operation couldn’t be completed`)) err_msg(`*-permissions`); return err_msg(`*`); }; } diff --git a/client/src/http/tauri.ts b/client/src/http/tauri.ts @@ -34,9 +34,10 @@ export class TauriClientHttp implements IClientHttp { public async init(opts: IClientDeviceMetadata): Promise<void> { this._headers = { + "User-Agent": `radroots-app/0.0.0`, "X-Client-Version": opts.version, "X-Client-Platform": opts.platform, - "X-Client-Locale": opts.locale + "X-Client-Locale": opts.locale, }; } @@ -56,35 +57,28 @@ export class TauriClientHttp implements IClientHttp { if (opts.data_bin) options.body = opts.data_bin; if (opts.connect_timeout) options.connectTimeout = opts.connect_timeout; const response = await fetch(url, options); - switch (response.ok) { - case true: { - let data: any = null; - try { - const res_json = await response.json(); - data = typeof res_json === `string` ? JSON.parse(res_json) : res_json; - } catch { } - if (!data) { - try { - const res_text = await response.text(); - data = res_text; - } catch { } - } - return { - status: response.status, - url: response.url, - data, - headers: parse_headers(response.headers) - }; - } - case false: { - return { - status: response.status, - url: response.url, - data: null, - headers: parse_headers(response.headers) - }; - } + let data: any = null; + try { + const res_json = await response.json(); + data = typeof res_json === `string` ? JSON.parse(res_json) : res_json; + } catch { } + if (!data) { + try { + const res_text = await response.text(); + data = res_text; + } catch { } } + return { + status: response.status, + url: response.url, + data: response.ok ? data : null, + error: !response.ok && `error` in data ? typeof data.error === `string` ? { + message: data.error + } : { + ...data.error + } : undefined, + headers: parse_headers(response.headers) + }; } catch (e) { console.log(`e fetch`, e) return err_msg(String(e)); diff --git a/client/src/http/types.ts b/client/src/http/types.ts @@ -20,9 +20,16 @@ export type IClientHttpImageResponse = { url: string; }; +export type IClientHttpResponseError = { + message: string; + label_ok?: string; + label_cancel?: string; +}; + export type IClientHttpResponse = { status: number; data: any; + error?: IClientHttpResponseError; headers: FieldRecord; url: string; };