From 52a9b5f8a257320ad703f8fc296ae4b03ab51c2d Mon Sep 17 00:00:00 2001 From: Ioan Moldovan Date: Mon, 14 Jul 2025 20:20:45 -0300 Subject: [PATCH] feat: use named types for api request params --- .../common/api/email-provider/gmail/google.ts | 42 +++--------- extension/js/common/api/shared/api.ts | 68 +++++++++++++------ 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/extension/js/common/api/email-provider/gmail/google.ts b/extension/js/common/api/email-provider/gmail/google.ts index 8f3d9ec54a8..819f33a918e 100644 --- a/extension/js/common/api/email-provider/gmail/google.ts +++ b/extension/js/common/api/email-provider/gmail/google.ts @@ -2,49 +2,22 @@ 'use strict'; -import { Ajax, ProgressCbs } from '../../shared/api.js'; -import { Dict, Str, UrlParams } from '../../../core/common.js'; +import { Ajax, AjaxParams, JsonParams, ProgressCbs } from '../../shared/api.js'; +import { Dict, Str } from '../../../core/common.js'; import { GMAIL_GOOGLE_API_HOST, PEOPLE_GOOGLE_API_HOST } from '../../../core/const.js'; import { GmailRes } from './gmail-parser.js'; import { GoogleOAuth } from '../../authentication/google/google-oauth.js'; -import { Serializable } from '../../../platform/store/abstract-store.js'; import { CatchHelper } from '../../../platform/catch-helper.js'; - export class Google { public static webmailUrl = (acctEmail: string) => { return `https://mail.google.com/mail/u/${acctEmail}`; }; - public static gmailCall = async ( - acctEmail: string, - path: string, - params?: - | { - method: 'POST' | 'PUT'; - data: Dict; - dataType?: 'JSON'; - } - | { - method: 'POST'; - data: string; - contentType: string; - dataType: 'TEXT'; - } - | { - method: 'GET'; - data?: UrlParams; - } - | { method: 'DELETE' }, - progress?: ProgressCbs - ): Promise => { + public static gmailCall = async (acctEmail: string, path: string, params?: AjaxParams, progress?: ProgressCbs): Promise => { progress = progress || {}; let url; - let dataPart: - | { method: 'POST' | 'PUT'; data: Dict; dataType: 'JSON' } - | { method: 'POST'; data: string; contentType: string; dataType: 'TEXT' } - | { method: 'GET'; data?: UrlParams } - | { method: 'DELETE' }; + let dataPart: AjaxParams; if (params?.method === 'POST' && params.dataType === 'TEXT') { url = `${GMAIL_GOOGLE_API_HOST}/upload/gmail/v1/users/me/${path}?uploadType=multipart`; dataPart = { method: 'POST', data: params.data, contentType: params.contentType, dataType: 'TEXT' }; @@ -53,7 +26,12 @@ export class Google { if (params?.method === 'GET') { dataPart = { method: 'GET', data: params.data }; } else if (params?.method === 'POST' || params?.method === 'PUT') { - dataPart = { method: params.method, data: params.data, dataType: 'JSON' }; + const { method, data } = params as JsonParams; + dataPart = { + method, + data, + dataType: 'JSON', + }; } else if (params?.method === 'DELETE') { dataPart = { ...params }; } else { diff --git a/extension/js/common/api/shared/api.ts b/extension/js/common/api/shared/api.ts index 67cabde67d7..1560d5f107b 100644 --- a/extension/js/common/api/shared/api.ts +++ b/extension/js/common/api/shared/api.ts @@ -25,20 +25,36 @@ export type AjaxHeaders = { authorization?: string; ['api-version']?: string; }; +interface GetParams { + method: 'GET' | 'DELETE'; + data?: UrlParams; +} +export interface JsonParams { + method: 'POST' | 'PUT'; + data?: Dict; + dataType?: 'JSON'; +} + +interface TextParams { + method: 'POST' | 'PUT'; + data: string; + contentType?: string; + dataType: 'TEXT'; +} +interface FormParams { + method: 'POST' | 'PUT'; + data: FormData; + dataType: 'FORM'; +} + +export type AjaxParams = GetParams | JsonParams | TextParams | FormParams; export type Ajax = { url: string; headers?: AjaxHeaders; progress?: ProgressCbs; timeout?: number; // todo: implement stack: string; -} & ( - | { method: 'GET' | 'DELETE'; data?: UrlParams } - | { method: 'POST' } - | { method: 'POST' | 'PUT'; data: Dict; dataType: 'JSON' } - | { method: 'POST' | 'PUT'; contentType?: string; data: string; dataType: 'TEXT' } - | { method: 'POST' | 'PUT'; data: FormData; dataType: 'FORM' } - | { method: never; data: never; contentType: never } -); +} & AjaxParams; type RawAjaxErr = { readyState: number; responseText?: string; @@ -157,7 +173,7 @@ export class Api { headersInit.push(['Content-Type', req.contentType]); } } else { - body = req.data; // todo: form data content-type? + body = req.data as FormData; // todo: form data content-type? } } } @@ -291,13 +307,26 @@ export class Api { let data: BodyInit | undefined = formattedData; const headersInit: Dict = req.headers ?? {}; - if (req.method === 'PUT' || req.method === 'POST') { - if ('data' in req && typeof req.data !== 'undefined') { - data = req.dataType === 'JSON' ? JSON.stringify(req.data) : req.data; - - if (req.dataType === 'TEXT' && typeof req.contentType === 'string') { - headersInit['Content-Type'] = req.contentType; - } + if ((req.method === 'PUT' || req.method === 'POST') && 'data' in req) { + switch (req.dataType) { + case 'JSON': + // req.data is Dict + data = JSON.stringify(req.data); + headersInit['Content-Type'] = 'application/json'; + break; + case 'TEXT': + // req.data is string + data = req.data; + if (req.contentType) { + headersInit['Content-Type'] = req.contentType; + } + break; + case 'FORM': + // req.data is FormData + data = req.data; + break; + default: + break; } } const apiReq: JQuery.AjaxSettings = { @@ -385,12 +414,7 @@ export class Api { ): Promise> { progress = progress || ({} as ProgressCbs); let formattedData: FormData | string | undefined; - let dataPart: - | { method: 'GET' } - | { method: 'POST' | 'PUT'; data: Dict; dataType: 'JSON' } - | { method: 'POST' | 'PUT'; data: string; dataType: 'TEXT' } - | { method: 'POST' | 'PUT'; data: FormData; dataType: 'FORM' }; - dataPart = { method: 'GET' }; + let dataPart: AjaxParams = { method: 'GET' }; if (values) { if (values.fmt === 'JSON') { dataPart = { method: values.method ?? 'POST', data: values.data, dataType: 'JSON' };