From ade50d5731de7c3ce298af7871847fe649d757c8 Mon Sep 17 00:00:00 2001 From: VladyslavMartynov10 Date: Sun, 21 Sep 2025 23:12:07 +0300 Subject: [PATCH 1/5] feat: new syntax --- scripts/api-codegen/check-generics.cpp | 65 +-- scripts/api-codegen/compile-all.sh | 0 scripts/api-codegen/query-keys.cpp | 65 ++- scripts/api-codegen/server-hooks.cpp | 227 ++++++---- src/shared/api/auth/AuthService.ts | 113 ++--- src/shared/api/auth/QueryKeys.ts | 20 +- src/shared/api/auth/mutations/index.ts | 3 +- ...leteUser.auth.ts => useCreateUser.Auth.ts} | 12 +- .../mutations/useGetUserAsMutation.auth.ts | 20 - src/shared/api/auth/queries/index.ts | 6 +- .../api/auth/queries/useGetUser.auth.ts | 2 +- .../auth/queries/useGetUserPrefetch.auth.ts | 94 ---- .../useGetUserPrefetchPaginate.auth.ts | 168 ------- ...e.auth.ts => useGetUsersPaginated.Auth.ts} | 38 +- src/shared/api/baseQuery.ts | 3 + src/shared/api/createApi.ts | 424 ++++-------------- yarn.lock | 58 --- 17 files changed, 355 insertions(+), 963 deletions(-) mode change 100644 => 100755 scripts/api-codegen/compile-all.sh rename src/shared/api/auth/mutations/{useDeleteUser.auth.ts => useCreateUser.Auth.ts} (51%) delete mode 100644 src/shared/api/auth/mutations/useGetUserAsMutation.auth.ts delete mode 100644 src/shared/api/auth/queries/useGetUserPrefetch.auth.ts delete mode 100644 src/shared/api/auth/queries/useGetUserPrefetchPaginate.auth.ts rename src/shared/api/auth/queries/{useGetUserPaginate.auth.ts => useGetUsersPaginated.Auth.ts} (77%) diff --git a/scripts/api-codegen/check-generics.cpp b/scripts/api-codegen/check-generics.cpp index 4687255..f4ce2ce 100644 --- a/scripts/api-codegen/check-generics.cpp +++ b/scripts/api-codegen/check-generics.cpp @@ -49,50 +49,33 @@ std::string readFileContent(const std::filesystem::path &filePath) { return buffer.str(); } -void validateEndpoints(const std::filesystem::path &filePath, - const std::string &fileContent) { - std::regex endpointsBlockPattern( - R"(endpoints:\s*builder\s*=>\s*\(\{[^}]+\}\))"); - std::regex endpointPattern( - R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|getAsMutation|post|postAsQuery|delete|put|patch|paginate|paginateAsPrefetch)\s*(<[^>]+>)?\s*\()"); - - std::smatch endpointsMatch; - if (!std::regex_search(fileContent, endpointsMatch, endpointsBlockPattern)) { - std::cout << "⚠️ No endpoints found in file: " << filePath << "\n"; +void validateCreateApiUsage(const std::filesystem::path &filePath, + const std::string &fileContent) { + // Pattern to match createApi() + std::regex createApiPattern( + R"(createApi<([a-zA-Z0-9_]+)>\(\)\()"); + + std::smatch match; + if (!std::regex_search(fileContent, match, createApiPattern)) { + std::cout << "⚠️ No createApi usage found in file: " << filePath << "\n"; return; } - std::sregex_iterator iter(fileContent.begin(), fileContent.end(), - endpointPattern); - std::sregex_iterator end; - - if (iter == end) { - std::cout << "⚠️ No endpoints found in file: " << filePath << "\n"; + std::string interfaceName = match[1].str(); + + // Check if the interface is defined in the same file + std::regex interfacePattern( + R"(interface\s+)" + interfaceName + R"(\s*\{)"); + + if (!std::regex_search(fileContent, interfacePattern)) { + std::cerr << "❌ Error: Interface '" << interfaceName << "' used in createApi<" + << interfaceName << "> is not defined in file '" << filePath << "'.\n"; + std::cerr << "💡 Hint: Make sure to define the interface that describes all endpoints.\n"; + ERROR_FOUND = true; return; } - while (iter != end) { - std::smatch match = *iter; - std::string endpointName = match[1].str(); - std::string generics = match[3].str(); - - if (generics.empty()) { - std::cerr << "❌ Error: Endpoint '" << endpointName << "' in file '" - << filePath << "' is missing generics (no < >).\n"; - ERROR_FOUND = true; - } else { - std::regex genericSplitPattern(R"(<([^,>]+),([^,>]+)>)"); - std::smatch genericsMatch; - if (!std::regex_match(generics, genericsMatch, genericSplitPattern)) { - std::cerr << "❌ Error: Endpoint '" << endpointName << "' in file '" - << filePath - << "' has incorrect generics format (missing a comma or " - "second generic).\n"; - ERROR_FOUND = true; - } - } - ++iter; - } + std::cout << "✅ Found valid createApi<" << interfaceName << "> with interface definition.\n"; } int main() { @@ -123,7 +106,7 @@ int main() { std::cout << "⏳ Processing file: " << path << "\n"; std::string fileContent = readFileContent(path); - validateEndpoints(path, fileContent); + validateCreateApiUsage(path, fileContent); } } } @@ -138,8 +121,8 @@ int main() { return 1; } - std::cout << "\n🎉 No errors found. You passed all necessary generics!\n"; - std::cout << "✅ Generics check completed.\n"; + std::cout << "\n🎉 No errors found. All createApi interfaces are properly defined!\n"; + std::cout << "✅ Interface validation completed.\n"; return 0; } diff --git a/scripts/api-codegen/compile-all.sh b/scripts/api-codegen/compile-all.sh old mode 100644 new mode 100755 diff --git a/scripts/api-codegen/query-keys.cpp b/scripts/api-codegen/query-keys.cpp index 5edf4d7..b24cb86 100644 --- a/scripts/api-codegen/query-keys.cpp +++ b/scripts/api-codegen/query-keys.cpp @@ -70,33 +70,52 @@ void extractEndpoints( std::vector> &queryEndpoints, std::vector &mutationEndpoints) { - std::regex endpointPattern( - R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|paginate|paginateAsPrefetch|post|postAsQuery|delete|put|patch|getAsMutation)<([^>]+)>\([^)]*\))"); - - std::sregex_iterator iter(fileContent.begin(), fileContent.end(), endpointPattern); + // First, find the interface that defines the API + std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))"); + std::smatch createApiMatch; + + if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) { + return; // No createApi found + } + + std::string interfaceName = createApiMatch[1].str(); + + // Find the interface definition + std::regex interfacePattern( + R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})"); + std::smatch interfaceMatch; + + if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) { + return; // Interface not found + } + + std::string interfaceContent = interfaceMatch[1].str(); + + // Extract endpoint definitions from interface (e.g., "getUser: Promisify;") + std::regex endpointDefPattern( + R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)"); + + std::sregex_iterator iter(interfaceContent.begin(), interfaceContent.end(), endpointDefPattern); std::sregex_iterator end; - + while (iter != end) { std::smatch match = *iter; std::string endpointName = match[1].str(); - std::string method = match[2].str(); - std::string fullGeneric = match[3].str(); - - std::stringstream ss(fullGeneric); - std::string responseType, requestType; - std::getline(ss, responseType, ','); - std::getline(ss, requestType, ','); - - responseType.erase( - remove_if(responseType.begin(), responseType.end(), ::isspace), - responseType.end()); + std::string requestType = match[2].str(); + std::string responseType = match[3].str(); + + // Clean up whitespace requestType.erase( remove_if(requestType.begin(), requestType.end(), ::isspace), requestType.end()); - - bool isMutation = method == "post" || method == "postAsQuery" || method == "delete" || - method == "put" || method == "patch" || method == "getAsMutation"; - + responseType.erase( + remove_if(responseType.begin(), responseType.end(), ::isspace), + responseType.end()); + + // Check if it's a mutation by looking at the actual builder usage + std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()"); + bool isMutation = std::regex_search(fileContent, mutationPattern); + if (!requestType.empty() && requestType != "void" && requestType != "unknown" && requestType != "null" && requestType != "any" && requestType != "boolean" && @@ -104,17 +123,17 @@ void extractEndpoints( requestType != "false" && requestType != "Object" && requestType != "{}" && requestType != "0" && requestType != "1" && requestType != "BigInt" && requestType != "[]") { - if (!isMutation && std::find(usedInterfaces.begin(), usedInterfaces.end(), requestType) == usedInterfaces.end()) { + if (std::find(usedInterfaces.begin(), usedInterfaces.end(), requestType) == usedInterfaces.end()) { usedInterfaces.push_back(requestType); } } - + if (isMutation) { mutationEndpoints.push_back(endpointName); } else { queryEndpoints.push_back({endpointName, requestType}); } - + ++iter; } } diff --git a/scripts/api-codegen/server-hooks.cpp b/scripts/api-codegen/server-hooks.cpp index ce2c569..7529b29 100644 --- a/scripts/api-codegen/server-hooks.cpp +++ b/scripts/api-codegen/server-hooks.cpp @@ -7,67 +7,59 @@ #include #include + const std::filesystem::path API_DIR = "./src/shared/api"; const std::string QUERY_KEYS_FILE = "src/shared/api/models/QueryKeys.ts"; const std::unordered_set EXCLUDED_FOLDERS = {"models"}; const std::string LOCK_FILE = "./codegen.lock"; -std::string toCamelCase(const std::string &input) -{ - std::stringstream ss(input); - std::string word, result; - bool first = true; - - while (std::getline(ss, word, '_')) - { - if (first) - { - result += std::tolower(word[0]); - result += word.substr(1); - first = false; - } - else - { - word[0] = std::toupper(word[0]); - result += word; +std::string toCamelCase(const std::string& input) { + std::stringstream ss(input); + std::string word, result; + bool first = true; + + while (std::getline(ss, word, '_')) { + if (first) { + result += std::tolower(word[0]); + result += word.substr(1); + first = false; + } else { + word[0] = std::toupper(word[0]); + result += word; + } } - } - return result; + return result; } -std::string toCapitalize(const std::string &input) -{ - if (input.empty()) - return input; - std::string result = input; - result[0] = std::toupper(result[0]); - return result; +std::string capitalizeFirstLetter(const std::string& input) { + if (input.empty()) return input; + std::string result = input; + result[0] = std::toupper(result[0]); + return result; } -std::string extractServicePrefix(const std::string &serviceName) -{ - std::string prefix = serviceName; +std::string toSnakeCase(const std::string& input) { + std::string result; + for (size_t i = 0; i < input.length(); i++) { + if (std::isupper(input[i]) && i > 0) { + result += "_"; + } + result += std::tolower(input[i]); + } + return result; +} - if (prefix.find("Service") != std::string::npos) - { - prefix = prefix.substr(0, prefix.find("Service")); - } - return toCamelCase(prefix); +std::string toCapitalize(const std::string& input) { + return capitalizeFirstLetter(input); } -std::string toSnakeCase(const std::string &input) -{ - std::string result; - for (char c : input) - { - if (std::isupper(c) && !result.empty()) - { - result += "_"; +std::string extractServicePrefix(const std::string& serviceName) { + std::string result = serviceName; + if (result.size() > 7 && result.substr(result.size() - 7) == "Service") { + result = result.substr(0, result.size() - 7); } - result += std::toupper(c); - } - return result; + return result; } std::string generateHash(const std::filesystem::path &filePath) @@ -84,7 +76,7 @@ std::string generateHash(const std::filesystem::path &filePath) std::string fileContent = fileContentStream.str(); std::regex methodPattern( - R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|getAsMutation|post|postAsQuery|delete|put|patch|paginate|paginateAsPrefetch)<\s*([^,]+),\s*([^>]+)>)"); + R"(([a-zA-Z0-9_]+):\s*builder\.(query|prefetch|mutation|infiniteQuery|prefetchInfiniteQuery)\s*\()"); std::sregex_iterator it(fileContent.begin(), fileContent.end(), methodPattern); std::sregex_iterator end; @@ -110,27 +102,17 @@ std::string normalizeType(const std::string &type) return std::regex_replace(type, std::regex(R"(\[\]$)"), ""); } -std::string capitalizeFirstLetter(const std::string &str) -{ - if (str.empty()) - return str; - std::string capitalized = str; - capitalized[0] = toupper(capitalized[0]); - return capitalized; -} -std::string readFile(const std::filesystem::path &filePath) -{ - std::ifstream file(filePath); - if (!file.is_open()) - { - std::cerr << "❌ Error: Unable to open file: " << filePath << "\n"; - return ""; - } +std::string readFileContent(const std::filesystem::path& filePath) { + std::ifstream file(filePath); + if (!file.is_open()) { + std::cerr << "❌ Error: Unable to open file: " << filePath << "\n"; + return ""; + } - std::ostringstream content; - content << file.rdbuf(); - return content.str(); + std::ostringstream fileContentStream; + fileContentStream << file.rdbuf(); + return fileContentStream.str(); } bool isExcludedFolder(const std::string &folderName, @@ -315,7 +297,7 @@ void generateQueryHook( << " = async ({ params, signal }: QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "(params, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = (params: " << requestType @@ -437,7 +419,7 @@ void generateQueryHook( << " = async ({ signal }:QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "(undefined, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = () => queryKeys." << queryKeyName @@ -598,7 +580,7 @@ void generatePrefetchQueryHook( << " = async ({ params, signal }: QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "(params, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = (params: " << requestType @@ -677,7 +659,7 @@ void generatePrefetchQueryHook( << " = async ({ signal }:QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "(undefined, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = () => queryKeys." << queryKeyName @@ -848,7 +830,7 @@ void generateInfiniteQueryHook( << "}: QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "({ ...params, pageParam }, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = (params: " << requestType << ") => queryKeys." @@ -1058,7 +1040,7 @@ void generatePrefetchInfiniteQueryHook( << "}: QueryFnParams) => {\n" << " const response = await " << serviceName << "." << endpointName << "({ ...params, pageParam }, { signal });\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getQueryKey = (params: " << requestType << ") => queryKeys." @@ -1215,7 +1197,7 @@ void generateMutationHook(const std::filesystem::path &hooksDir, << " = async (params: " << inlineRequestType << ") => {\n" << " const response = await " << serviceName << "." << endpointName << "(params);\n" - << " return response?.data;\n" + << " return response;\n" << "};\n\n"; outFile << "const getMutationKey = () => queryKeys." << queryKeyName @@ -1305,65 +1287,117 @@ void generateHooks(const std::string &serviceName, std::filesystem::create_directories(hooksDir / "queries"); std::filesystem::create_directories(hooksDir / "mutations"); - std::string fileContent = readFile(serviceFile); + std::string fileContent = readFileContent(serviceFile); if (fileContent.empty()) { return; } - std::regex methodPattern( - R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|getAsMutation|post|postAsQuery|delete|put|patch|paginate|paginateAsPrefetch)<\s*([^,]+),\s*([^>]+)>)"); - + // First, find the interface that defines the API + std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))"); + std::smatch createApiMatch; + + if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) { + return; // No createApi found + } + + std::string interfaceName = createApiMatch[1].str(); + + // Find the interface definition + std::regex interfacePattern( + R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})"); + std::smatch interfaceMatch; + + if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) { + return; // Interface not found + } + + std::string interfaceContent = interfaceMatch[1].str(); + + // Extract endpoint definitions from interface + std::regex endpointDefPattern( + R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)"); + + std::sregex_iterator interfaceIter(interfaceContent.begin(), interfaceContent.end(), endpointDefPattern); + std::sregex_iterator interfaceEnd; + std::unordered_set detectedQueries; std::unordered_set detectedMutations; bool hasQueries = false; bool hasMutations = false; - std::sregex_iterator it(fileContent.begin(), fileContent.end(), methodPattern); - std::sregex_iterator end; - - for (; it != end; ++it) + for (; interfaceIter != interfaceEnd; ++interfaceIter) { - std::smatch match = *it; + std::smatch match = *interfaceIter; std::string endpointName = match[1].str(); - std::string method = match[2].str(); + std::string requestType = match[2].str(); std::string responseType = match[3].str(); - std::string requestType = match[4].str(); + + // Clean up whitespace + requestType.erase( + remove_if(requestType.begin(), requestType.end(), ::isspace), + requestType.end()); + responseType.erase( + remove_if(responseType.begin(), responseType.end(), ::isspace), + responseType.end()); std::string hookName = "use" + capitalizeFirstLetter(endpointName); std::string servicePrefix = extractServicePrefix(serviceName); std::string queryKeyName = toCamelCase(endpointName) + toCapitalize(serviceName); bool isVoidRequest = requestType == "void"; - - if (method == "get" || method == "postAsQuery") + + // Check what method type this endpoint uses + std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()"); + std::regex queryPattern(endpointName + R"(:\s*builder\.query\s*\()"); + std::regex infiniteQueryPattern(endpointName + R"(:\s*builder\.infiniteQuery\s*\()"); + std::regex prefetchPattern(endpointName + R"(:\s*builder\.prefetch\s*\()"); + std::regex prefetchInfiniteQueryPattern(endpointName + R"(:\s*builder\.prefetchInfiniteQuery\s*\()"); + + bool isMutation = std::regex_search(fileContent, mutationPattern); + bool isQuery = std::regex_search(fileContent, queryPattern); + bool isInfiniteQuery = std::regex_search(fileContent, infiniteQueryPattern); + bool isPrefetch = std::regex_search(fileContent, prefetchPattern); + bool isPrefetchInfiniteQuery = std::regex_search(fileContent, prefetchInfiniteQueryPattern); + + if (isMutation) + { + hasMutations = true; + generateMutationHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedMutations.insert(hookName); + } + else if (isQuery) { hasQueries = true; generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); detectedQueries.insert(hookName); } - else if (method == "getAsPrefetch") + else if (isInfiniteQuery) + { + hasQueries = true; + generateInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isPrefetch) { hasQueries = true; generatePrefetchQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); detectedQueries.insert(hookName); } - else if (method == "paginate" || method == "paginateAsPrefetch") + else if (isPrefetchInfiniteQuery) { hasQueries = true; - generateInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + generatePrefetchInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); detectedQueries.insert(hookName); } - else if (std::regex_match( - method, - std::regex(R"(post|getAsMutation|delete|put|patch)"))) + else { - hasMutations = true; - generateMutationHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - - detectedMutations.insert(hookName); + // Default to query if method not recognized + hasQueries = true; + generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); } } @@ -1424,6 +1458,7 @@ int main() continue; } + std::cout << "🗑️ Removing old generated files...\n"; removeGeneratedFiles(serviceDir); diff --git a/src/shared/api/auth/AuthService.ts b/src/shared/api/auth/AuthService.ts index e62f597..a11f2fe 100644 --- a/src/shared/api/auth/AuthService.ts +++ b/src/shared/api/auth/AuthService.ts @@ -1,84 +1,43 @@ -import { createApi } from 'api/createApi'; -import { baseQuery } from '../baseQuery'; +import { createApi, Promisify } from '../createApi'; +import { axiosBaseQuery } from '../baseQuery'; import { CreateAccountResponse, Test } from './models'; -export const AuthService = createApi({ - baseQuery, +interface AuthServiceAPI { + getUser: Promisify; + createUser: Promisify; + getUsersPaginated: Promisify; +} + +export const AuthService = createApi()({ + baseQuery: axiosBaseQuery, endpoints: builder => ({ - getUser: builder.get({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, - }), - getUserPrefetch: builder.getAsPrefetch({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, - }), - getUserPaginate: builder.paginate({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, - }), - getUserPrefetchPaginate: builder.paginateAsPrefetch< - CreateAccountResponse, - Test - >({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, - }), - getUserAsMutation: builder.getAsMutation({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, + getUser: builder.query(({ token }, { signal, client }) => { + return client.get(`/v2/customer/`, { + params: { test: 'test12' }, + headers: { Authorization: `Bearer ${token}` }, + signal, + }); }), - deleteUser: builder.delete({ - query: ({ token }) => ({ - url: `/v2/customer/`, - params: { - test: 'test12', - }, - headers: { - Authorization: `Bearer ${token}`, - }, - }), - disableGlobalErrorHandler: true, + + createUser: builder.mutation(async ({ token }, { client }) => { + const query = await client.post( + `/v2/customer/`, + { token }, + { + headers: { Authorization: `Bearer ${token}` }, + }, + ); + + return query.data; }), + + getUsersPaginated: builder.infiniteQuery( + ({ token }, { signal, client }) => { + return client.get(`/v2/customer/paginated`, { + params: { token }, + signal, + }); + }, + ), }), }); diff --git a/src/shared/api/auth/QueryKeys.ts b/src/shared/api/auth/QueryKeys.ts index a21d9c6..44db46f 100644 --- a/src/shared/api/auth/QueryKeys.ts +++ b/src/shared/api/auth/QueryKeys.ts @@ -2,24 +2,14 @@ import { Test } from './models'; const QUERY_KEYS = { GET_USER_AUTH_SERVICE: 'GET_USER_AUTH_SERVICE', - GET_USER_PREFETCH_AUTH_SERVICE: 'GET_USER_PREFETCH_AUTH_SERVICE', - GET_USER_PAGINATE_AUTH_SERVICE: 'GET_USER_PAGINATE_AUTH_SERVICE', - GET_USER_PREFETCH_PAGINATE_AUTH_SERVICE: - 'GET_USER_PREFETCH_PAGINATE_AUTH_SERVICE', - GET_USER_AS_MUTATION_AUTH_SERVICE: 'GET_USER_AS_MUTATION_AUTH_SERVICE', - DELETE_USER_AUTH_SERVICE: 'DELETE_USER_AUTH_SERVICE', + GET_USERS_PAGINATED_AUTH_SERVICE: 'GET_USERS_PAGINATED_AUTH_SERVICE', + CREATE_USER_AUTH_SERVICE: 'CREATE_USER_AUTH_SERVICE', } as const; export const AUTH_QUERY_KEYS = { getUserAuthService: (params: Test) => [QUERY_KEYS.GET_USER_AUTH_SERVICE, params] as const, - getUserPrefetchAuthService: (params: Test) => - [QUERY_KEYS.GET_USER_PREFETCH_AUTH_SERVICE, params] as const, - getUserPaginateAuthService: (params: Test) => - [QUERY_KEYS.GET_USER_PAGINATE_AUTH_SERVICE, params] as const, - getUserPrefetchPaginateAuthService: (params: Test) => - [QUERY_KEYS.GET_USER_PREFETCH_PAGINATE_AUTH_SERVICE, params] as const, - getUserAsMutationAuthService: () => - [QUERY_KEYS.GET_USER_AS_MUTATION_AUTH_SERVICE] as const, - deleteUserAuthService: () => [QUERY_KEYS.DELETE_USER_AUTH_SERVICE] as const, + getUsersPaginatedAuthService: (params: Test) => + [QUERY_KEYS.GET_USERS_PAGINATED_AUTH_SERVICE, params] as const, + createUserAuthService: () => [QUERY_KEYS.CREATE_USER_AUTH_SERVICE] as const, }; diff --git a/src/shared/api/auth/mutations/index.ts b/src/shared/api/auth/mutations/index.ts index 40bd090..dbce154 100644 --- a/src/shared/api/auth/mutations/index.ts +++ b/src/shared/api/auth/mutations/index.ts @@ -1,2 +1 @@ -export * from './useGetUserAsMutation.auth'; -export * from './useDeleteUser.auth'; +export * from './useCreateUser.Auth'; diff --git a/src/shared/api/auth/mutations/useDeleteUser.auth.ts b/src/shared/api/auth/mutations/useCreateUser.Auth.ts similarity index 51% rename from src/shared/api/auth/mutations/useDeleteUser.auth.ts rename to src/shared/api/auth/mutations/useCreateUser.Auth.ts index 4a5f8cf..540f4bb 100644 --- a/src/shared/api/auth/mutations/useDeleteUser.auth.ts +++ b/src/shared/api/auth/mutations/useCreateUser.Auth.ts @@ -4,17 +4,17 @@ import { AuthService } from '../AuthService'; import { Test, CreateAccountResponse } from '../models'; -export const deleteUserMutationFnAuthService = async (params: Test) => { - const response = await AuthService.deleteUser(params); +export const createUserMutationFnAuthService = async (params: Test) => { + const response = await AuthService.createUser(params); - return response?.data; + return response; }; -const getMutationKey = () => queryKeys.deleteUserAuthService(); +const getMutationKey = () => queryKeys.createUserAuthService(); -export const useDeleteUserMutationAuthService = () => { +export const useCreateUserMutationAuthService = () => { return useMutation({ - mutationFn: deleteUserMutationFnAuthService, + mutationFn: createUserMutationFnAuthService, mutationKey: getMutationKey(), }); }; diff --git a/src/shared/api/auth/mutations/useGetUserAsMutation.auth.ts b/src/shared/api/auth/mutations/useGetUserAsMutation.auth.ts deleted file mode 100644 index 789699b..0000000 --- a/src/shared/api/auth/mutations/useGetUserAsMutation.auth.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useMutation } from '@tanstack/react-query'; -import { QueryError, queryKeys } from '../../models'; -import { AuthService } from '../AuthService'; - -import { Test, CreateAccountResponse } from '../models'; - -export const getUserAsMutationMutationFnAuthService = async (params: Test) => { - const response = await AuthService.getUserAsMutation(params); - - return response?.data; -}; - -const getMutationKey = () => queryKeys.getUserAsMutationAuthService(); - -export const useGetUserAsMutationMutationAuthService = () => { - return useMutation({ - mutationFn: getUserAsMutationMutationFnAuthService, - mutationKey: getMutationKey(), - }); -}; diff --git a/src/shared/api/auth/queries/index.ts b/src/shared/api/auth/queries/index.ts index 559fa1a..d4623ff 100644 --- a/src/shared/api/auth/queries/index.ts +++ b/src/shared/api/auth/queries/index.ts @@ -1,4 +1,2 @@ -export * from './useGetUser.auth'; -export * from './useGetUserPrefetch.auth'; -export * from './useGetUserPaginate.auth'; -export * from './useGetUserPrefetchPaginate.auth'; +export * from './useGetUser.Auth'; +export * from './useGetUsersPaginated.Auth'; diff --git a/src/shared/api/auth/queries/useGetUser.auth.ts b/src/shared/api/auth/queries/useGetUser.auth.ts index 604dc0b..0573bb9 100644 --- a/src/shared/api/auth/queries/useGetUser.auth.ts +++ b/src/shared/api/auth/queries/useGetUser.auth.ts @@ -58,7 +58,7 @@ export const getUserQueryFnAuthService = async ({ }: QueryFnParams) => { const response = await AuthService.getUser(params, { signal }); - return response?.data; + return response; }; const getQueryKey = (params: Test) => queryKeys.getUserAuthService(params); diff --git a/src/shared/api/auth/queries/useGetUserPrefetch.auth.ts b/src/shared/api/auth/queries/useGetUserPrefetch.auth.ts deleted file mode 100644 index c1ade30..0000000 --- a/src/shared/api/auth/queries/useGetUserPrefetch.auth.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { InvalidateQueryFilters } from '@tanstack/react-query'; -import { getQueryClient } from '../../queryClient'; -import { - QueryError, - QueryKeyType, - UsePrefetchQueryWithOptionsParams, - QueryFetchParams, - queryKeys, -} from '../../models'; -import { usePrefetchQueryWithOptions } from '../../hooks'; -import { AuthService } from '../AuthService'; - -import { CreateAccountResponse, Test } from '../models'; - -interface HookParams extends Test { - options?: UsePrefetchQueryWithOptionsParams< - CreateAccountResponse, - QueryError, - TData, - QueryKeyType - >['options']; -} - -interface QueryFnParams { - params: Test; - meta?: Record | undefined; - queryKey?: QueryKeyType; - signal?: AbortSignal; -} - -export const getUserPrefetchQueryFnAuthService = async ({ - params, - signal, -}: QueryFnParams) => { - const response = await AuthService.getUserPrefetch(params, { signal }); - - return response?.data; -}; - -const getQueryKey = (params: Test) => - queryKeys.getUserPrefetchAuthService(params); - -export const getUserPrefetchPrefetchQueryAuthService = < - TData = CreateAccountResponse, - TError = QueryError, ->({ - params, - fetchOptions, -}: QueryFetchParams) => { - const queryClient = getQueryClient(); - - return queryClient.prefetchQuery< - CreateAccountResponse, - TError, - TData, - QueryKeyType - >({ - queryKey: getQueryKey(params), - queryFn: ({ signal }) => - getUserPrefetchQueryFnAuthService({ params, signal }), - ...fetchOptions, - }); -}; - -export const useGetUserPrefetchPrefetchQueryAuthService = < - TData = CreateAccountResponse, ->({ - options, - ...params -}: HookParams) => { - return usePrefetchQueryWithOptions< - CreateAccountResponse, - QueryError, - TData, - QueryKeyType - >({ - queryFn: ({ signal }) => - getUserPrefetchQueryFnAuthService({ params, signal }), - queryKey: getQueryKey(params), - options, - }); -}; - -export const invalidateGetUserPrefetchQueryAuthService = ( - params: Test, - options?: Omit, -) => { - const queryClient = getQueryClient(); - - return queryClient.invalidateQueries({ - queryKey: getQueryKey(params), - ...options, - }); -}; diff --git a/src/shared/api/auth/queries/useGetUserPrefetchPaginate.auth.ts b/src/shared/api/auth/queries/useGetUserPrefetchPaginate.auth.ts deleted file mode 100644 index 296f7a3..0000000 --- a/src/shared/api/auth/queries/useGetUserPrefetchPaginate.auth.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { InvalidateQueryFilters, InfiniteData } from '@tanstack/react-query'; -import { getQueryClient } from '../../queryClient'; -import { - InfiniteQueryFetchParams, - QueryError, - QueryKeyType, - UseInfiniteQueryWithOptionsParams, - queryKeys, -} from '../../models'; -import { useInfiniteQueryWithOptions } from '../../hooks'; -import { AuthService } from '../AuthService'; - -import { CreateAccountResponse, Test } from '../models'; - -type PageParam = string | number | unknown; - -interface InfiniteHookParams extends Test { - initialPageParam: TPageParam; - getNextPageParam: UseInfiniteQueryWithOptionsParams< - CreateAccountResponse, - QueryError, - TData, - QueryKeyType, - TPageParam - >['getNextPageParam']; - options?: UseInfiniteQueryWithOptionsParams< - CreateAccountResponse, - QueryError, - TData, - QueryKeyType, - TPageParam - >['options']; -} - -interface InfiniteFetchParams extends Test { - initialPageParam: TPageParam; - getNextPageParam: InfiniteQueryFetchParams< - CreateAccountResponse, - QueryError, - InfiniteData, - Test, - QueryKeyType, - TPageParam - >['getNextPageParam']; - options?: InfiniteQueryFetchParams< - CreateAccountResponse, - QueryError, - InfiniteData, - Test, - QueryKeyType, - TPageParam - >['fetchOptions']; -} - -interface QueryFnParams { - params: Test; - pageParam: TPageParam; - signal: AbortSignal; -} - -export const getUserPrefetchPaginateQueryFnAuthService = async < - TPageParam extends PageParam, ->({ - params, - pageParam, - signal, -}: QueryFnParams) => { - const response = await AuthService.getUserPrefetchPaginate( - { ...params, pageParam }, - { signal }, - ); - - return response?.data; -}; - -const getQueryKey = (params: Test) => - queryKeys.getUserPrefetchPaginateAuthService(params); - -export const getUserPrefetchPaginateInfiniteQueryAuthService = < - TData = CreateAccountResponse, - TPageParam = PageParam, ->({ - initialPageParam, - getNextPageParam, - options, - ...params -}: InfiniteFetchParams) => { - const queryClient = getQueryClient(); - - return queryClient.fetchInfiniteQuery< - CreateAccountResponse, - QueryError, - InfiniteData, - QueryKeyType, - TPageParam - >({ - queryFn: ({ pageParam, signal }) => - getUserPrefetchPaginateQueryFnAuthService({ pageParam, params, signal }), - queryKey: getQueryKey(params), - initialPageParam, - getNextPageParam, - ...options, - }); -}; - -export const useGetUserPrefetchPaginateInfiniteQueryAuthService = < - TData = CreateAccountResponse, - TPageParam = PageParam, ->({ - options, - initialPageParam, - getNextPageParam, - ...params -}: InfiniteHookParams) => { - return useInfiniteQueryWithOptions< - CreateAccountResponse, - QueryError, - TData, - QueryKeyType, - TPageParam - >({ - queryFn: ({ pageParam, signal }) => - getUserPrefetchPaginateQueryFnAuthService({ pageParam, params, signal }), - queryKey: getQueryKey(params), - initialPageParam, - getNextPageParam, - options, - }); -}; - -export const invalidateGetUserPrefetchPaginateInfiniteQueryAuthService = ( - params: Test, - options?: Omit, -) => { - const queryClient = getQueryClient(); - - return queryClient.invalidateQueries({ - queryKey: getQueryKey(params), - ...options, - }); -}; - -export const resetGetUserPrefetchPaginateInfiniteQueryAuthService = async < - TPageParam = PageParam, ->( - params: Test, -): Promise => { - const queryClient = getQueryClient(); - const queryKey = getQueryKey(params); - - queryClient.setQueryData( - queryKey, - (oldData: InfiniteData) => { - if (!oldData) { - return undefined; - } - - return { - pages: oldData.pages.slice(0, 1), - pageParams: oldData.pageParams.slice(0, 1), - }; - }, - ); - - await queryClient.invalidateQueries({ - queryKey: getQueryKey(params), - }); -}; diff --git a/src/shared/api/auth/queries/useGetUserPaginate.auth.ts b/src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts similarity index 77% rename from src/shared/api/auth/queries/useGetUserPaginate.auth.ts rename to src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts index 69413d1..cf838d9 100644 --- a/src/shared/api/auth/queries/useGetUserPaginate.auth.ts +++ b/src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts @@ -17,14 +17,14 @@ type PageParam = string | number | unknown; interface InfiniteHookParams extends Test { initialPageParam: TPageParam; getNextPageParam: UseInfiniteQueryWithOptionsParams< - CreateAccountResponse, + CreateAccountResponse[], QueryError, TData, QueryKeyType, TPageParam >['getNextPageParam']; options?: UseInfiniteQueryWithOptionsParams< - CreateAccountResponse, + CreateAccountResponse[], QueryError, TData, QueryKeyType, @@ -35,7 +35,7 @@ interface InfiniteHookParams extends Test { interface InfiniteFetchParams extends Test { initialPageParam: TPageParam; getNextPageParam: InfiniteQueryFetchParams< - CreateAccountResponse, + CreateAccountResponse[], QueryError, InfiniteData, Test, @@ -43,7 +43,7 @@ interface InfiniteFetchParams extends Test { TPageParam >['getNextPageParam']; options?: InfiniteQueryFetchParams< - CreateAccountResponse, + CreateAccountResponse[], QueryError, InfiniteData, Test, @@ -58,26 +58,26 @@ interface QueryFnParams { signal: AbortSignal; } -export const getUserPaginateQueryFnAuthService = async < +export const getUsersPaginatedQueryFnAuthService = async < TPageParam extends PageParam, >({ params, pageParam, signal, }: QueryFnParams) => { - const response = await AuthService.getUserPaginate( + const response = await AuthService.getUsersPaginated( { ...params, pageParam }, { signal }, ); - return response?.data; + return response; }; const getQueryKey = (params: Test) => - queryKeys.getUserPaginateAuthService(params); + queryKeys.getUsersPaginatedAuthService(params); -export const getUserPaginateInfiniteQueryAuthService = < - TData = CreateAccountResponse, +export const getUsersPaginatedInfiniteQueryAuthService = < + TData = CreateAccountResponse[], TPageParam = PageParam, >({ initialPageParam, @@ -88,14 +88,14 @@ export const getUserPaginateInfiniteQueryAuthService = < const queryClient = getQueryClient(); return queryClient.fetchInfiniteQuery< - CreateAccountResponse, + CreateAccountResponse[], QueryError, InfiniteData, QueryKeyType, TPageParam >({ queryFn: ({ pageParam, signal }) => - getUserPaginateQueryFnAuthService({ pageParam, params, signal }), + getUsersPaginatedQueryFnAuthService({ pageParam, params, signal }), queryKey: getQueryKey(params), initialPageParam, getNextPageParam, @@ -103,8 +103,8 @@ export const getUserPaginateInfiniteQueryAuthService = < }); }; -export const useGetUserPaginateInfiniteQueryAuthService = < - TData = CreateAccountResponse, +export const useGetUsersPaginatedInfiniteQueryAuthService = < + TData = CreateAccountResponse[], TPageParam = PageParam, >({ options, @@ -113,14 +113,14 @@ export const useGetUserPaginateInfiniteQueryAuthService = < ...params }: InfiniteHookParams) => { return useInfiniteQueryWithOptions< - CreateAccountResponse, + CreateAccountResponse[], QueryError, TData, QueryKeyType, TPageParam >({ queryFn: ({ pageParam, signal }) => - getUserPaginateQueryFnAuthService({ pageParam, params, signal }), + getUsersPaginatedQueryFnAuthService({ pageParam, params, signal }), queryKey: getQueryKey(params), initialPageParam, getNextPageParam, @@ -128,7 +128,7 @@ export const useGetUserPaginateInfiniteQueryAuthService = < }); }; -export const invalidateGetUserPaginateInfiniteQueryAuthService = ( +export const invalidateGetUsersPaginatedInfiniteQueryAuthService = ( params: Test, options?: Omit, ) => { @@ -140,7 +140,7 @@ export const invalidateGetUserPaginateInfiniteQueryAuthService = ( }); }; -export const resetGetUserPaginateInfiniteQueryAuthService = async < +export const resetGetUsersPaginatedInfiniteQueryAuthService = async < TPageParam = PageParam, >( params: Test, @@ -150,7 +150,7 @@ export const resetGetUserPaginateInfiniteQueryAuthService = async < queryClient.setQueryData( queryKey, - (oldData: InfiniteData) => { + (oldData: InfiniteData) => { if (!oldData) { return undefined; } diff --git a/src/shared/api/baseQuery.ts b/src/shared/api/baseQuery.ts index ff22e2f..0ddf0b4 100644 --- a/src/shared/api/baseQuery.ts +++ b/src/shared/api/baseQuery.ts @@ -1,11 +1,14 @@ import Config from 'react-native-config'; import { ExceptionService, ToastService } from 'services'; import { getAuthStoreInstance, resetAllStores } from 'stores'; +import axios from 'axios'; import { Mutex } from 'async-mutex'; import { createAxiosClient } from './http-client'; export const refreshMutex = new Mutex(); +export const axiosBaseQuery = axios.create({ baseURL: '' }); + export const baseQuery = createAxiosClient({ baseURL: Config.API_URL || '', getToken: () => { diff --git a/src/shared/api/createApi.ts b/src/shared/api/createApi.ts index 5abf879..bbef7b4 100644 --- a/src/shared/api/createApi.ts +++ b/src/shared/api/createApi.ts @@ -1,367 +1,113 @@ -import { ApiBuilder, HTTPClient, QueryReturnType } from './types'; - -export const createApi = ({ - baseQuery, - endpoints, -}: { - baseQuery: HTTPClient; - endpoints: (builder: ApiBuilder) => TEndpoints; -}): TEndpoints => { - const builder: ApiBuilder = { - get: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; +export type Promisify = ( + params: TRequest, + extra?: { signal?: AbortSignal }, +) => Promise; + +type GenericApiBuilder = { + query( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async ( - requestOptions: P, - extra?: { signal?: AbortSignal }, - ): Promise<{ data: TResponse }> => { - const { url, params, headers } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'get', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, - signal: extra?.signal, - }); - - return response; }, - - getAsPrefetch: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + prefetch( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async ( - requestOptions: P, - extra?: { signal?: AbortSignal }, - ): Promise<{ data: TResponse }> => { - const { url, params, headers } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'get', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, - signal: extra?.signal, - }); - - return response; }, - - getAsMutation: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + mutation( + mutationFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async (requestOptions: P): Promise<{ data: TResponse }> => { - const { url, headers, params } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'get', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, - }); - - return response; }, - - paginate: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + infiniteQuery( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async ( - requestOptions: P, - extra?: { signal?: AbortSignal }, - ): Promise<{ data: TResponse }> => { - const { url, params, headers } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'get', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, - signal: extra?.signal, - }); - - return response; }, - - paginateAsPrefetch: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + prefetchInfiniteQuery( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async ( - requestOptions: P, - extra?: { signal?: AbortSignal }, - ): Promise<{ data: TResponse }> => { - const { url, params, headers } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; + }, + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; +}; - const response = await queryInstance.request({ - method: 'get', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, +export const createApi = + () => + (config: { + baseQuery: TClient; + endpoints: (builder: GenericApiBuilder) => TServiceInterface; + }): TServiceInterface => { + const { baseQuery, endpoints } = config; + const builder: GenericApiBuilder = { + query: queryFn => (params, extra) => { + return queryFn(params, { signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, }); - - return response; }, - delete: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: P) => QueryReturnType; - overrideBaseQuery?: boolean; - disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async (requestOptions: P): Promise<{ data: TResponse }> => { - const { url, params, headers } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'delete', - url, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, + prefetch: queryFn => (params, extra) => { + return queryFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, }); - - return response; }, - post: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: TBody) => QueryReturnType; - overrideBaseQuery?: boolean; - disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async (requestOptions: TBody): Promise<{ data: TResponse }> => { - const { url, data, headers, params } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'post', - url, - data, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, + mutation: mutationFn => (params, extra) => { + return mutationFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, }); - - return response; }, - postAsQuery: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: TBody) => QueryReturnType; - overrideBaseQuery?: boolean; - disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async ( - requestOptions: TBody, - extra?: { signal?: AbortSignal }, - ): Promise<{ data: TResponse }> => { - const { url, data, headers, params } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'post', - url, - data, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, + infiniteQuery: queryFn => (params, extra) => { + return queryFn(params, { signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, }); - - return response; }, - put: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (options: TBody) => QueryReturnType; - overrideBaseQuery?: boolean; - disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async (requestOptions: TBody): Promise<{ data: TResponse }> => { - const { url, data, headers, params } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'put', - url, - data, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, + prefetchInfiniteQuery: queryFn => (params, extra) => { + return queryFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, }); - - return response; }, + }; - patch: - ({ - query, - overrideBaseQuery, - disableGlobalErrorHandler, - baseQuery: customBaseQuery, - }: { - query: (requestOptions: TBody) => QueryReturnType; - overrideBaseQuery?: boolean; - disableGlobalErrorHandler?: boolean; - baseQuery?: HTTPClient; - }) => - async (requestOptions: TBody): Promise<{ data: TResponse }> => { - const { data, params, headers, url } = query(requestOptions); - - const queryInstance = - overrideBaseQuery && customBaseQuery ? customBaseQuery : baseQuery; - - const response = await queryInstance.request({ - method: 'patch', - url, - data, - params, - headers: { - ...headers, - 'x-disable-global-toast': disableGlobalErrorHandler - ? 'false' - : 'true', - }, - }); - - return response; - }, + return endpoints(builder); }; - - return endpoints(builder); -}; diff --git a/yarn.lock b/yarn.lock index 93081d6..b0808da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4020,9 +4020,6 @@ __metadata: react-native-svg-transformer: "npm:^1.5.0" react-native-unistyles: "npm:3.0.10" react-native-vector-icons: "npm:10.2.0" - reactotron-react-native: "npm:^5.1.15" - reactotron-react-native-mmkv: "npm:^0.2.8" - reactotron-react-query: "npm:^2.0.2" sonner-native: "npm:0.21.1" ts-to-zod: "npm:3.8.5" typescript: "npm:5.0.4" @@ -9384,13 +9381,6 @@ __metadata: languageName: node linkType: hard -"mitt@npm:^3.0.1": - version: 3.0.1 - resolution: "mitt@npm:3.0.1" - checksum: 10c0/3ab4fdecf3be8c5255536faa07064d05caa3dd332bd318ff02e04621f7b3069ca1de9106cfe8e7ced675abfc2bec2ce4c4ef321c4a1bb1fb29df8ae090741913 - languageName: node - linkType: hard - "mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" @@ -10763,54 +10753,6 @@ __metadata: languageName: node linkType: hard -"reactotron-core-client@npm:2.9.7": - version: 2.9.7 - resolution: "reactotron-core-client@npm:2.9.7" - dependencies: - reactotron-core-contract: "npm:0.2.5" - checksum: 10c0/c18f93761feeadd043461b59ad0dee748d8a6ab0ac01beecda9653fdd190e15ecccd55d246a8ac25058f2b74b4d62ff07861f3fb0856d1995418b45886170485 - languageName: node - linkType: hard - -"reactotron-core-contract@npm:0.2.5": - version: 0.2.5 - resolution: "reactotron-core-contract@npm:0.2.5" - checksum: 10c0/4cf35d9f5e442bbbd32346f9b9ae26e4dd2400ffb9abc618d039df3b3398eaef1fb59c9df04703d6da4e2786f2922454a454c5522c055c8300146da3d6754508 - languageName: node - linkType: hard - -"reactotron-react-native-mmkv@npm:^0.2.8": - version: 0.2.8 - resolution: "reactotron-react-native-mmkv@npm:0.2.8" - peerDependencies: - react-native-mmkv: "*" - reactotron-core-client: "*" - checksum: 10c0/77b81c2ad4b0856127a649ce9dab04b53cb0148f302309574abe27f4de5c1f63e289108454fa12d4f513064af19e54530ea86bff0d857fa40dbf629a22ccf8ed - languageName: node - linkType: hard - -"reactotron-react-native@npm:^5.1.15": - version: 5.1.15 - resolution: "reactotron-react-native@npm:5.1.15" - dependencies: - mitt: "npm:^3.0.1" - reactotron-core-client: "npm:2.9.7" - peerDependencies: - react-native: ">=0.40.0" - checksum: 10c0/b3b5d9ef36ae194671e8e23de322a205c95f770cafea33019030bbb03098b110fc0267841f9165f3bccad4677b0fbc6514a8ac3bb9530fe7dece1ae9fbbd4338 - languageName: node - linkType: hard - -"reactotron-react-query@npm:^2.0.2": - version: 2.0.2 - resolution: "reactotron-react-query@npm:2.0.2" - peerDependencies: - "@tanstack/react-query": ^5.80.10 - reactotron-core-client: ^2.9.7 - checksum: 10c0/8a69e449cb7efa9ac55f171260f92bde90a67e1db2279f1cda43533b53f415d091ed95dd63e676c9c11893cbd82e409a54289e5a8269daf232314a5445a87e65 - languageName: node - linkType: hard - "readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" From 502351258c93cc7d114218bd1b58ee01ed350751 Mon Sep 17 00:00:00 2001 From: VladyslavMartynov10 Date: Tue, 23 Sep 2025 17:33:15 +0300 Subject: [PATCH 2/5] feat: new c++ codegen API --- scripts/api-codegen/server-hooks.cpp | 995 ++++++++++++++---- src/shared/api/auth/AuthService.ts | 61 +- src/shared/api/auth/QueryKeys.ts | 34 +- src/shared/api/auth/mutations/index.ts | 2 +- ...teUser.Auth.ts => useTestMutation.auth.ts} | 10 +- src/shared/api/auth/queries/index.ts | 9 +- ...d.Auth.ts => useTestInfiniteQuery.auth.ts} | 18 +- .../api/auth/queries/useTestPrefetch.auth.ts | 91 ++ .../useTestPrefetchInfiniteQuery.auth.ts | 180 ++++ .../api/auth/queries/useTestQueries.auth.ts | 53 + ...seGetUser.auth.ts => useTestQuery.auth.ts} | 20 +- .../useTestSuspenseInfiniteQuery.auth.ts | 147 +++ .../auth/queries/useTestSuspenseQuery.auth.ts | 94 ++ src/shared/api/createApi.ts | 57 + src/shared/api/hooks/index.ts | 3 + src/shared/api/hooks/useQueriesWithOptions.ts | 43 + .../useSuspenseInfiniteQueryWithOptions.ts | 94 ++ .../api/hooks/useSuspenseQueryWithOptions.ts | 60 ++ src/shared/api/models/index.ts | 4 + src/shared/api/models/types.ts | 91 ++ 20 files changed, 1819 insertions(+), 247 deletions(-) rename src/shared/api/auth/mutations/{useCreateUser.Auth.ts => useTestMutation.auth.ts} (52%) rename src/shared/api/auth/queries/{useGetUsersPaginated.Auth.ts => useTestInfiniteQuery.auth.ts} (86%) create mode 100644 src/shared/api/auth/queries/useTestPrefetch.auth.ts create mode 100644 src/shared/api/auth/queries/useTestPrefetchInfiniteQuery.auth.ts create mode 100644 src/shared/api/auth/queries/useTestQueries.auth.ts rename src/shared/api/auth/queries/{useGetUser.auth.ts => useTestQuery.auth.ts} (82%) create mode 100644 src/shared/api/auth/queries/useTestSuspenseInfiniteQuery.auth.ts create mode 100644 src/shared/api/auth/queries/useTestSuspenseQuery.auth.ts create mode 100644 src/shared/api/hooks/useQueriesWithOptions.ts create mode 100644 src/shared/api/hooks/useSuspenseInfiniteQueryWithOptions.ts create mode 100644 src/shared/api/hooks/useSuspenseQueryWithOptions.ts diff --git a/scripts/api-codegen/server-hooks.cpp b/scripts/api-codegen/server-hooks.cpp index 7529b29..f6c0a5b 100644 --- a/scripts/api-codegen/server-hooks.cpp +++ b/scripts/api-codegen/server-hooks.cpp @@ -7,59 +7,71 @@ #include #include - const std::filesystem::path API_DIR = "./src/shared/api"; const std::string QUERY_KEYS_FILE = "src/shared/api/models/QueryKeys.ts"; const std::unordered_set EXCLUDED_FOLDERS = {"models"}; const std::string LOCK_FILE = "./codegen.lock"; -std::string toCamelCase(const std::string& input) { - std::stringstream ss(input); - std::string word, result; - bool first = true; - - while (std::getline(ss, word, '_')) { - if (first) { - result += std::tolower(word[0]); - result += word.substr(1); - first = false; - } else { - word[0] = std::toupper(word[0]); - result += word; - } +std::string toCamelCase(const std::string &input) +{ + std::stringstream ss(input); + std::string word, result; + bool first = true; + + while (std::getline(ss, word, '_')) + { + if (first) + { + result += std::tolower(word[0]); + result += word.substr(1); + first = false; + } + else + { + word[0] = std::toupper(word[0]); + result += word; } + } - return result; + return result; } -std::string capitalizeFirstLetter(const std::string& input) { - if (input.empty()) return input; - std::string result = input; - result[0] = std::toupper(result[0]); - return result; +std::string capitalizeFirstLetter(const std::string &input) +{ + if (input.empty()) + return input; + std::string result = input; + result[0] = std::toupper(result[0]); + return result; } -std::string toSnakeCase(const std::string& input) { - std::string result; - for (size_t i = 0; i < input.length(); i++) { - if (std::isupper(input[i]) && i > 0) { - result += "_"; - } - result += std::tolower(input[i]); +std::string toSnakeCase(const std::string &input) +{ + std::string result; + for (size_t i = 0; i < input.length(); i++) + { + if (std::isupper(input[i]) && i > 0) + { + result += "_"; } - return result; + result += std::tolower(input[i]); + } + return result; } -std::string toCapitalize(const std::string& input) { - return capitalizeFirstLetter(input); +std::string toCapitalize(const std::string &input) +{ + return capitalizeFirstLetter(input); } -std::string extractServicePrefix(const std::string& serviceName) { - std::string result = serviceName; - if (result.size() > 7 && result.substr(result.size() - 7) == "Service") { - result = result.substr(0, result.size() - 7); - } - return result; +std::string extractServicePrefix(const std::string &serviceName) +{ + std::string result = serviceName; + if (result.size() > 7 && result.substr(result.size() - 7) == "Service") + { + result = result.substr(0, result.size() - 7); + } + return result; } std::string generateHash(const std::filesystem::path &filePath) @@ -76,7 +88,7 @@ std::string generateHash(const std::filesystem::path &filePath) std::string fileContent = fileContentStream.str(); std::regex methodPattern( - R"(([a-zA-Z0-9_]+):\s*builder\.(query|prefetch|mutation|infiniteQuery|prefetchInfiniteQuery)\s*\()"); + R"(([a-zA-Z0-9_]+):\s*builder\.(query|prefetch|mutation|infiniteQuery|prefetchInfiniteQuery|suspenseQuery|suspenseInfiniteQuery|queries)\s*\()"); std::sregex_iterator it(fileContent.begin(), fileContent.end(), methodPattern); std::sregex_iterator end; @@ -102,17 +114,18 @@ std::string normalizeType(const std::string &type) return std::regex_replace(type, std::regex(R"(\[\]$)"), ""); } +std::string readFileContent(const std::filesystem::path &filePath) +{ + std::ifstream file(filePath); + if (!file.is_open()) + { + std::cerr << "❌ Error: Unable to open file: " << filePath << "\n"; + return ""; + } -std::string readFileContent(const std::filesystem::path& filePath) { - std::ifstream file(filePath); - if (!file.is_open()) { - std::cerr << "❌ Error: Unable to open file: " << filePath << "\n"; - return ""; - } - - std::ostringstream fileContentStream; - fileContentStream << file.rdbuf(); - return fileContentStream.str(); + std::ostringstream fileContentStream; + fileContentStream << file.rdbuf(); + return fileContentStream.str(); } bool isExcludedFolder(const std::string &folderName, @@ -960,18 +973,20 @@ void generatePrefetchInfiniteQueryHook( return; } - outFile << "import { getQueryClient } from '../../queryClient';\n" - << "import {\n" - << " FetchInfiniteQueryOptions,\n" - << " GetNextPageParamFunction,\n" - << " InfiniteData,\n" - << "} from '@tanstack/react-query';\n" - << "import { QueryError, QueryKeyType, queryKeys } from " - "'../../models';\n" - << "import { usePrefetchInfiniteQueryWithOptions } from " - "'../../hooks';\n" - << "import { " << serviceName << " } from '../" << serviceName - << "';\n\n"; + outFile + << "import { InvalidateQueryFilters } from '@tanstack/react-query';\n" + << "import { getQueryClient } from '../../queryClient';\n" + << "import {\n" + << " FetchInfiniteQueryOptions,\n" + << " GetNextPageParamFunction,\n" + << " InfiniteData,\n" + << "} from '@tanstack/react-query';\n" + << "import { QueryError, QueryKeyType, PrefetchInfiniteQueryFetchParams, queryKeys } from " + "'../../models';\n" + << "import { usePrefetchInfiniteQueryWithOptions } from " + "'../../hooks';\n" + << "import { " << serviceName << " } from '../" << serviceName + << "';\n\n"; if (!isSpecialType(responseType)) { @@ -995,7 +1010,7 @@ void generatePrefetchInfiniteQueryHook( << " FetchInfiniteQueryOptions<\n" << " " << responseType << ",\n" << " QueryError,\n" - << " InfiniteData,\n" + << " TData,\n" << " QueryKeyType,\n" << " TPageParam\n" << " >,\n" @@ -1008,7 +1023,7 @@ void generatePrefetchInfiniteQueryHook( "extends " << requestType << " {\n" << " initialPageParam: TPageParam;\n" - << " getNextPageParam: InfiniteQueryFetchParams<\n" + << " getNextPageParam: PrefetchInfiniteQueryFetchParams<\n" << " " << responseType << ",\n" << " QueryError,\n" << " InfiniteData,\n" @@ -1016,7 +1031,7 @@ void generatePrefetchInfiniteQueryHook( << " QueryKeyType,\n" << " TPageParam\n" << " >['getNextPageParam'];\n" - << " options?: InfiniteQueryFetchParams<\n" + << " options?: PrefetchInfiniteQueryFetchParams<\n" << " " << responseType << ",\n" << " QueryError,\n" << " InfiniteData,\n" @@ -1252,170 +1267,739 @@ void generateMutationHook(const std::filesystem::path &hooksDir, std::cout << "✅ Mutation hook generated: " << mutationFile << "\n"; } -void removeEmptyFolders(const std::filesystem::path &serviceDir) +void generateSuspenseQueryHook( + const std::filesystem::path &hooksDir, const std::string &hookName, + const std::string &responseType, const std::string &requestType, + const std::string &queryKeyName, const std::string &serviceName, + const std::string &endpointName, const std::string &servicePrefix, + bool isVoidRequest, const std::string &servicePrefixHook) { - std::filesystem::path queriesDir = serviceDir / "queries"; - std::filesystem::path mutationsDir = serviceDir / "mutations"; - std::filesystem::path queryKeysFile = serviceDir / "QueryKeys.ts"; + std::filesystem::path queryFile = + hooksDir / "queries" / (hookName + "." + servicePrefix + ".ts"); - if (std::filesystem::exists(queriesDir) && std::filesystem::is_empty(queriesDir)) + std::ofstream outFile(queryFile); + if (!outFile.is_open()) { - std::filesystem::remove_all(queriesDir); - std::cout << "🗑️ Removed empty queries folder.\n"; + std::cerr << "❌ Error: Unable to create suspense query file: " << queryFile << "\n"; + return; } - if (std::filesystem::exists(mutationsDir) && std::filesystem::is_empty(mutationsDir)) - { - std::filesystem::remove_all(mutationsDir); - std::cout << "🗑️ Removed empty mutations folder.\n"; - } + outFile << "import { InvalidateQueryFilters } from '@tanstack/react-query';\n" + << "import { getQueryClient } from '../../queryClient';\n" + << "import {\n" + << " QueryError,\n" + << " QueryKeyType,\n" + << " UseSuspenseQueryWithOptionsParams,\n" + << " QueryFetchParams,\n" + << " queryKeys,\n" + << "} from '../../models';\n" + << "import { useSuspenseQueryWithOptions } from '../../hooks';\n" + << "import { " << serviceName << " } from '../" << serviceName + << "';\n\n"; - if (std::filesystem::exists(queryKeysFile)) + if (!isSpecialType(responseType)) { - std::filesystem::remove(queryKeysFile); - std::cout << "🗑️ Removed unused QueryKeys.ts.\n"; + outFile << "import { " << normalizeType(responseType) << " } from '../models';\n"; } -} - -void generateHooks(const std::string &serviceName, - const std::filesystem::path &serviceFile, - const std::filesystem::path &hooksDir) -{ - - std::string fileExtension = "." + toSnakeCase(serviceName) + ".ts"; - - std::filesystem::create_directories(hooksDir / "queries"); - std::filesystem::create_directories(hooksDir / "mutations"); - std::string fileContent = readFileContent(serviceFile); - if (fileContent.empty()) + if (!isVoidRequest && !isSpecialType(requestType)) { - return; - } - - // First, find the interface that defines the API - std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))"); - std::smatch createApiMatch; - - if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) { - return; // No createApi found - } - - std::string interfaceName = createApiMatch[1].str(); - - // Find the interface definition - std::regex interfacePattern( - R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})"); - std::smatch interfaceMatch; - - if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) { - return; // Interface not found + outFile << "import { " << normalizeType(requestType) << " } from '../models';\n"; } - - std::string interfaceContent = interfaceMatch[1].str(); - - // Extract endpoint definitions from interface - std::regex endpointDefPattern( - R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)"); - - std::sregex_iterator interfaceIter(interfaceContent.begin(), interfaceContent.end(), endpointDefPattern); - std::sregex_iterator interfaceEnd; - - std::unordered_set detectedQueries; - std::unordered_set detectedMutations; - bool hasQueries = false; - bool hasMutations = false; - - for (; interfaceIter != interfaceEnd; ++interfaceIter) + if (!isVoidRequest) { - std::smatch match = *interfaceIter; + outFile << "\ninterface HookParams extends " << requestType << " {\n" + << " options?: UseSuspenseQueryWithOptionsParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " TData,\n" + << " QueryKeyType\n" + << " >['options'];\n" + << "}\n\n"; - std::string endpointName = match[1].str(); - std::string requestType = match[2].str(); - std::string responseType = match[3].str(); - - // Clean up whitespace - requestType.erase( - remove_if(requestType.begin(), requestType.end(), ::isspace), - requestType.end()); - responseType.erase( - remove_if(responseType.begin(), responseType.end(), ::isspace), - responseType.end()); + outFile << "interface QueryFnParams {\n" + << " params: " << requestType << ";\n" + << " meta?: Record | undefined;\n" + << " queryKey?: QueryKeyType;\n" + << " signal?: AbortSignal;\n" + << "}\n\n"; - std::string hookName = "use" + capitalizeFirstLetter(endpointName); - std::string servicePrefix = extractServicePrefix(serviceName); - std::string queryKeyName = toCamelCase(endpointName) + toCapitalize(serviceName); + outFile << "export const " << endpointName << "QueryFn" << serviceName + << " = async ({ params, signal }: QueryFnParams) => {\n" + << " const response = await " << serviceName << "." << endpointName + << "(params, { signal });\n" + << " return response;\n" + << "};\n\n"; - bool isVoidRequest = requestType == "void"; - - // Check what method type this endpoint uses - std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()"); - std::regex queryPattern(endpointName + R"(:\s*builder\.query\s*\()"); - std::regex infiniteQueryPattern(endpointName + R"(:\s*builder\.infiniteQuery\s*\()"); - std::regex prefetchPattern(endpointName + R"(:\s*builder\.prefetch\s*\()"); - std::regex prefetchInfiniteQueryPattern(endpointName + R"(:\s*builder\.prefetchInfiniteQuery\s*\()"); - - bool isMutation = std::regex_search(fileContent, mutationPattern); - bool isQuery = std::regex_search(fileContent, queryPattern); - bool isInfiniteQuery = std::regex_search(fileContent, infiniteQueryPattern); - bool isPrefetch = std::regex_search(fileContent, prefetchPattern); - bool isPrefetchInfiniteQuery = std::regex_search(fileContent, prefetchInfiniteQueryPattern); + outFile << "const getQueryKey = (params: " << requestType + << ") => queryKeys." << queryKeyName << "(params);\n\n"; - if (isMutation) - { - hasMutations = true; - generateMutationHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedMutations.insert(hookName); - } - else if (isQuery) - { - hasQueries = true; - generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedQueries.insert(hookName); - } - else if (isInfiniteQuery) - { - hasQueries = true; - generateInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedQueries.insert(hookName); - } - else if (isPrefetch) - { - hasQueries = true; - generatePrefetchQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedQueries.insert(hookName); - } - else if (isPrefetchInfiniteQuery) - { - hasQueries = true; - generatePrefetchInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedQueries.insert(hookName); - } - else - { - // Default to query if method not recognized - hasQueries = true; - generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); - detectedQueries.insert(hookName); - } - } + outFile << "export const " << endpointName << "SuspenseQuery" << servicePrefixHook + << " = <\n" + << " TData = " << responseType << ",\n" + << " TError = QueryError,\n" + << ">({\n" + << " params,\n" + << " fetchOptions,\n" + << "}: QueryFetchParams<\n" + << " " << responseType << ",\n" + << " TError,\n" + << " TData,\n" + << " " << requestType << "\n" + << ">) => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.fetchQuery<\n" + << " " << responseType << ",\n" + << " TError,\n" + << " TData,\n" + << " QueryKeyType\n" + << " >({\n" + << " queryKey: getQueryKey(params),\n" + << " queryFn: ({ signal }) => " << endpointName << "QueryFn" << serviceName + << "({ params, signal }),\n" + << " ...fetchOptions,\n" + << " });\n" + << "};\n\n"; - if (detectedQueries.empty()) - { - std::filesystem::remove_all(hooksDir / "queries"); - std::cout << "🗑️ Removed empty queries folder.\n"; + outFile << "export const " << hookName << "SuspenseQuery" << servicePrefixHook + << " = ({\n" + << " options,\n" + << " ...params\n" + << "}: HookParams) => {\n" + << " return useSuspenseQueryWithOptions<" << responseType + << ", QueryError, TData, QueryKeyType>({\n" + << " queryFn: ({ signal }) => " << endpointName << "QueryFn" << serviceName + << "({ params, signal }),\n" + << " queryKey: getQueryKey(params),\n" + << " options,\n" + << " });\n" + << "};\n"; } - if (detectedMutations.empty()) + else { - std::filesystem::remove_all(hooksDir / "mutations"); - std::cout << "🗑️ Removed empty mutations folder.\n"; - } + outFile << "\ninterface HookParams {\n" + << " options?: UseSuspenseQueryWithOptionsParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " TData,\n" + << " QueryKeyType\n" + << " >['options'];\n" + << "}\n\n"; - updateIndexFile(hooksDir); -} + outFile << "interface QueryFnParams {\n" + << " meta?: Record | undefined;\n" + << " queryKey?: QueryKeyType;\n" + << " signal?: AbortSignal;\n" + << "}\n\n"; -void removeGeneratedFiles(const std::filesystem::path &serviceDir) + outFile << "export const " << endpointName << "QueryFn" << serviceName + << " = async ({ signal }:QueryFnParams) => {\n" + << " const response = await " << serviceName << "." << endpointName + << "(undefined, { signal });\n" + << " return response;\n" + << "};\n\n"; + + outFile << "const getQueryKey = () => queryKeys." << queryKeyName + << "();\n\n"; + + outFile << "export const " << endpointName << "SuspenseQuery" << servicePrefixHook + << " = <\n" + << " TData = " << responseType << ",\n" + << " TError = QueryError,\n" + << ">({ fetchOptions }: QueryFetchParams<\n" + << " " << responseType << ",\n" + << " TError,\n" + << " TData,\n" + << " " << requestType << "\n" + << ">) => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.fetchQuery<\n" + << " " << responseType << ",\n" + << " TError,\n" + << " TData,\n" + << " QueryKeyType\n" + << " >({\n" + << " queryKey: getQueryKey(),\n" + << " queryFn: ({ signal }) => " << endpointName << "QueryFn" << serviceName + << "({ signal }),\n" + << " ...fetchOptions,\n" + << " });\n" + << "};\n\n"; + + outFile << "export const " << hookName << "SuspenseQuery" << servicePrefixHook + << " = ({\n" + << " options,\n" + << "}: HookParams) => {\n" + << " return useSuspenseQueryWithOptions<" << responseType + << ", QueryError, TData, QueryKeyType>({\n" + << " queryFn: ({ signal }) => " << endpointName << "QueryFn" << serviceName + << "({ signal }),\n" + << " queryKey: getQueryKey(),\n" + << " options,\n" + << " });\n" + << "};\n"; + } + + // Add invalidate function + if (!isVoidRequest) + { + outFile << "\nexport const invalidate" << capitalizeFirstLetter(endpointName) + << "SuspenseQuery" << servicePrefixHook << " = (\n" + << " params: " << requestType << ",\n" + << " options?: Omit\n" + << ") => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.invalidateQueries({\n" + << " queryKey: getQueryKey(params),\n" + << " ...options,\n" + << " });\n" + << "};\n"; + } + else + { + outFile << "\nexport const invalidate" << capitalizeFirstLetter(endpointName) + << "SuspenseQuery" << servicePrefixHook << " = (\n" + << " options?: Omit\n" + << ") => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.invalidateQueries({\n" + << " queryKey: getQueryKey(),\n" + << " ...options,\n" + << " });\n" + << "};\n"; + } + + std::filesystem::path indexFile = hooksDir / "queries" / "index.ts"; + std::ofstream indexOutFile(indexFile, std::ios::app); + if (!indexOutFile.is_open()) + { + std::cerr << "❌ Error: Unable to update queries index file: " + << indexFile << "\n"; + return; + } + + indexOutFile << "export * from './" << hookName << "." << servicePrefix + << "';\n"; + indexOutFile.close(); + + outFile.close(); + std::cout << "✅ Suspense query hook generated: " << queryFile << "\n"; +} + +void generateSuspenseInfiniteQueryHook( + const std::filesystem::path &hooksDir, const std::string &hookName, + const std::string &responseType, const std::string &requestType, + const std::string &queryKeyName, const std::string &serviceName, + const std::string &endpointName, const std::string &servicePrefix, + bool isVoidRequest, const std::string &servicePrefixHook) +{ + std::filesystem::path queryFile = + hooksDir / "queries" / (hookName + "." + servicePrefix + ".ts"); + + std::ofstream outFile(queryFile); + if (!outFile.is_open()) + { + std::cerr << "❌ Error: Unable to create suspense infinite query file: " << queryFile + << "\n"; + return; + } + + outFile << "import { InfiniteData, InvalidateQueryFilters } from '@tanstack/react-query';\n" + << "import { getQueryClient } from '../../queryClient';\n" + << "import {\n" + << " InfiniteQueryFetchParams,\n" + << " QueryError,\n" + << " QueryKeyType,\n" + << " UseSuspenseInfiniteQueryWithOptionsParams,\n" + << " queryKeys,\n" + << "} from '../../models';\n" + << "import { useSuspenseInfiniteQueryWithOptions } from '../../hooks';\n" + << "import { " << serviceName << " } from '../" << serviceName + << "';\n\n"; + + if (!isSpecialType(responseType)) + { + outFile << "import { " << normalizeType(responseType) << " } from '../models';\n"; + } + + if (!isVoidRequest && !isSpecialType(requestType)) + { + outFile << "import { " << normalizeType(requestType) << " } from '../models';\n"; + } + + outFile << "\ntype PageParam = string | number | unknown;\n\n"; + + outFile << "interface InfiniteHookParams " + "extends " + << requestType << " {\n" + << " initialPageParam: TPageParam;\n" + << " getNextPageParam: UseSuspenseInfiniteQueryWithOptionsParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " TData,\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >['getNextPageParam'];\n" + << " options?: UseSuspenseInfiniteQueryWithOptionsParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " TData,\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >['options'];\n" + << "}\n\n"; + + outFile << "interface InfiniteFetchParams " + "extends " + << requestType << " {\n" + << " initialPageParam: TPageParam;\n" + << " getNextPageParam: InfiniteQueryFetchParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " InfiniteData,\n" + << " " << requestType << ",\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >['getNextPageParam'];\n" + << " options?: InfiniteQueryFetchParams<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " InfiniteData,\n" + << " " << requestType << ",\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >['fetchOptions'];\n" + << "}\n\n"; + + outFile << "interface QueryFnParams {\n" + << " params: " << requestType << ";\n" + << " pageParam: TPageParam;\n" + << " signal: AbortSignal;\n" + << "}\n\n"; + + outFile << "export const " << endpointName << "QueryFn" << serviceName + << " = async ({\n" + << " params,\n" + << " pageParam,\n" + << " signal,\n" + << "}: QueryFnParams) => {\n" + << " const response = await " << serviceName << "." << endpointName + << "({ ...params, pageParam }, { signal });\n" + << " return response;\n" + << "};\n\n"; + + outFile << "const getQueryKey = (params: " << requestType << ") => queryKeys." + << queryKeyName << "(params);\n\n"; + + outFile << "export const " << endpointName << "SuspenseInfiniteQuery" + << servicePrefixHook << " = <\n" + << " TData = " << responseType << ",\n" + << " TPageParam = PageParam,\n" + << ">({\n" + << " initialPageParam,\n" + << " getNextPageParam,\n" + << " options,\n" + << " ...params\n" + << "}: InfiniteFetchParams) => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.fetchInfiniteQuery<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " InfiniteData,\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >({\n" + << " queryFn: ({ pageParam, signal }) => " << endpointName << "QueryFn" + << serviceName << "({ pageParam, params, signal }),\n" + << " queryKey: getQueryKey(params),\n" + << " initialPageParam,\n" + << " getNextPageParam,\n" + << " ...options,\n" + << " });\n" + << "};\n\n"; + + outFile << "export const " << hookName << "SuspenseInfiniteQuery" << servicePrefixHook + << " = <\n" + << " TData = " << responseType << ",\n" + << " TPageParam = PageParam,\n" + << ">({\n" + << " options,\n" + << " initialPageParam,\n" + << " getNextPageParam,\n" + << " ...params\n" + << "}: InfiniteHookParams) => {\n" + << " return useSuspenseInfiniteQueryWithOptions<\n" + << " " << responseType << ",\n" + << " QueryError,\n" + << " TData,\n" + << " QueryKeyType,\n" + << " TPageParam\n" + << " >({\n" + << " queryFn: ({ pageParam, signal }) => " << endpointName << "QueryFn" + << serviceName << "({ pageParam, params, signal }),\n" + << " queryKey: getQueryKey(params),\n" + << " initialPageParam,\n" + << " getNextPageParam,\n" + << " options,\n" + << " });\n" + << "};\n"; + + // Add invalidate function + outFile << "\nexport const invalidate" << capitalizeFirstLetter(endpointName) + << "SuspenseInfiniteQuery" << servicePrefixHook << " = (\n" + << " params: " << requestType << ",\n" + << " options?: Omit\n" + << ") => {\n" + << " const queryClient = getQueryClient();\n\n" + << " return queryClient.invalidateQueries({\n" + << " queryKey: getQueryKey(params),\n" + << " ...options,\n" + << " });\n" + << "};\n"; + + std::filesystem::path indexFile = hooksDir / "queries" / "index.ts"; + std::ofstream indexOutFile(indexFile, std::ios::app); + if (!indexOutFile.is_open()) + { + std::cerr << "❌ Error: Unable to update queries index file: " + << indexFile << "\n"; + return; + } + + indexOutFile << "export * from './" << hookName << "." << servicePrefix + << "';\n"; + indexOutFile.close(); + + outFile.close(); + std::cout << "✅ Suspense infinite query hook generated: " << queryFile << "\n"; +} + +void generateQueriesHook( + const std::filesystem::path &hooksDir, const std::string &hookName, + const std::string &responseType, const std::string &requestType, + const std::string &queryKeyName, const std::string &serviceName, + const std::string &endpointName, const std::string &servicePrefix, + bool isVoidRequest, const std::string &servicePrefixHook) +{ + std::filesystem::path queryFile = + hooksDir / "queries" / (hookName + "." + servicePrefix + ".ts"); + + std::ofstream outFile(queryFile); + if (!outFile.is_open()) + { + std::cerr << "❌ Error: Unable to create queries hook file: " << queryFile + << "\n"; + return; + } + + outFile + << "import {\n" + << " QueryKeyType,\n" + << " UseQueriesWithOptionsParams,\n" + << " queryKeys,\n" + << "} from '../../models';\n" + << "import { useQueriesWithOptions } from '../../hooks';\n" + << "import { " << serviceName << " } from '../" << serviceName + << "';\n\n"; + + if (!isSpecialType(responseType)) + { + outFile << "import { " << normalizeType(responseType) << " } from '../models';\n"; + } + + if (!isVoidRequest && !isSpecialType(requestType)) + { + outFile << "import { " << normalizeType(requestType) << " } from '../models';\n"; + } + + if (!isVoidRequest) + { + outFile << "\ninterface QueryFnParams {\n" + << " params: " << requestType << ";\n" + << " meta?: Record | undefined;\n" + << " queryKey?: QueryKeyType;\n" + << " signal?: AbortSignal;\n" + << "}\n\n"; + + outFile << "export const " << endpointName << "QueryFn" << serviceName + << " = async ({\n" + << " params,\n" + << " signal,\n" + << "}: QueryFnParams) => {\n" + << " const response = await " << serviceName << "." << endpointName + << "(params, { signal });\n\n" + << " return response;\n" + << "};\n\n"; + + outFile << "const getQueryKey = (params: " << requestType << ") => queryKeys." + << endpointName << serviceName << "(params);\n\n"; + + outFile << "interface HookParams {\n" + << " params: " << requestType << "[];\n" + << " options?: UseQueriesWithOptionsParams Promise<" << responseType << ">;\n" + << " }>>['options'];\n" + << "}\n\n"; + + outFile << "export const " << hookName << "Queries" << servicePrefixHook + << " = ({\n" + << " params,\n" + << " options,\n" + << "}: HookParams) => {\n" + << " const queries = params.map((param) => ({\n" + << " queryKey: getQueryKey(param),\n" + << " queryFn: ({ signal }: { signal?: AbortSignal }) => " << endpointName << "QueryFn" << serviceName << "({ params: param, signal }),\n" + << " }));\n\n" + << " return useQueriesWithOptions({\n" + << " queries,\n" + << " options,\n" + << " });\n" + << "};\n"; + } + else + { + outFile << "\nexport const " << endpointName << "QueryFn" << serviceName + << " = async ({ signal }: { signal?: AbortSignal }) => {\n" + << " const response = await " << serviceName << "." << endpointName + << "(undefined, { signal });\n\n" + << " return response;\n" + << "};\n\n"; + + outFile << "const getQueryKey = () => queryKeys." + << endpointName << serviceName << "();\n\n"; + + outFile << "interface HookParams {\n" + << " count: number;\n" + << " options?: UseQueriesWithOptionsParams Promise<" << responseType << ">;\n" + << " }>>['options'];\n" + << "}\n\n"; + + outFile << "export const " << hookName << "Queries" << servicePrefixHook + << " = ({\n" + << " count,\n" + << " options,\n" + << "}: HookParams) => {\n" + << " const queries = Array.from({ length: count }, (_, index) => ({\n" + << " queryKey: [...getQueryKey(), index],\n" + << " queryFn: ({ signal }: { signal?: AbortSignal }) => " << endpointName << "QueryFn" << serviceName << "({ signal }),\n" + << " }));\n\n" + << " return useQueriesWithOptions({\n" + << " queries,\n" + << " options,\n" + << " });\n" + << "};\n"; + } + + std::filesystem::path indexFile = hooksDir / "queries" / "index.ts"; + std::ofstream indexOutFile(indexFile, std::ios::app); + if (!indexOutFile.is_open()) + { + std::cerr << "❌ Error: Unable to update queries index file: " + << indexFile << "\n"; + return; + } + + indexOutFile << "export * from './" << hookName << "." << servicePrefix + << "';\n"; + indexOutFile.close(); + + outFile.close(); + std::cout << "✅ Queries hook generated: " << queryFile << "\n"; +} + +void removeEmptyFolders(const std::filesystem::path &serviceDir) +{ + std::filesystem::path queriesDir = serviceDir / "queries"; + std::filesystem::path mutationsDir = serviceDir / "mutations"; + std::filesystem::path queryKeysFile = serviceDir / "QueryKeys.ts"; + + if (std::filesystem::exists(queriesDir) && std::filesystem::is_empty(queriesDir)) + { + std::filesystem::remove_all(queriesDir); + std::cout << "🗑️ Removed empty queries folder.\n"; + } + + if (std::filesystem::exists(mutationsDir) && std::filesystem::is_empty(mutationsDir)) + { + std::filesystem::remove_all(mutationsDir); + std::cout << "🗑️ Removed empty mutations folder.\n"; + } + + if (std::filesystem::exists(queryKeysFile)) + { + std::filesystem::remove(queryKeysFile); + std::cout << "🗑️ Removed unused QueryKeys.ts.\n"; + } +} + +void generateHooks(const std::string &serviceName, + const std::filesystem::path &serviceFile, + const std::filesystem::path &hooksDir) +{ + + std::string fileExtension = "." + toSnakeCase(serviceName) + ".ts"; + + std::filesystem::create_directories(hooksDir / "queries"); + std::filesystem::create_directories(hooksDir / "mutations"); + + std::string fileContent = readFileContent(serviceFile); + if (fileContent.empty()) + { + return; + } + + // First, find the interface that defines the API + std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))"); + std::smatch createApiMatch; + + if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) + { + return; // No createApi found + } + + std::string interfaceName = createApiMatch[1].str(); + + // Find the interface definition + std::regex interfacePattern( + R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})"); + std::smatch interfaceMatch; + + if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) + { + return; // Interface not found + } + + std::string interfaceContent = interfaceMatch[1].str(); + + // Extract endpoint definitions from interface + std::regex endpointDefPattern( + R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)"); + + std::sregex_iterator interfaceIter(interfaceContent.begin(), interfaceContent.end(), endpointDefPattern); + std::sregex_iterator interfaceEnd; + + std::unordered_set detectedQueries; + std::unordered_set detectedMutations; + + bool hasQueries = false; + bool hasMutations = false; + + for (; interfaceIter != interfaceEnd; ++interfaceIter) + { + std::smatch match = *interfaceIter; + + std::string endpointName = match[1].str(); + std::string requestType = match[2].str(); + std::string responseType = match[3].str(); + + // Clean up whitespace + requestType.erase( + remove_if(requestType.begin(), requestType.end(), ::isspace), + requestType.end()); + responseType.erase( + remove_if(responseType.begin(), responseType.end(), ::isspace), + responseType.end()); + + std::string hookName = "use" + capitalizeFirstLetter(endpointName); + std::string servicePrefix = toSnakeCase(extractServicePrefix(serviceName)); + std::string queryKeyName = toCamelCase(endpointName) + toCapitalize(serviceName); + + bool isVoidRequest = requestType == "void"; + + // Check what method type this endpoint uses + std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()"); + std::regex queryPattern(endpointName + R"(:\s*builder\.query\s*\()"); + std::regex infiniteQueryPattern(endpointName + R"(:\s*builder\.infiniteQuery\s*\()"); + std::regex prefetchPattern(endpointName + R"(:\s*builder\.prefetch\s*\()"); + std::regex prefetchInfiniteQueryPattern(endpointName + R"(:\s*builder\.prefetchInfiniteQuery\s*\()"); + std::regex suspenseQueryPattern(endpointName + R"(:\s*builder\.suspenseQuery\s*\()"); + std::regex suspenseInfiniteQueryPattern(endpointName + R"(:\s*builder\.suspenseInfiniteQuery\s*\()"); + std::regex queriesPattern(endpointName + R"(:\s*builder\.queries\s*\()"); + + bool isMutation = std::regex_search(fileContent, mutationPattern); + bool isQuery = std::regex_search(fileContent, queryPattern); + bool isInfiniteQuery = std::regex_search(fileContent, infiniteQueryPattern); + bool isPrefetch = std::regex_search(fileContent, prefetchPattern); + bool isPrefetchInfiniteQuery = std::regex_search(fileContent, prefetchInfiniteQueryPattern); + bool isSuspenseQuery = std::regex_search(fileContent, suspenseQueryPattern); + bool isSuspenseInfiniteQuery = std::regex_search(fileContent, suspenseInfiniteQueryPattern); + bool isQueries = std::regex_search(fileContent, queriesPattern); + + if (isMutation) + { + hasMutations = true; + generateMutationHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedMutations.insert(hookName); + } + else if (isQuery) + { + hasQueries = true; + generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isInfiniteQuery) + { + hasQueries = true; + generateInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isPrefetch) + { + hasQueries = true; + generatePrefetchQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isPrefetchInfiniteQuery) + { + hasQueries = true; + generatePrefetchInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isSuspenseQuery) + { + hasQueries = true; + generateSuspenseQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isSuspenseInfiniteQuery) + { + hasQueries = true; + generateSuspenseInfiniteQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else if (isQueries) + { + hasQueries = true; + generateQueriesHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + else + { + hasQueries = true; + generateQueryHook(hooksDir, hookName, responseType, requestType, queryKeyName, serviceName, endpointName, servicePrefix, isVoidRequest, serviceName); + detectedQueries.insert(hookName); + } + } + + if (detectedQueries.empty()) + { + std::filesystem::remove_all(hooksDir / "queries"); + std::cout << "🗑️ Removed empty queries folder.\n"; + } + if (detectedMutations.empty()) + { + std::filesystem::remove_all(hooksDir / "mutations"); + std::cout << "🗑️ Removed empty mutations folder.\n"; + } + + updateIndexFile(hooksDir); +} + +void removeGeneratedFiles(const std::filesystem::path &serviceDir) { std::filesystem::path queriesDir = serviceDir / "queries"; std::filesystem::path mutationsDir = serviceDir / "mutations"; @@ -1458,7 +2042,6 @@ int main() continue; } - std::cout << "🗑️ Removing old generated files...\n"; removeGeneratedFiles(serviceDir); diff --git a/src/shared/api/auth/AuthService.ts b/src/shared/api/auth/AuthService.ts index a11f2fe..4825400 100644 --- a/src/shared/api/auth/AuthService.ts +++ b/src/shared/api/auth/AuthService.ts @@ -3,15 +3,20 @@ import { axiosBaseQuery } from '../baseQuery'; import { CreateAccountResponse, Test } from './models'; interface AuthServiceAPI { - getUser: Promisify; - createUser: Promisify; - getUsersPaginated: Promisify; + testQuery: Promisify; + testMutation: Promisify; + testInfiniteQuery: Promisify; + testSuspenseQuery: Promisify; + testSuspenseInfiniteQuery: Promisify; + testQueries: Promisify; + testPrefetch: Promisify; + testPrefetchInfiniteQuery: Promisify; } export const AuthService = createApi()({ baseQuery: axiosBaseQuery, endpoints: builder => ({ - getUser: builder.query(({ token }, { signal, client }) => { + testQuery: builder.query(({ token }, { signal, client }) => { return client.get(`/v2/customer/`, { params: { test: 'test12' }, headers: { Authorization: `Bearer ${token}` }, @@ -19,7 +24,7 @@ export const AuthService = createApi()({ }); }), - createUser: builder.mutation(async ({ token }, { client }) => { + testMutation: builder.mutation(async ({ token }, { client }) => { const query = await client.post( `/v2/customer/`, { token }, @@ -31,7 +36,7 @@ export const AuthService = createApi()({ return query.data; }), - getUsersPaginated: builder.infiniteQuery( + testInfiniteQuery: builder.infiniteQuery( ({ token }, { signal, client }) => { return client.get(`/v2/customer/paginated`, { params: { token }, @@ -39,5 +44,49 @@ export const AuthService = createApi()({ }); }, ), + + testSuspenseQuery: builder.suspenseQuery( + ({ token }, { signal, client }) => { + return client.get(`/v2/customer/suspense`, { + params: { test: 'suspense-test' }, + headers: { Authorization: `Bearer ${token}` }, + signal, + }); + }, + ), + + testSuspenseInfiniteQuery: builder.suspenseInfiniteQuery( + ({ token }, { signal, client }) => { + return client.get(`/v2/customer/suspense-infinite`, { + params: { token }, + signal, + }); + }, + ), + + testQueries: builder.queries(({ token }, { signal, client }) => { + return client.get(`/v2/customer/queries`, { + params: { test: 'queries-test' }, + headers: { Authorization: `Bearer ${token}` }, + signal, + }); + }), + + testPrefetch: builder.prefetch(({ token }, { signal, client }) => { + return client.get(`/v2/customer/prefetch`, { + params: { test: 'prefetch-test' }, + headers: { Authorization: `Bearer ${token}` }, + signal, + }); + }), + + testPrefetchInfiniteQuery: builder.prefetchInfiniteQuery( + ({ token }, { signal, client }) => { + return client.get(`/v2/customer/prefetch-infinite`, { + params: { token }, + signal, + }); + }, + ), }), }); diff --git a/src/shared/api/auth/QueryKeys.ts b/src/shared/api/auth/QueryKeys.ts index 44db46f..594b6f5 100644 --- a/src/shared/api/auth/QueryKeys.ts +++ b/src/shared/api/auth/QueryKeys.ts @@ -1,15 +1,33 @@ import { Test } from './models'; const QUERY_KEYS = { - GET_USER_AUTH_SERVICE: 'GET_USER_AUTH_SERVICE', - GET_USERS_PAGINATED_AUTH_SERVICE: 'GET_USERS_PAGINATED_AUTH_SERVICE', - CREATE_USER_AUTH_SERVICE: 'CREATE_USER_AUTH_SERVICE', + TEST_QUERY_AUTH_SERVICE: 'TEST_QUERY_AUTH_SERVICE', + TEST_INFINITE_QUERY_AUTH_SERVICE: 'TEST_INFINITE_QUERY_AUTH_SERVICE', + TEST_SUSPENSE_QUERY_AUTH_SERVICE: 'TEST_SUSPENSE_QUERY_AUTH_SERVICE', + TEST_SUSPENSE_INFINITE_QUERY_AUTH_SERVICE: + 'TEST_SUSPENSE_INFINITE_QUERY_AUTH_SERVICE', + TEST_QUERIES_AUTH_SERVICE: 'TEST_QUERIES_AUTH_SERVICE', + TEST_PREFETCH_AUTH_SERVICE: 'TEST_PREFETCH_AUTH_SERVICE', + TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE: + 'TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE', + TEST_MUTATION_AUTH_SERVICE: 'TEST_MUTATION_AUTH_SERVICE', } as const; export const AUTH_QUERY_KEYS = { - getUserAuthService: (params: Test) => - [QUERY_KEYS.GET_USER_AUTH_SERVICE, params] as const, - getUsersPaginatedAuthService: (params: Test) => - [QUERY_KEYS.GET_USERS_PAGINATED_AUTH_SERVICE, params] as const, - createUserAuthService: () => [QUERY_KEYS.CREATE_USER_AUTH_SERVICE] as const, + testQueryAuthService: (params: Test) => + [QUERY_KEYS.TEST_QUERY_AUTH_SERVICE, params] as const, + testInfiniteQueryAuthService: (params: Test) => + [QUERY_KEYS.TEST_INFINITE_QUERY_AUTH_SERVICE, params] as const, + testSuspenseQueryAuthService: (params: Test) => + [QUERY_KEYS.TEST_SUSPENSE_QUERY_AUTH_SERVICE, params] as const, + testSuspenseInfiniteQueryAuthService: (params: Test) => + [QUERY_KEYS.TEST_SUSPENSE_INFINITE_QUERY_AUTH_SERVICE, params] as const, + testQueriesAuthService: (params: Test) => + [QUERY_KEYS.TEST_QUERIES_AUTH_SERVICE, params] as const, + testPrefetchAuthService: (params: Test) => + [QUERY_KEYS.TEST_PREFETCH_AUTH_SERVICE, params] as const, + testPrefetchInfiniteQueryAuthService: (params: Test) => + [QUERY_KEYS.TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE, params] as const, + testMutationAuthService: () => + [QUERY_KEYS.TEST_MUTATION_AUTH_SERVICE] as const, }; diff --git a/src/shared/api/auth/mutations/index.ts b/src/shared/api/auth/mutations/index.ts index dbce154..2ee4a49 100644 --- a/src/shared/api/auth/mutations/index.ts +++ b/src/shared/api/auth/mutations/index.ts @@ -1 +1 @@ -export * from './useCreateUser.Auth'; +export * from './useTestMutation.auth'; diff --git a/src/shared/api/auth/mutations/useCreateUser.Auth.ts b/src/shared/api/auth/mutations/useTestMutation.auth.ts similarity index 52% rename from src/shared/api/auth/mutations/useCreateUser.Auth.ts rename to src/shared/api/auth/mutations/useTestMutation.auth.ts index 540f4bb..a7772b4 100644 --- a/src/shared/api/auth/mutations/useCreateUser.Auth.ts +++ b/src/shared/api/auth/mutations/useTestMutation.auth.ts @@ -4,17 +4,17 @@ import { AuthService } from '../AuthService'; import { Test, CreateAccountResponse } from '../models'; -export const createUserMutationFnAuthService = async (params: Test) => { - const response = await AuthService.createUser(params); +export const testMutationMutationFnAuthService = async (params: Test) => { + const response = await AuthService.testMutation(params); return response; }; -const getMutationKey = () => queryKeys.createUserAuthService(); +const getMutationKey = () => queryKeys.testMutationAuthService(); -export const useCreateUserMutationAuthService = () => { +export const useTestMutationMutationAuthService = () => { return useMutation({ - mutationFn: createUserMutationFnAuthService, + mutationFn: testMutationMutationFnAuthService, mutationKey: getMutationKey(), }); }; diff --git a/src/shared/api/auth/queries/index.ts b/src/shared/api/auth/queries/index.ts index d4623ff..58d1183 100644 --- a/src/shared/api/auth/queries/index.ts +++ b/src/shared/api/auth/queries/index.ts @@ -1,2 +1,7 @@ -export * from './useGetUser.Auth'; -export * from './useGetUsersPaginated.Auth'; +export * from './useTestQuery.auth'; +export * from './useTestInfiniteQuery.auth'; +export * from './useTestSuspenseQuery.auth'; +export * from './useTestSuspenseInfiniteQuery.auth'; +export * from './useTestQueries.auth'; +export * from './useTestPrefetch.auth'; +export * from './useTestPrefetchInfiniteQuery.auth'; diff --git a/src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts b/src/shared/api/auth/queries/useTestInfiniteQuery.auth.ts similarity index 86% rename from src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts rename to src/shared/api/auth/queries/useTestInfiniteQuery.auth.ts index cf838d9..a50b3ed 100644 --- a/src/shared/api/auth/queries/useGetUsersPaginated.Auth.ts +++ b/src/shared/api/auth/queries/useTestInfiniteQuery.auth.ts @@ -58,14 +58,14 @@ interface QueryFnParams { signal: AbortSignal; } -export const getUsersPaginatedQueryFnAuthService = async < +export const testInfiniteQueryQueryFnAuthService = async < TPageParam extends PageParam, >({ params, pageParam, signal, }: QueryFnParams) => { - const response = await AuthService.getUsersPaginated( + const response = await AuthService.testInfiniteQuery( { ...params, pageParam }, { signal }, ); @@ -74,9 +74,9 @@ export const getUsersPaginatedQueryFnAuthService = async < }; const getQueryKey = (params: Test) => - queryKeys.getUsersPaginatedAuthService(params); + queryKeys.testInfiniteQueryAuthService(params); -export const getUsersPaginatedInfiniteQueryAuthService = < +export const testInfiniteQueryInfiniteQueryAuthService = < TData = CreateAccountResponse[], TPageParam = PageParam, >({ @@ -95,7 +95,7 @@ export const getUsersPaginatedInfiniteQueryAuthService = < TPageParam >({ queryFn: ({ pageParam, signal }) => - getUsersPaginatedQueryFnAuthService({ pageParam, params, signal }), + testInfiniteQueryQueryFnAuthService({ pageParam, params, signal }), queryKey: getQueryKey(params), initialPageParam, getNextPageParam, @@ -103,7 +103,7 @@ export const getUsersPaginatedInfiniteQueryAuthService = < }); }; -export const useGetUsersPaginatedInfiniteQueryAuthService = < +export const useTestInfiniteQueryInfiniteQueryAuthService = < TData = CreateAccountResponse[], TPageParam = PageParam, >({ @@ -120,7 +120,7 @@ export const useGetUsersPaginatedInfiniteQueryAuthService = < TPageParam >({ queryFn: ({ pageParam, signal }) => - getUsersPaginatedQueryFnAuthService({ pageParam, params, signal }), + testInfiniteQueryQueryFnAuthService({ pageParam, params, signal }), queryKey: getQueryKey(params), initialPageParam, getNextPageParam, @@ -128,7 +128,7 @@ export const useGetUsersPaginatedInfiniteQueryAuthService = < }); }; -export const invalidateGetUsersPaginatedInfiniteQueryAuthService = ( +export const invalidateTestInfiniteQueryInfiniteQueryAuthService = ( params: Test, options?: Omit, ) => { @@ -140,7 +140,7 @@ export const invalidateGetUsersPaginatedInfiniteQueryAuthService = ( }); }; -export const resetGetUsersPaginatedInfiniteQueryAuthService = async < +export const resetTestInfiniteQueryInfiniteQueryAuthService = async < TPageParam = PageParam, >( params: Test, diff --git a/src/shared/api/auth/queries/useTestPrefetch.auth.ts b/src/shared/api/auth/queries/useTestPrefetch.auth.ts new file mode 100644 index 0000000..b1277b2 --- /dev/null +++ b/src/shared/api/auth/queries/useTestPrefetch.auth.ts @@ -0,0 +1,91 @@ +import { InvalidateQueryFilters } from '@tanstack/react-query'; +import { getQueryClient } from '../../queryClient'; +import { + QueryError, + QueryKeyType, + UsePrefetchQueryWithOptionsParams, + QueryFetchParams, + queryKeys, +} from '../../models'; +import { usePrefetchQueryWithOptions } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +interface HookParams extends Test { + options?: UsePrefetchQueryWithOptionsParams< + CreateAccountResponse, + QueryError, + TData, + QueryKeyType + >['options']; +} + +interface QueryFnParams { + params: Test; + meta?: Record | undefined; + queryKey?: QueryKeyType; + signal?: AbortSignal; +} + +export const testPrefetchQueryFnAuthService = async ({ + params, + signal, +}: QueryFnParams) => { + const response = await AuthService.testPrefetch(params, { signal }); + + return response; +}; + +const getQueryKey = (params: Test) => queryKeys.testPrefetchAuthService(params); + +export const testPrefetchPrefetchQueryAuthService = < + TData = CreateAccountResponse, + TError = QueryError, +>({ + params, + fetchOptions, +}: QueryFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.prefetchQuery< + CreateAccountResponse, + TError, + TData, + QueryKeyType + >({ + queryKey: getQueryKey(params), + queryFn: ({ signal }) => testPrefetchQueryFnAuthService({ params, signal }), + ...fetchOptions, + }); +}; + +export const useTestPrefetchPrefetchQueryAuthService = < + TData = CreateAccountResponse, +>({ + options, + ...params +}: HookParams) => { + return usePrefetchQueryWithOptions< + CreateAccountResponse, + QueryError, + TData, + QueryKeyType + >({ + queryFn: ({ signal }) => testPrefetchQueryFnAuthService({ params, signal }), + queryKey: getQueryKey(params), + options, + }); +}; + +export const invalidateTestPrefetchQueryAuthService = ( + params: Test, + options?: Omit, +) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); +}; diff --git a/src/shared/api/auth/queries/useTestPrefetchInfiniteQuery.auth.ts b/src/shared/api/auth/queries/useTestPrefetchInfiniteQuery.auth.ts new file mode 100644 index 0000000..5b787b7 --- /dev/null +++ b/src/shared/api/auth/queries/useTestPrefetchInfiniteQuery.auth.ts @@ -0,0 +1,180 @@ +import { + InvalidateQueryFilters, + FetchInfiniteQueryOptions, + GetNextPageParamFunction, + InfiniteData, +} from '@tanstack/react-query'; +import { getQueryClient } from '../../queryClient'; +import { + QueryError, + QueryKeyType, + PrefetchInfiniteQueryFetchParams, + queryKeys, +} from '../../models'; +import { usePrefetchInfiniteQueryWithOptions } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +type PageParam = string | number | unknown; + +interface InfiniteHookParams extends Test { + initialPageParam: TPageParam; + getNextPageParam: GetNextPageParamFunction< + TPageParam, + CreateAccountResponse[] + >; + options?: Omit< + FetchInfiniteQueryOptions< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType, + TPageParam + >, + 'queryFn' | 'queryKey' | 'initialPageParam' | 'getNextPageParam' + >; +} + +interface InfiniteFetchParams extends Test { + initialPageParam: TPageParam; + getNextPageParam: PrefetchInfiniteQueryFetchParams< + CreateAccountResponse[], + QueryError, + InfiniteData, + Test, + QueryKeyType, + TPageParam + >['getNextPageParam']; + options?: PrefetchInfiniteQueryFetchParams< + CreateAccountResponse[], + QueryError, + InfiniteData, + Test, + QueryKeyType, + TPageParam + >['fetchOptions']; +} + +interface QueryFnParams { + params: Test; + pageParam: TPageParam; + signal: AbortSignal; +} + +export const testPrefetchInfiniteQueryQueryFnAuthService = async < + TPageParam extends PageParam, +>({ + params, + pageParam, + signal, +}: QueryFnParams) => { + const response = await AuthService.testPrefetchInfiniteQuery( + { ...params, pageParam }, + { signal }, + ); + + return response; +}; + +const getQueryKey = (params: Test) => + queryKeys.testPrefetchInfiniteQueryAuthService(params); + +export const testPrefetchInfiniteQueryPrefetchInfiniteQueryAuthService = < + TData = CreateAccountResponse[], + TPageParam = PageParam, +>({ + initialPageParam, + getNextPageParam, + options, + ...params +}: InfiniteFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.prefetchInfiniteQuery< + CreateAccountResponse[], + QueryError, + InfiniteData, + QueryKeyType, + TPageParam + >({ + queryFn: ({ pageParam, signal }) => + testPrefetchInfiniteQueryQueryFnAuthService({ + pageParam, + params, + signal, + }), + queryKey: getQueryKey(params), + initialPageParam, + getNextPageParam, + ...options, + }); +}; + +export const useTestPrefetchInfiniteQueryPrefetchInfiniteQueryAuthService = < + TData = CreateAccountResponse[], + TPageParam = PageParam, +>({ + options, + initialPageParam, + getNextPageParam, + ...params +}: InfiniteHookParams) => { + return usePrefetchInfiniteQueryWithOptions< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType, + TPageParam + >({ + queryFn: ({ pageParam, signal }) => + testPrefetchInfiniteQueryQueryFnAuthService({ + pageParam, + params, + signal, + }), + queryKey: getQueryKey(params), + initialPageParam, + getNextPageParam, + options, + }); +}; + +export const invalidateTestPrefetchInfiniteQueryInfiniteQueryAuthService = ( + params: Test, + options?: Omit, +) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); +}; + +export const resetTestPrefetchInfiniteQueryInfiniteQueryAuthService = async < + TPageParam = PageParam, +>( + params: Test, +): Promise => { + const queryClient = getQueryClient(); + const queryKey = getQueryKey(params); + + queryClient.setQueryData( + queryKey, + (oldData: InfiniteData) => { + if (!oldData) { + return undefined; + } + + return { + pages: oldData.pages.slice(0, 1), + pageParams: oldData.pageParams.slice(0, 1), + }; + }, + ); + + await queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + }); +}; diff --git a/src/shared/api/auth/queries/useTestQueries.auth.ts b/src/shared/api/auth/queries/useTestQueries.auth.ts new file mode 100644 index 0000000..6da4597 --- /dev/null +++ b/src/shared/api/auth/queries/useTestQueries.auth.ts @@ -0,0 +1,53 @@ +import { + QueryKeyType, + UseQueriesWithOptionsParams, + queryKeys, +} from '../../models'; +import { useQueriesWithOptions } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +interface QueryFnParams { + params: Test; + meta?: Record | undefined; + queryKey?: QueryKeyType; + signal?: AbortSignal; +} + +export const testQueriesQueryFnAuthService = async ({ + params, + signal, +}: QueryFnParams) => { + const response = await AuthService.testQueries(params, { signal }); + + return response; +}; + +const getQueryKey = (params: Test) => queryKeys.testQueriesAuthService(params); + +interface HookParams { + params: Test[]; + options?: UseQueriesWithOptionsParams< + Array<{ + queryKey: QueryKeyType; + queryFn: () => Promise; + }> + >['options']; +} + +export const useTestQueriesQueriesAuthService = ({ + params, + options, +}: HookParams) => { + const queries = params.map(param => ({ + queryKey: getQueryKey(param), + queryFn: ({ signal }: { signal?: AbortSignal }) => + testQueriesQueryFnAuthService({ params: param, signal }), + })); + + return useQueriesWithOptions({ + queries, + options, + }); +}; diff --git a/src/shared/api/auth/queries/useGetUser.auth.ts b/src/shared/api/auth/queries/useTestQuery.auth.ts similarity index 82% rename from src/shared/api/auth/queries/useGetUser.auth.ts rename to src/shared/api/auth/queries/useTestQuery.auth.ts index 0573bb9..5839cbd 100644 --- a/src/shared/api/auth/queries/useGetUser.auth.ts +++ b/src/shared/api/auth/queries/useTestQuery.auth.ts @@ -52,18 +52,18 @@ interface QueryFnParams { signal?: AbortSignal; } -export const getUserQueryFnAuthService = async ({ +export const testQueryQueryFnAuthService = async ({ params, signal, }: QueryFnParams) => { - const response = await AuthService.getUser(params, { signal }); + const response = await AuthService.testQuery(params, { signal }); return response; }; -const getQueryKey = (params: Test) => queryKeys.getUserAuthService(params); +const getQueryKey = (params: Test) => queryKeys.testQueryAuthService(params); -export const getUserQueryAuthService = < +export const testQueryQueryAuthService = < TData = CreateAccountResponse[], TError = QueryError, >({ @@ -79,12 +79,12 @@ export const getUserQueryAuthService = < QueryKeyType >({ queryKey: getQueryKey(params), - queryFn: ({ signal }) => getUserQueryFnAuthService({ params, signal }), + queryFn: ({ signal }) => testQueryQueryFnAuthService({ params, signal }), ...fetchOptions, }); }; -export const useGetUserQueryAuthService = ({ +export const useTestQueryQueryAuthService = ({ options, ...params }: HookParams) => { @@ -94,13 +94,13 @@ export const useGetUserQueryAuthService = ({ TData, QueryKeyType >({ - queryFn: ({ signal }) => getUserQueryFnAuthService({ params, signal }), + queryFn: ({ signal }) => testQueryQueryFnAuthService({ params, signal }), queryKey: getQueryKey(params), options, }); }; -export const invalidateGetUserQueryAuthService = ( +export const invalidateTestQueryQueryAuthService = ( params: Test, options?: Omit, ) => { @@ -112,7 +112,7 @@ export const invalidateGetUserQueryAuthService = ( }); }; -export const useGetUserAuthServiceObservable = < +export const useTestQueryAuthServiceObservable = < TData = CreateAccountResponse[], TSelected = TData, >({ @@ -134,7 +134,7 @@ export const useGetUserAuthServiceObservable = < >({ queryClient, queryFn: ({ signal }) => - getUserQueryFnAuthService({ params: params$, signal }), + testQueryQueryFnAuthService({ params: params$, signal }), queryKey: queryKey$.get(), options, observableOptions, diff --git a/src/shared/api/auth/queries/useTestSuspenseInfiniteQuery.auth.ts b/src/shared/api/auth/queries/useTestSuspenseInfiniteQuery.auth.ts new file mode 100644 index 0000000..cdd7b0f --- /dev/null +++ b/src/shared/api/auth/queries/useTestSuspenseInfiniteQuery.auth.ts @@ -0,0 +1,147 @@ +import { InfiniteData, InvalidateQueryFilters } from '@tanstack/react-query'; +import { getQueryClient } from '../../queryClient'; +import { + InfiniteQueryFetchParams, + QueryError, + QueryKeyType, + UseSuspenseInfiniteQueryWithOptionsParams, + queryKeys, +} from '../../models'; +import { useSuspenseInfiniteQueryWithOptions } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +type PageParam = string | number | unknown; + +interface InfiniteHookParams extends Test { + initialPageParam: TPageParam; + getNextPageParam: UseSuspenseInfiniteQueryWithOptionsParams< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType, + TPageParam + >['getNextPageParam']; + options?: UseSuspenseInfiniteQueryWithOptionsParams< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType, + TPageParam + >['options']; +} + +interface InfiniteFetchParams extends Test { + initialPageParam: TPageParam; + getNextPageParam: InfiniteQueryFetchParams< + CreateAccountResponse[], + QueryError, + InfiniteData, + Test, + QueryKeyType, + TPageParam + >['getNextPageParam']; + options?: InfiniteQueryFetchParams< + CreateAccountResponse[], + QueryError, + InfiniteData, + Test, + QueryKeyType, + TPageParam + >['fetchOptions']; +} + +interface QueryFnParams { + params: Test; + pageParam: TPageParam; + signal: AbortSignal; +} + +export const testSuspenseInfiniteQueryQueryFnAuthService = async < + TPageParam extends PageParam, +>({ + params, + pageParam, + signal, +}: QueryFnParams) => { + const response = await AuthService.testSuspenseInfiniteQuery( + { ...params, pageParam }, + { signal }, + ); + + return response; +}; + +const getQueryKey = (params: Test) => + queryKeys.testSuspenseInfiniteQueryAuthService(params); + +export const testSuspenseInfiniteQuerySuspenseInfiniteQueryAuthService = < + TData = CreateAccountResponse[], + TPageParam = PageParam, +>({ + initialPageParam, + getNextPageParam, + options, + ...params +}: InfiniteFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.fetchInfiniteQuery< + CreateAccountResponse[], + QueryError, + InfiniteData, + QueryKeyType, + TPageParam + >({ + queryFn: ({ pageParam, signal }) => + testSuspenseInfiniteQueryQueryFnAuthService({ + pageParam, + params, + signal, + }), + queryKey: getQueryKey(params), + initialPageParam, + getNextPageParam, + ...options, + }); +}; + +export const useTestSuspenseInfiniteQuerySuspenseInfiniteQueryAuthService = < + TData = CreateAccountResponse[], + TPageParam = PageParam, +>({ + options, + initialPageParam, + getNextPageParam, + ...params +}: InfiniteHookParams) => { + return useSuspenseInfiniteQueryWithOptions< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType, + TPageParam + >({ + queryFn: ({ pageParam, signal }) => + testSuspenseInfiniteQueryQueryFnAuthService({ + pageParam, + params, + signal, + }), + queryKey: getQueryKey(params), + initialPageParam, + getNextPageParam, + options, + }); +}; + +export const invalidateTestSuspenseInfiniteQuerySuspenseInfiniteQueryAuthService = + (params: Test, options?: Omit) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); + }; diff --git a/src/shared/api/auth/queries/useTestSuspenseQuery.auth.ts b/src/shared/api/auth/queries/useTestSuspenseQuery.auth.ts new file mode 100644 index 0000000..6b04bb4 --- /dev/null +++ b/src/shared/api/auth/queries/useTestSuspenseQuery.auth.ts @@ -0,0 +1,94 @@ +import { InvalidateQueryFilters } from '@tanstack/react-query'; +import { getQueryClient } from '../../queryClient'; +import { + QueryError, + QueryKeyType, + UseSuspenseQueryWithOptionsParams, + QueryFetchParams, + queryKeys, +} from '../../models'; +import { useSuspenseQueryWithOptions } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +interface HookParams extends Test { + options?: UseSuspenseQueryWithOptionsParams< + CreateAccountResponse, + QueryError, + TData, + QueryKeyType + >['options']; +} + +interface QueryFnParams { + params: Test; + meta?: Record | undefined; + queryKey?: QueryKeyType; + signal?: AbortSignal; +} + +export const testSuspenseQueryQueryFnAuthService = async ({ + params, + signal, +}: QueryFnParams) => { + const response = await AuthService.testSuspenseQuery(params, { signal }); + + return response; +}; + +const getQueryKey = (params: Test) => + queryKeys.testSuspenseQueryAuthService(params); + +export const testSuspenseQuerySuspenseQueryAuthService = < + TData = CreateAccountResponse, + TError = QueryError, +>({ + params, + fetchOptions, +}: QueryFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.fetchQuery< + CreateAccountResponse, + TError, + TData, + QueryKeyType + >({ + queryKey: getQueryKey(params), + queryFn: ({ signal }) => + testSuspenseQueryQueryFnAuthService({ params, signal }), + ...fetchOptions, + }); +}; + +export const useTestSuspenseQuerySuspenseQueryAuthService = < + TData = CreateAccountResponse, +>({ + options, + ...params +}: HookParams) => { + return useSuspenseQueryWithOptions< + CreateAccountResponse, + QueryError, + TData, + QueryKeyType + >({ + queryFn: ({ signal }) => + testSuspenseQueryQueryFnAuthService({ params, signal }), + queryKey: getQueryKey(params), + options, + }); +}; + +export const invalidateTestSuspenseQuerySuspenseQueryAuthService = ( + params: Test, + options?: Omit, +) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); +}; diff --git a/src/shared/api/createApi.ts b/src/shared/api/createApi.ts index bbef7b4..3bcba00 100644 --- a/src/shared/api/createApi.ts +++ b/src/shared/api/createApi.ts @@ -58,6 +58,39 @@ type GenericApiBuilder = { }, ) => Promise, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + suspenseQuery( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; + disableGlobalErrorHandler?: boolean; + }, + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + suspenseInfiniteQuery( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; + disableGlobalErrorHandler?: boolean; + }, + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; + + queries( + queryFn: ( + params: TRequest, + context: { + signal?: AbortSignal; + client: TClient; + disableGlobalErrorHandler?: boolean; + }, + ) => Promise, + ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; }; export const createApi = @@ -107,6 +140,30 @@ export const createApi = disableGlobalErrorHandler: false, }); }, + + suspenseQuery: queryFn => (params, extra) => { + return queryFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, + }); + }, + + suspenseInfiniteQuery: queryFn => (params, extra) => { + return queryFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, + }); + }, + + queries: queryFn => (params, extra) => { + return queryFn(params, { + signal: extra?.signal, + client: baseQuery, + disableGlobalErrorHandler: false, + }); + }, }; return endpoints(builder); diff --git a/src/shared/api/hooks/index.ts b/src/shared/api/hooks/index.ts index 61007bc..d14ee12 100644 --- a/src/shared/api/hooks/index.ts +++ b/src/shared/api/hooks/index.ts @@ -4,4 +4,7 @@ export * from './useQueryWithOptions'; export * from './useInfiniteQueryWithOptions'; export * from './usePrefetchQueryWithOptions'; export * from './usePrefetchInfiniteQueryWithOptions'; +export * from './useQueriesWithOptions'; +export * from './useSuspenseQueryWithOptions'; +export * from './useSuspenseInfiniteQueryWithOptions'; export * from './syncedQuery'; diff --git a/src/shared/api/hooks/useQueriesWithOptions.ts b/src/shared/api/hooks/useQueriesWithOptions.ts new file mode 100644 index 0000000..929e934 --- /dev/null +++ b/src/shared/api/hooks/useQueriesWithOptions.ts @@ -0,0 +1,43 @@ +/* eslint-disable no-redeclare */ +/* eslint-disable func-style */ + +import { + useQueries, + QueriesOptions, + QueriesResults, +} from '@tanstack/react-query'; + +interface UseQueriesWithOptionsParams> { + queries: readonly [...QueriesOptions]; + options?: { + combine?: (result: QueriesResults) => any; + subscribed?: boolean; + }; +} + +export function useQueriesWithOptions< + T extends Array, + TCombinedResult = QueriesResults, +>( + params: UseQueriesWithOptionsParams & { + options: { + combine: (result: QueriesResults) => TCombinedResult; + subscribed?: boolean; + }; + }, +): TCombinedResult; + +export function useQueriesWithOptions>( + params: UseQueriesWithOptionsParams, +): QueriesResults; + +export function useQueriesWithOptions>( + params: UseQueriesWithOptionsParams, +): QueriesResults | any { + const { queries, options } = params; + + return useQueries({ + queries, + ...options, + }); +} diff --git a/src/shared/api/hooks/useSuspenseInfiniteQueryWithOptions.ts b/src/shared/api/hooks/useSuspenseInfiniteQueryWithOptions.ts new file mode 100644 index 0000000..6b727f9 --- /dev/null +++ b/src/shared/api/hooks/useSuspenseInfiniteQueryWithOptions.ts @@ -0,0 +1,94 @@ +/* eslint-disable no-redeclare */ +/* eslint-disable func-style */ + +import { + useSuspenseInfiniteQuery, + UseSuspenseInfiniteQueryOptions, + UseSuspenseInfiniteQueryResult, + InfiniteData, +} from '@tanstack/react-query'; +import { QueryKeyType } from 'api'; + +interface UseSuspenseInfiniteQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey extends QueryKeyType, + TPageParam, +> { + queryKey: TQueryKey; + queryFn: UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >['queryFn']; + initialPageParam: TPageParam; + getNextPageParam: UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >['getNextPageParam']; + options?: Omit< + UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, + 'queryFn' | 'queryKey' | 'initialPageParam' | 'getNextPageParam' + >; +} + +export function useSuspenseInfiniteQueryWithOptions< + TQueryFnData, + TError, + TData = InfiniteData, + TQueryKey extends QueryKeyType = QueryKeyType, + TPageParam = unknown, +>( + params: UseSuspenseInfiniteQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, +): UseSuspenseInfiniteQueryResult; + +export function useSuspenseInfiniteQueryWithOptions< + TQueryFnData, + TError, + TData = InfiniteData, + TQueryKey extends QueryKeyType = QueryKeyType, + TPageParam = unknown, +>( + params: UseSuspenseInfiniteQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, +): UseSuspenseInfiniteQueryResult { + const { queryKey, queryFn, initialPageParam, getNextPageParam, options } = + params; + + return useSuspenseInfiniteQuery< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >({ + queryKey, + queryFn, + initialPageParam, + getNextPageParam, + ...options, + }); +} diff --git a/src/shared/api/hooks/useSuspenseQueryWithOptions.ts b/src/shared/api/hooks/useSuspenseQueryWithOptions.ts new file mode 100644 index 0000000..630f50d --- /dev/null +++ b/src/shared/api/hooks/useSuspenseQueryWithOptions.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-redeclare */ +/* eslint-disable func-style */ + +import { + useSuspenseQuery, + UseSuspenseQueryOptions, + UseSuspenseQueryResult, + QueryFunction, +} from '@tanstack/react-query'; +import { QueryKeyType } from 'api'; + +interface UseSuspenseQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey extends QueryKeyType, +> { + queryKey: TQueryKey; + queryFn: QueryFunction; + options?: Omit< + UseSuspenseQueryOptions, + 'queryFn' | 'queryKey' + >; +} + +export function useSuspenseQueryWithOptions< + TQueryFnData, + TError, + TData = TQueryFnData, + TQueryKey extends QueryKeyType = QueryKeyType, +>( + params: UseSuspenseQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey + >, +): UseSuspenseQueryResult; + +export function useSuspenseQueryWithOptions< + TQueryFnData, + TError, + TData = TQueryFnData, + TQueryKey extends QueryKeyType = QueryKeyType, +>( + params: UseSuspenseQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey + >, +): UseSuspenseQueryResult { + const { queryKey, queryFn, options } = params; + + return useSuspenseQuery({ + queryKey, + queryFn, + ...options, + }); +} diff --git a/src/shared/api/models/index.ts b/src/shared/api/models/index.ts index fba8057..420eef9 100644 --- a/src/shared/api/models/index.ts +++ b/src/shared/api/models/index.ts @@ -6,5 +6,9 @@ export { type UseInfiniteQueryWithOptionsParams, type QueryFetchParams, type InfiniteQueryFetchParams, + type PrefetchInfiniteQueryFetchParams, type UsePrefetchQueryWithOptionsParams, + type UseSuspenseQueryWithOptionsParams, + type UseSuspenseInfiniteQueryWithOptionsParams, + type UseQueriesWithOptionsParams, } from './types'; diff --git a/src/shared/api/models/types.ts b/src/shared/api/models/types.ts index 13f96ad..59a1825 100644 --- a/src/shared/api/models/types.ts +++ b/src/shared/api/models/types.ts @@ -4,10 +4,14 @@ import { InfiniteData, UseQueryOptions, UseInfiniteQueryOptions, + UseSuspenseQueryOptions, + UseSuspenseInfiniteQueryOptions, FetchQueryOptions, FetchInfiniteQueryOptions, GetNextPageParamFunction, QueryFunction, + QueriesOptions, + QueriesResults, } from '@tanstack/react-query'; import { QueryKeyType } from './QueryKeys'; @@ -115,6 +119,36 @@ export interface InfiniteQueryFetchParams< ) => TPageParam | undefined; } +export interface PrefetchInfiniteQueryFetchParams< + TQueryFnData, + TError = QueryError, + TData = InfiniteData, + TParams = unknown, + TQueryKey extends QueryKeyType = QueryKeyType, + TPageParam = unknown, +> { + params: TParams; + fetchOptions?: Omit< + FetchInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, + | 'queryFn' + | 'queryKey' + | 'initialPageParam' + | 'getNextPageParam' + | 'staleTime' + >; + initialPageParam: TPageParam; + getNextPageParam: ( + lastPage: TQueryFnData, + allPages: TQueryFnData[], + ) => TPageParam | undefined; +} + export type FetchQueryOptionsWithoutKeyFn< TQueryFnData, TError, @@ -134,3 +168,60 @@ export interface QueryFetchParams { QueryKeyType >; } + +export interface UseSuspenseQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey extends QueryKeyType, +> { + queryKey: TQueryKey; + queryFn: QueryFunction; + options?: Omit< + UseSuspenseQueryOptions, + 'queryFn' | 'queryKey' + >; +} + +export interface UseSuspenseInfiniteQueryWithOptionsParams< + TQueryFnData, + TError, + TData, + TQueryKey extends QueryKeyType, + TPageParam, +> { + queryKey: TQueryKey; + queryFn: UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >['queryFn']; + initialPageParam: TPageParam; + getNextPageParam: UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >['getNextPageParam']; + options?: Omit< + UseSuspenseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, + 'queryFn' | 'queryKey' | 'initialPageParam' | 'getNextPageParam' + >; +} + +export interface UseQueriesWithOptionsParams> { + queries: readonly [...QueriesOptions]; + options?: { + combine?: (result: QueriesResults) => any; + subscribed?: boolean; + }; +} From 671bfabdc603988d520b205a4417fbc5c8cfeb0d Mon Sep 17 00:00:00 2001 From: VladyslavMartynov10 Date: Tue, 23 Sep 2025 17:59:37 +0300 Subject: [PATCH 3/5] feat: base query overrride example --- src/shared/api/auth/AuthService.ts | 48 ++++++++++++- src/shared/api/createApi.ts | 104 ++++++++++++++++++++++++----- 2 files changed, 135 insertions(+), 17 deletions(-) diff --git a/src/shared/api/auth/AuthService.ts b/src/shared/api/auth/AuthService.ts index 4825400..f6d3c7c 100644 --- a/src/shared/api/auth/AuthService.ts +++ b/src/shared/api/auth/AuthService.ts @@ -1,5 +1,5 @@ import { createApi, Promisify } from '../createApi'; -import { axiosBaseQuery } from '../baseQuery'; +import { axiosBaseQuery, baseQuery } from '../baseQuery'; import { CreateAccountResponse, Test } from './models'; interface AuthServiceAPI { @@ -11,6 +11,8 @@ interface AuthServiceAPI { testQueries: Promisify; testPrefetch: Promisify; testPrefetchInfiniteQuery: Promisify; + testQueryWithCustomClient: Promisify; + testQueryWithFetch: Promisify; } export const AuthService = createApi()({ @@ -88,5 +90,49 @@ export const AuthService = createApi()({ }); }, ), + + testQueryWithCustomClient: builder.query( + ({ token }, { signal, client }) => { + return client.get(`/v2/customer/custom`, { + params: { test: 'custom-client' }, + headers: { Authorization: `Bearer ${token}` }, + signal, + }); + }, + { + overrideBaseQuery: true, + baseQuery, + }, + ), + + testQueryWithFetch: builder.query( + async ({ token }, { signal }) => { + const params = new URLSearchParams({ test: 'fetch-example' }); + + const response = await fetch( + `https://api.example.com/v2/customer?${params}`, + { + method: 'GET', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + signal, + }, + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + return data; + }, + { + overrideBaseQuery: true, + baseQuery: null, + }, + ), }), }); diff --git a/src/shared/api/createApi.ts b/src/shared/api/createApi.ts index 3bcba00..34d7bfe 100644 --- a/src/shared/api/createApi.ts +++ b/src/shared/api/createApi.ts @@ -13,6 +13,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; prefetch( @@ -24,6 +28,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; mutation( @@ -35,6 +43,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; infiniteQuery( @@ -46,6 +58,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; prefetchInfiniteQuery( @@ -57,6 +73,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; suspenseQuery( @@ -68,6 +88,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; suspenseInfiniteQuery( @@ -79,6 +103,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; queries( @@ -90,6 +118,10 @@ type GenericApiBuilder = { disableGlobalErrorHandler?: boolean; }, ) => Promise, + options?: { + overrideBaseQuery?: boolean; + baseQuery?: any; + }, ): (params: TRequest, extra?: { signal?: AbortSignal }) => Promise; }; @@ -101,66 +133,106 @@ export const createApi = }): TServiceInterface => { const { baseQuery, endpoints } = config; const builder: GenericApiBuilder = { - query: queryFn => (params, extra) => { + query: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - prefetch: queryFn => (params, extra) => { + prefetch: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - mutation: mutationFn => (params, extra) => { + mutation: (mutationFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return mutationFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - infiniteQuery: queryFn => (params, extra) => { + infiniteQuery: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - prefetchInfiniteQuery: queryFn => (params, extra) => { + prefetchInfiniteQuery: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - suspenseQuery: queryFn => (params, extra) => { + suspenseQuery: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - suspenseInfiniteQuery: queryFn => (params, extra) => { + suspenseInfiniteQuery: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, - queries: queryFn => (params, extra) => { + queries: (queryFn, options) => (params, extra) => { + const clientToUse = + options?.overrideBaseQuery && options?.baseQuery + ? options.baseQuery + : baseQuery; + return queryFn(params, { signal: extra?.signal, - client: baseQuery, + client: clientToUse as TClient, disableGlobalErrorHandler: false, }); }, From a390e3eacde480a789a9a76393b8d0e0b0605a79 Mon Sep 17 00:00:00 2001 From: VladyslavMartynov10 Date: Wed, 24 Sep 2025 14:50:56 +0300 Subject: [PATCH 4/5] chore: minors --- scripts/api-codegen/server-hooks.cpp | 9 +- src/shared/api/auth/QueryKeys.ts | 7 + src/shared/api/auth/queries/index.ts | 2 + .../useTestQueryWithCustomClient.auth.ts | 153 ++++++++++++++++++ .../queries/useTestQueryWithFetch.auth.ts | 148 +++++++++++++++++ 5 files changed, 312 insertions(+), 7 deletions(-) create mode 100644 src/shared/api/auth/queries/useTestQueryWithCustomClient.auth.ts create mode 100644 src/shared/api/auth/queries/useTestQueryWithFetch.auth.ts diff --git a/scripts/api-codegen/server-hooks.cpp b/scripts/api-codegen/server-hooks.cpp index f6c0a5b..b0c5ecb 100644 --- a/scripts/api-codegen/server-hooks.cpp +++ b/scripts/api-codegen/server-hooks.cpp @@ -1852,30 +1852,27 @@ void generateHooks(const std::string &serviceName, return; } - // First, find the interface that defines the API std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))"); std::smatch createApiMatch; if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) { - return; // No createApi found + return; } std::string interfaceName = createApiMatch[1].str(); - // Find the interface definition std::regex interfacePattern( R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})"); std::smatch interfaceMatch; if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) { - return; // Interface not found + return; } std::string interfaceContent = interfaceMatch[1].str(); - // Extract endpoint definitions from interface std::regex endpointDefPattern( R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)"); @@ -1896,7 +1893,6 @@ void generateHooks(const std::string &serviceName, std::string requestType = match[2].str(); std::string responseType = match[3].str(); - // Clean up whitespace requestType.erase( remove_if(requestType.begin(), requestType.end(), ::isspace), requestType.end()); @@ -1910,7 +1906,6 @@ void generateHooks(const std::string &serviceName, bool isVoidRequest = requestType == "void"; - // Check what method type this endpoint uses std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()"); std::regex queryPattern(endpointName + R"(:\s*builder\.query\s*\()"); std::regex infiniteQueryPattern(endpointName + R"(:\s*builder\.infiniteQuery\s*\()"); diff --git a/src/shared/api/auth/QueryKeys.ts b/src/shared/api/auth/QueryKeys.ts index 594b6f5..65bfe4e 100644 --- a/src/shared/api/auth/QueryKeys.ts +++ b/src/shared/api/auth/QueryKeys.ts @@ -10,6 +10,9 @@ const QUERY_KEYS = { TEST_PREFETCH_AUTH_SERVICE: 'TEST_PREFETCH_AUTH_SERVICE', TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE: 'TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE', + TEST_QUERY_WITH_CUSTOM_CLIENT_AUTH_SERVICE: + 'TEST_QUERY_WITH_CUSTOM_CLIENT_AUTH_SERVICE', + TEST_QUERY_WITH_FETCH_AUTH_SERVICE: 'TEST_QUERY_WITH_FETCH_AUTH_SERVICE', TEST_MUTATION_AUTH_SERVICE: 'TEST_MUTATION_AUTH_SERVICE', } as const; @@ -28,6 +31,10 @@ export const AUTH_QUERY_KEYS = { [QUERY_KEYS.TEST_PREFETCH_AUTH_SERVICE, params] as const, testPrefetchInfiniteQueryAuthService: (params: Test) => [QUERY_KEYS.TEST_PREFETCH_INFINITE_QUERY_AUTH_SERVICE, params] as const, + testQueryWithCustomClientAuthService: (params: Test) => + [QUERY_KEYS.TEST_QUERY_WITH_CUSTOM_CLIENT_AUTH_SERVICE, params] as const, + testQueryWithFetchAuthService: (params: Test) => + [QUERY_KEYS.TEST_QUERY_WITH_FETCH_AUTH_SERVICE, params] as const, testMutationAuthService: () => [QUERY_KEYS.TEST_MUTATION_AUTH_SERVICE] as const, }; diff --git a/src/shared/api/auth/queries/index.ts b/src/shared/api/auth/queries/index.ts index 58d1183..10f11db 100644 --- a/src/shared/api/auth/queries/index.ts +++ b/src/shared/api/auth/queries/index.ts @@ -5,3 +5,5 @@ export * from './useTestSuspenseInfiniteQuery.auth'; export * from './useTestQueries.auth'; export * from './useTestPrefetch.auth'; export * from './useTestPrefetchInfiniteQuery.auth'; +export * from './useTestQueryWithCustomClient.auth'; +export * from './useTestQueryWithFetch.auth'; diff --git a/src/shared/api/auth/queries/useTestQueryWithCustomClient.auth.ts b/src/shared/api/auth/queries/useTestQueryWithCustomClient.auth.ts new file mode 100644 index 0000000..0e33b81 --- /dev/null +++ b/src/shared/api/auth/queries/useTestQueryWithCustomClient.auth.ts @@ -0,0 +1,153 @@ +import { + InvalidateQueryFilters, + QueryObserverOptions, + QueryObserverResult, +} from '@tanstack/react-query'; +import { useComputed, useObservable } from '@legendapp/state/react'; +import { SyncedOptions } from '@legendapp/state/sync'; +import { getQueryClient } from '../../queryClient'; +import { + QueryError, + QueryKeyType, + UseQueryWithOptionsParams, + QueryFetchParams, + queryKeys, +} from '../../models'; +import { useQueryWithOptions, syncedQuery } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +interface HookParams extends Test { + options?: UseQueryWithOptionsParams< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType + >['options']; +} + +interface ObservableHookParams { + params$: Test; + options?: Omit< + QueryObserverOptions< + CreateAccountResponse[], + QueryError, + TData, + TSelected, + QueryKeyType + >, + 'queryFn' | 'queryKey' + >; + observableOptions?: Omit< + SyncedOptions>, + 'get' | 'set' | 'retry' + >; +} + +interface QueryFnParams { + params: Test; + meta?: Record | undefined; + queryKey?: QueryKeyType; + signal?: AbortSignal; +} + +export const testQueryWithCustomClientQueryFnAuthService = async ({ + params, + signal, +}: QueryFnParams) => { + const response = await AuthService.testQueryWithCustomClient(params, { + signal, + }); + + return response; +}; + +const getQueryKey = (params: Test) => + queryKeys.testQueryWithCustomClientAuthService(params); + +export const testQueryWithCustomClientQueryAuthService = < + TData = CreateAccountResponse[], + TError = QueryError, +>({ + params, + fetchOptions, +}: QueryFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.fetchQuery< + CreateAccountResponse[], + TError, + TData, + QueryKeyType + >({ + queryKey: getQueryKey(params), + queryFn: ({ signal }) => + testQueryWithCustomClientQueryFnAuthService({ params, signal }), + ...fetchOptions, + }); +}; + +export const useTestQueryWithCustomClientQueryAuthService = < + TData = CreateAccountResponse[], +>({ + options, + ...params +}: HookParams) => { + return useQueryWithOptions< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType + >({ + queryFn: ({ signal }) => + testQueryWithCustomClientQueryFnAuthService({ params, signal }), + queryKey: getQueryKey(params), + options, + }); +}; + +export const invalidateTestQueryWithCustomClientQueryAuthService = ( + params: Test, + options?: Omit, +) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); +}; + +export const useTestQueryWithCustomClientAuthServiceObservable = < + TData = CreateAccountResponse[], + TSelected = TData, +>({ + params$, + options, + observableOptions, +}: ObservableHookParams) => { + const queryClient = getQueryClient(); + + const queryKey$ = useComputed(() => getQueryKey(params$)); + + return useObservable( + syncedQuery< + CreateAccountResponse[], + QueryError, + TData, + TSelected, + QueryKeyType + >({ + queryClient, + queryFn: ({ signal }) => + testQueryWithCustomClientQueryFnAuthService({ + params: params$, + signal, + }), + queryKey: queryKey$.get(), + options, + observableOptions, + }), + ); +}; diff --git a/src/shared/api/auth/queries/useTestQueryWithFetch.auth.ts b/src/shared/api/auth/queries/useTestQueryWithFetch.auth.ts new file mode 100644 index 0000000..09e650b --- /dev/null +++ b/src/shared/api/auth/queries/useTestQueryWithFetch.auth.ts @@ -0,0 +1,148 @@ +import { + InvalidateQueryFilters, + QueryObserverOptions, + QueryObserverResult, +} from '@tanstack/react-query'; +import { useComputed, useObservable } from '@legendapp/state/react'; +import { SyncedOptions } from '@legendapp/state/sync'; +import { getQueryClient } from '../../queryClient'; +import { + QueryError, + QueryKeyType, + UseQueryWithOptionsParams, + QueryFetchParams, + queryKeys, +} from '../../models'; +import { useQueryWithOptions, syncedQuery } from '../../hooks'; +import { AuthService } from '../AuthService'; + +import { CreateAccountResponse, Test } from '../models'; + +interface HookParams extends Test { + options?: UseQueryWithOptionsParams< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType + >['options']; +} + +interface ObservableHookParams { + params$: Test; + options?: Omit< + QueryObserverOptions< + CreateAccountResponse[], + QueryError, + TData, + TSelected, + QueryKeyType + >, + 'queryFn' | 'queryKey' + >; + observableOptions?: Omit< + SyncedOptions>, + 'get' | 'set' | 'retry' + >; +} + +interface QueryFnParams { + params: Test; + meta?: Record | undefined; + queryKey?: QueryKeyType; + signal?: AbortSignal; +} + +export const testQueryWithFetchQueryFnAuthService = async ({ + params, + signal, +}: QueryFnParams) => { + const response = await AuthService.testQueryWithFetch(params, { signal }); + + return response; +}; + +const getQueryKey = (params: Test) => + queryKeys.testQueryWithFetchAuthService(params); + +export const testQueryWithFetchQueryAuthService = < + TData = CreateAccountResponse[], + TError = QueryError, +>({ + params, + fetchOptions, +}: QueryFetchParams) => { + const queryClient = getQueryClient(); + + return queryClient.fetchQuery< + CreateAccountResponse[], + TError, + TData, + QueryKeyType + >({ + queryKey: getQueryKey(params), + queryFn: ({ signal }) => + testQueryWithFetchQueryFnAuthService({ params, signal }), + ...fetchOptions, + }); +}; + +export const useTestQueryWithFetchQueryAuthService = < + TData = CreateAccountResponse[], +>({ + options, + ...params +}: HookParams) => { + return useQueryWithOptions< + CreateAccountResponse[], + QueryError, + TData, + QueryKeyType + >({ + queryFn: ({ signal }) => + testQueryWithFetchQueryFnAuthService({ params, signal }), + queryKey: getQueryKey(params), + options, + }); +}; + +export const invalidateTestQueryWithFetchQueryAuthService = ( + params: Test, + options?: Omit, +) => { + const queryClient = getQueryClient(); + + return queryClient.invalidateQueries({ + queryKey: getQueryKey(params), + ...options, + }); +}; + +export const useTestQueryWithFetchAuthServiceObservable = < + TData = CreateAccountResponse[], + TSelected = TData, +>({ + params$, + options, + observableOptions, +}: ObservableHookParams) => { + const queryClient = getQueryClient(); + + const queryKey$ = useComputed(() => getQueryKey(params$)); + + return useObservable( + syncedQuery< + CreateAccountResponse[], + QueryError, + TData, + TSelected, + QueryKeyType + >({ + queryClient, + queryFn: ({ signal }) => + testQueryWithFetchQueryFnAuthService({ params: params$, signal }), + queryKey: queryKey$.get(), + options, + observableOptions, + }), + ); +}; From 8e4aaec0ee9761b8f1c72acc191e716e997226e9 Mon Sep 17 00:00:00 2001 From: VladyslavMartynov10 Date: Mon, 29 Sep 2025 21:41:38 +0300 Subject: [PATCH 5/5] chore: activity indicator --- App.tsx | 25 +- metro.config.js | 6 - package.json | 10 +- src/navigation/RootNavigator.tsx | 2 +- .../ActivityIndicator/ActivityIndicator.tsx | 5 +- yarn.lock | 976 ++++++++++++++++-- 6 files changed, 934 insertions(+), 90 deletions(-) diff --git a/App.tsx b/App.tsx index d8ebbfc..460bf45 100644 --- a/App.tsx +++ b/App.tsx @@ -1,9 +1,13 @@ import React from 'react'; -import { StyleSheet as RnStylesheet } from 'react-native'; +import { StyleSheet as RNStylesheet, View } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { KeyboardProvider } from 'react-native-keyboard-controller'; import { StyleSheet } from 'react-native-unistyles'; +import { + PortalProvider as TeleportProvider, + PortalHost, +} from 'react-native-teleport'; import { QueryClientProvider } from '@tanstack/react-query'; import { Toaster } from 'sonner-native'; import { ReducedMotionConfig, ReduceMotion } from 'react-native-reanimated'; @@ -40,12 +44,17 @@ export const App: React.FC = () => { - - - + + + + + + + + - + @@ -53,8 +62,12 @@ export const App: React.FC = () => { ); }; -const styles = RnStylesheet.create({ +const styles = RNStylesheet.create({ layout: { flex: 1, }, + overlay: { + ...RNStylesheet.absoluteFillObject, + zIndex: 9999, + }, }); diff --git a/metro.config.js b/metro.config.js index 4c77960..08f9d38 100644 --- a/metro.config.js +++ b/metro.config.js @@ -6,12 +6,6 @@ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const defaultConfig = getDefaultConfig(__dirname); const { assetExts, sourceExts } = defaultConfig.resolver; -/** - * Metro configuration - * https://reactnative.dev/docs/metro - * - * @type {import('metro-config').MetroConfig} - */ const config = { transformer: { babelTransformerPath: require.resolve( diff --git a/package.json b/package.json index c9c9a08..1790c5a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "prepare": "husky" }, "dependencies": { - "@gorhom/portal": "^1.0.14", "@legendapp/state": "^3.0.0-beta.30", "@react-native-vector-icons/icomoon": "^12.2.0", "@react-navigation/bottom-tabs": "7.2.0", @@ -57,6 +56,7 @@ "react-native-safe-area-context": "5.6.0", "react-native-screens": "4.14.0", "react-native-svg": "15.12.1", + "react-native-teleport": "^0.3.0", "react-native-unistyles": "3.0.10", "react-native-vector-icons": "10.2.0", "sonner-native": "0.21.1", @@ -74,10 +74,10 @@ "@react-native/eslint-config": "0.79.0", "@react-native/metro-config": "0.79.0", "@react-native/typescript-config": "0.79.0", - "@rozenite/metro": "1.0.0-alpha.12", - "@rozenite/mmkv-plugin": "1.0.0-alpha.12", - "@rozenite/network-activity-plugin": "1.0.0-alpha.12", - "@rozenite/tanstack-query-plugin": "1.0.0-alpha.12", + "@rozenite/metro": "1.0.0-alpha.14", + "@rozenite/mmkv-plugin": "1.0.0-alpha.14", + "@rozenite/network-activity-plugin": "1.0.0-alpha.14", + "@rozenite/tanstack-query-plugin": "1.0.0-alpha.14", "@svgr/cli": "^8.1.0", "@types/react": "^19.1.2", "@types/react-native-vector-icons": "^6.4.18", diff --git a/src/navigation/RootNavigator.tsx b/src/navigation/RootNavigator.tsx index 5e8038c..af26484 100644 --- a/src/navigation/RootNavigator.tsx +++ b/src/navigation/RootNavigator.tsx @@ -23,7 +23,7 @@ export const RootNavigator: React.FC = () => { uniProps={(theme, runtime) => ({ barStyle: runtime.themeName === 'light' ? 'dark-content' : 'light-content', - backgroundColor: theme.colors.background, + backgroundColor: theme.colors.transparent, })} animated translucent diff --git a/src/shared/ui/ActivityIndicator/ActivityIndicator.tsx b/src/shared/ui/ActivityIndicator/ActivityIndicator.tsx index a93816a..e83f480 100644 --- a/src/shared/ui/ActivityIndicator/ActivityIndicator.tsx +++ b/src/shared/ui/ActivityIndicator/ActivityIndicator.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { ActivityIndicator as BaseIndicator, View } from 'react-native'; +import { Portal } from 'react-native-teleport'; import { StyleSheet, withUnistyles } from 'react-native-unistyles'; import { AnimatedBackdrop } from '../AnimatedBackDrop'; @@ -13,7 +14,7 @@ export const ActivityIndicator: React.FC = ({ isVisible, }) => { return ( - <> + {isVisible && ( @@ -24,7 +25,7 @@ export const ActivityIndicator: React.FC = ({ /> )} - + ); }; diff --git a/yarn.lock b/yarn.lock index b0808da..deee28a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -313,6 +313,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-identifier@npm:7.25.9" @@ -320,6 +327,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10c0/c558f11c4871d526498e49d07a84752d1800bf72ac0d3dad100309a2eaba24efbf56ea59af5137ff15e3a00280ebe588560534b0e894a4750f8b1411d8f78b84 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-option@npm:7.25.9" @@ -370,6 +384,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.0.0": + version: 7.28.4 + resolution: "@babel/parser@npm:7.28.4" + dependencies: + "@babel/types": "npm:^7.28.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/58b239a5b1477ac7ed7e29d86d675cc81075ca055424eba6485872626db2dc556ce63c45043e5a679cd925e999471dba8a3ed4864e7ab1dbf64306ab72c52707 + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.26.9": version: 7.26.9 resolution: "@babel/parser@npm:7.26.9" @@ -1724,6 +1749,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/types@npm:7.28.4" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + checksum: 10c0/ac6f909d6191319e08c80efbfac7bd9a25f80cc83b43cd6d82e7233f7a6b9d6e7b90236f3af7400a3f83b576895bcab9188a22b584eb0f224e80e6d4e95f4517 + languageName: node + linkType: hard + "@commitlint/cli@npm:^19.5.0": version: 19.7.1 resolution: "@commitlint/cli@npm:19.7.1" @@ -1915,6 +1950,59 @@ __metadata: languageName: node linkType: hard +"@discoveryjs/cli@npm:2.14.2": + version: 2.14.2 + resolution: "@discoveryjs/cli@npm:2.14.2" + dependencies: + "@discoveryjs/json-ext": "npm:^0.6.3" + archiver: "npm:^5.3.1" + chalk: "npm:^4.1.2" + clap: "npm:^3.1.1" + cors: "npm:^2.8.5" + cron-parser: "npm:^4.9.0" + cron-validator: "npm:^1.3.1" + cronstrue: "npm:^2.51.0" + esbuild: "npm:^0.25.1" + express: "npm:^4.21.1" + mime: "npm:^3.0.0" + pretty-ms: "npm:^7.0.0" + peerDependencies: + "@discoveryjs/discovery": ^1.0.0-beta.74 + bin: + discovery: bin/serve + discovery-build: bin/build + checksum: 10c0/0bc918452305a53dcfb06240045df6d1526807c1fced5d0e7af2314343a12757ab1acc2b9c616e575db59a8ef29e9677228c64c45ef695e53e57fca2c3148532 + languageName: node + linkType: hard + +"@discoveryjs/discovery@npm:1.0.0-beta.93": + version: 1.0.0-beta.93 + resolution: "@discoveryjs/discovery@npm:1.0.0-beta.93" + dependencies: + "@discoveryjs/json-ext": "npm:^0.6.3" + codemirror: "npm:^5.65.2" + github-slugger: "npm:^2.0.0" + hitext: "npm:^1.0.0-beta.1" + jora: "npm:1.0.0-beta.13" + marked: "npm:^14.1.4" + checksum: 10c0/9fc58bce3dab11879e84bb086ad664ea6e06a0f6e862d8cbcfa6d05f4317249adcd456fe35432668f202518191e406e58f8f9b0fcc449e359090d46cf464f39a + languageName: node + linkType: hard + +"@discoveryjs/json-ext@npm:^0.6.3": + version: 0.6.3 + resolution: "@discoveryjs/json-ext@npm:0.6.3" + checksum: 10c0/778a9f9d5c3696da3c1f9fa4186613db95a1090abbfb6c2601430645c0d0158cd5e4ba4f32c05904e2dd2747d57710f6aab22bd2f8aa3c4e8feab9b247c65d85 + languageName: node + linkType: hard + +"@discoveryjs/natural-compare@npm:^1.1.0": + version: 1.1.0 + resolution: "@discoveryjs/natural-compare@npm:1.1.0" + checksum: 10c0/ce9f86237d1ffa68938cd4a0a0dbb10a3cf6dcdb7a8759371a65e0b8f04c12f47aa96f9ab4a2b2598f71e107805ad05d1c190ad156f0a15478fc454112a91660 + languageName: node + linkType: hard + "@egjs/hammerjs@npm:^2.0.17": version: 2.0.17 resolution: "@egjs/hammerjs@npm:2.0.17" @@ -1940,6 +2028,188 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/aix-ppc64@npm:0.25.10" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-arm64@npm:0.25.10" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-arm@npm:0.25.10" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/android-x64@npm:0.25.10" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/darwin-arm64@npm:0.25.10" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/darwin-x64@npm:0.25.10" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/freebsd-arm64@npm:0.25.10" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/freebsd-x64@npm:0.25.10" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-arm64@npm:0.25.10" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-arm@npm:0.25.10" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-ia32@npm:0.25.10" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-loong64@npm:0.25.10" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-mips64el@npm:0.25.10" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-ppc64@npm:0.25.10" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-riscv64@npm:0.25.10" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-s390x@npm:0.25.10" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/linux-x64@npm:0.25.10" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/netbsd-arm64@npm:0.25.10" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/netbsd-x64@npm:0.25.10" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openbsd-arm64@npm:0.25.10" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openbsd-x64@npm:0.25.10" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/openharmony-arm64@npm:0.25.10" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/sunos-x64@npm:0.25.10" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-arm64@npm:0.25.10" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-ia32@npm:0.25.10" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.10": + version: 0.25.10 + resolution: "@esbuild/win32-x64@npm:0.25.10" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.1 resolution: "@eslint-community/eslint-utils@npm:4.4.1" @@ -2040,18 +2310,6 @@ __metadata: languageName: node linkType: hard -"@gorhom/portal@npm:^1.0.14": - version: 1.0.14 - resolution: "@gorhom/portal@npm:1.0.14" - dependencies: - nanoid: "npm:^3.3.1" - peerDependencies: - react: "*" - react-native: "*" - checksum: 10c0/86f33afc2ac2656a86a6f3fd1e41565419839576ede2c38333434a93a0a2fe4fb6fc18ab3360579427f2a1fc3b4564b933cc5ae1793a7e2825c93860a00b215f - languageName: node - linkType: hard - "@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": version: 9.3.0 resolution: "@hapi/hoek@npm:9.3.0" @@ -3046,97 +3304,98 @@ __metadata: languageName: node linkType: hard -"@rozenite/metro@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/metro@npm:1.0.0-alpha.12" +"@rozenite/metro@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/metro@npm:1.0.0-alpha.14" dependencies: - "@rozenite/middleware": "npm:1.0.0-alpha.12" + "@rozenite/middleware": "npm:1.0.0-alpha.14" + "@rozenite/tools": "npm:1.0.0-alpha.14" tslib: "npm:^2.3.0" - checksum: 10c0/58de765715d3b1e1d726cd96fb4a1f8e86edecdaa49eb71a56ad4b3c2558c61d37c64911e0a9547b5d10c4ff53ca851f1ab842cfcc9e28979fc0f79df8e32f68 + checksum: 10c0/52f45f8e247b232a1ece2f9a0f7e395c2bc042d362fb46d0abf63fa2daa304454aae942a707c8dc48c793cebc4713e239dc2c16ce471f969152ac82d5ee9b80e languageName: node linkType: hard -"@rozenite/middleware@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/middleware@npm:1.0.0-alpha.12" +"@rozenite/middleware@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/middleware@npm:1.0.0-alpha.14" dependencies: - "@rozenite/runtime": "npm:1.0.0-alpha.12" - "@rozenite/tools": "npm:1.0.0-alpha.12" + "@rozenite/runtime": "npm:1.0.0-alpha.14" + "@rozenite/tools": "npm:1.0.0-alpha.14" express: "npm:^5.1.0" semver: "npm:^7.7.2" serve-static: "npm:^2.2.0" tslib: "npm:^2.3.0" - checksum: 10c0/ca0f48e375ce582803ae263b4756e2395127e97774e85b9852ea4278007f6749c24354c12b46a867b676bbc1f7552ed965c4d9bb176eec75b74728fa9d66ac4d + checksum: 10c0/e17608799232c1b79d1befbe30aedc265ca88e67fe0df8823e98425e8dedde4361fb5f29194a2280a23cdf126812accb2e7d3b4f5ac556a99cdbc7aae2c64e18 languageName: node linkType: hard -"@rozenite/mmkv-plugin@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/mmkv-plugin@npm:1.0.0-alpha.12" +"@rozenite/mmkv-plugin@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/mmkv-plugin@npm:1.0.0-alpha.14" dependencies: - "@rozenite/plugin-bridge": "npm:1.0.0-alpha.12" + "@rozenite/plugin-bridge": "npm:1.0.0-alpha.14" nanoevents: "npm:^9.1.0" peerDependencies: react: "*" react-native: "*" react-native-mmkv: "*" - checksum: 10c0/2ebacf86de1c2b1e0a64d2b2e584a3b02f94045e659d073cb6a1dab38085a0e077a91106a7168f7b2261dcb3f819c7b70866baa019a9976fd57fd8a6055e508c + checksum: 10c0/3fbed13d16fa4c50fb89c33d36584e215e36a4a289d780b22209ae38893f8cfbfe7906f3c4c1e3be769cea86e553f4cb5801e249f7e0aea154413393cd0ceab9 languageName: node linkType: hard -"@rozenite/network-activity-plugin@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/network-activity-plugin@npm:1.0.0-alpha.12" +"@rozenite/network-activity-plugin@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/network-activity-plugin@npm:1.0.0-alpha.14" dependencies: - "@rozenite/plugin-bridge": "npm:1.0.0-alpha.12" + "@rozenite/plugin-bridge": "npm:1.0.0-alpha.14" nanoevents: "npm:^9.1.0" peerDependencies: react-native-sse: "*" peerDependenciesMeta: react-native-sse: optional: true - checksum: 10c0/c5a4995ab00b38416ed64ef369de882be426d066276d6396b2e352d944742a315b827e74407ae8c40ecbbc6aac8005fd01c68273afed65fa10eb7e393713a031 + checksum: 10c0/5c550ebb6ff19c3c999cb598ac4971120ef49be221a40b6cdfd8b21e9d9402d33b4f1c5ab228e3a1c252e3932345d28381680191c772eca3a43061d84dda137e languageName: node linkType: hard -"@rozenite/plugin-bridge@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/plugin-bridge@npm:1.0.0-alpha.12" +"@rozenite/plugin-bridge@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/plugin-bridge@npm:1.0.0-alpha.14" dependencies: tslib: "npm:^2.3.0" peerDependencies: react: ">=17" - checksum: 10c0/9ec11bd61a6d37406bc4f4c9662b55841904becb71c7e9470fc2f3079791ed3b1ffefc5e9745ffa9ee7777531f5e063e5f857a5dd69042873e71ef1f3f63d02b + checksum: 10c0/025500642e5e87091ae1df40760a8127b2c6b14ae183685f8f92b229221895d9869856c2b6dfa480e9a076594c67f89ac4e328d463c11ed9cac90fce860fe5cd languageName: node linkType: hard -"@rozenite/runtime@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/runtime@npm:1.0.0-alpha.12" +"@rozenite/runtime@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/runtime@npm:1.0.0-alpha.14" dependencies: tslib: "npm:^2.3.0" - checksum: 10c0/3f81a2e14c4627cb749ad1bbb07cdc671b9df6cc17f42c87890853d3fae8fd441e3069d7b5ea1c0e79b35527e35f151815abaa15da56986240c05668d257f46d + checksum: 10c0/8091e40af616b22f04144999bd760aacb121f0e635793425a720ca9e0bb63aa266b4bdba04aff06ed3998eb8afe7d59e3dab16b466de9d86f7ce3a4406ca3093 languageName: node linkType: hard -"@rozenite/tanstack-query-plugin@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/tanstack-query-plugin@npm:1.0.0-alpha.12" +"@rozenite/tanstack-query-plugin@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/tanstack-query-plugin@npm:1.0.0-alpha.14" dependencies: - "@rozenite/plugin-bridge": "npm:1.0.0-alpha.12" + "@rozenite/plugin-bridge": "npm:1.0.0-alpha.14" fast-deep-equal: "npm:^3.1.3" peerDependencies: "@tanstack/react-query": ^5.0.0 react: "*" react-native: "*" - checksum: 10c0/19439cba4e0836e4f4639c56948b33235115969125bef8196d93c93712c2c046fcbc92cdcdb2da7f7820d008a0d30f614f70c2558cd9d918a404fde41fdfb128 + checksum: 10c0/84a06d3a2f65e97eb02e37710b174ebdc124a4686f9aff92d3d404db3b2c81444dfdbbc54ff99e352916da58887a80826742b516f1a8ea1f94c478c421d27af2 languageName: node linkType: hard -"@rozenite/tools@npm:1.0.0-alpha.12": - version: 1.0.0-alpha.12 - resolution: "@rozenite/tools@npm:1.0.0-alpha.12" - checksum: 10c0/484bc5bacb27c961cc96ca666f0bb80e069446e412beca6f914f20078d9dc9dd37dac6ee00f8b4763d1fceb68ff28d294b8449a72db347db9d7283ac82207ce7 +"@rozenite/tools@npm:1.0.0-alpha.14": + version: 1.0.0-alpha.14 + resolution: "@rozenite/tools@npm:1.0.0-alpha.14" + checksum: 10c0/fa6ba12e448aa71437438e38eb8116061d368bc2d78264e6fee426fecbaed74424c97602281b08e831ba83ba3926175f7832da48dc879f25d4fefb505679ec29 languageName: node linkType: hard @@ -3956,7 +4215,6 @@ __metadata: "@babel/runtime": "npm:^7.25.0" "@commitlint/cli": "npm:^19.5.0" "@commitlint/config-conventional": "npm:^19.5.0" - "@gorhom/portal": "npm:^1.0.14" "@legendapp/state": "npm:^3.0.0-beta.30" "@react-native-community/cli": "npm:18.0.0" "@react-native-community/cli-platform-android": "npm:18.0.0" @@ -3968,10 +4226,10 @@ __metadata: "@react-navigation/bottom-tabs": "npm:7.2.0" "@react-navigation/native": "npm:7.0.14" "@react-navigation/native-stack": "npm:7.2.0" - "@rozenite/metro": "npm:1.0.0-alpha.12" - "@rozenite/mmkv-plugin": "npm:1.0.0-alpha.12" - "@rozenite/network-activity-plugin": "npm:1.0.0-alpha.12" - "@rozenite/tanstack-query-plugin": "npm:1.0.0-alpha.12" + "@rozenite/metro": "npm:1.0.0-alpha.14" + "@rozenite/mmkv-plugin": "npm:1.0.0-alpha.14" + "@rozenite/network-activity-plugin": "npm:1.0.0-alpha.14" + "@rozenite/tanstack-query-plugin": "npm:1.0.0-alpha.14" "@shopify/react-native-skia": "npm:2.2.3" "@svgr/cli": "npm:^8.1.0" "@tanstack/react-query": "npm:5.85.5" @@ -4005,6 +4263,8 @@ __metadata: react-i18next: "npm:15.0.2" react-native: "npm:0.79.0" react-native-bootsplash: "npm:6.3.3" + react-native-bundle-discovery: "npm:^1.2.1" + react-native-bundle-discovery-rozenite-plugin: "npm:^1.0.0" react-native-config: "npm:1.5.5" react-native-device-info: "npm:14.0.4" react-native-edge-to-edge: "npm:^1.6.0" @@ -4018,6 +4278,7 @@ __metadata: react-native-screens: "npm:4.14.0" react-native-svg: "npm:15.12.1" react-native-svg-transformer: "npm:^1.5.0" + react-native-teleport: "npm:^0.3.0" react-native-unistyles: "npm:3.0.10" react-native-vector-icons: "npm:10.2.0" sonner-native: "npm:0.21.1" @@ -4043,7 +4304,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.7, accepts@npm:~1.3.7": +"accepts@npm:^1.3.7, accepts@npm:~1.3.7, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -4119,6 +4380,13 @@ __metadata: languageName: node linkType: hard +"ansi-colors@npm:^4.1.1": + version: 4.1.3 + resolution: "ansi-colors@npm:4.1.3" + checksum: 10c0/ec87a2f59902f74e61eada7f6e6fe20094a628dab765cfdbd03c3477599368768cffccdb5d3bb19a1b6c99126783a143b1fee31aab729b31ffe5836c7e5e28b9 + languageName: node + linkType: hard + "ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -4216,6 +4484,57 @@ __metadata: languageName: node linkType: hard +"archiver-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "archiver-utils@npm:2.1.0" + dependencies: + glob: "npm:^7.1.4" + graceful-fs: "npm:^4.2.0" + lazystream: "npm:^1.0.0" + lodash.defaults: "npm:^4.2.0" + lodash.difference: "npm:^4.5.0" + lodash.flatten: "npm:^4.4.0" + lodash.isplainobject: "npm:^4.0.6" + lodash.union: "npm:^4.6.0" + normalize-path: "npm:^3.0.0" + readable-stream: "npm:^2.0.0" + checksum: 10c0/6ea5b02e440f3099aff58b18dd384f84ecfe18632e81d26c1011fe7dfdb80ade43d7a06cbf048ef0e9ee0f2c87a80cb24c0f0ac5e3a2c4d67641d6f0d6e36ece + languageName: node + linkType: hard + +"archiver-utils@npm:^3.0.4": + version: 3.0.4 + resolution: "archiver-utils@npm:3.0.4" + dependencies: + glob: "npm:^7.2.3" + graceful-fs: "npm:^4.2.0" + lazystream: "npm:^1.0.0" + lodash.defaults: "npm:^4.2.0" + lodash.difference: "npm:^4.5.0" + lodash.flatten: "npm:^4.4.0" + lodash.isplainobject: "npm:^4.0.6" + lodash.union: "npm:^4.6.0" + normalize-path: "npm:^3.0.0" + readable-stream: "npm:^3.6.0" + checksum: 10c0/9bb7e271e95ff33bdbdcd6f69f8860e0aeed3fcba352a74f51a626d1c32b404f20e3185d5214f171b24a692471d01702f43874d1a4f0d2e5f57bd0834bc54c14 + languageName: node + linkType: hard + +"archiver@npm:^5.3.1": + version: 5.3.2 + resolution: "archiver@npm:5.3.2" + dependencies: + archiver-utils: "npm:^2.1.0" + async: "npm:^3.2.4" + buffer-crc32: "npm:^0.2.1" + readable-stream: "npm:^3.6.0" + readdir-glob: "npm:^1.1.2" + tar-stream: "npm:^2.2.0" + zip-stream: "npm:^4.1.0" + checksum: 10c0/973384d749b3fa96f44ceda1603a65aaa3f24a267230d69a4df9d7b607d38d3ebc6c18c358af76eb06345b6b331ccb9eca07bd079430226b5afce95de22dfade + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -4249,6 +4568,13 @@ __metadata: languageName: node linkType: hard +"array-flatten@npm:1.1.1": + version: 1.1.1 + resolution: "array-flatten@npm:1.1.1" + checksum: 10c0/806966c8abb2f858b08f5324d9d18d7737480610f3bd5d3498aaae6eb5efdc501a884ba019c9b4a8f02ff67002058749d05548fd42fa8643f02c9c7f22198b91 + languageName: node + linkType: hard + "array-ify@npm:^1.0.0": version: 1.0.0 resolution: "array-ify@npm:1.0.0" @@ -4413,7 +4739,7 @@ __metadata: languageName: node linkType: hard -"async@npm:^3.2.3": +"async@npm:^3.2.3, async@npm:^3.2.4": version: 3.2.6 resolution: "async@npm:3.2.6" checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70 @@ -4716,7 +5042,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^1.20.3": +"body-parser@npm:1.20.3, body-parser@npm:^1.20.3": version: 1.20.3 resolution: "body-parser@npm:1.20.3" dependencies: @@ -4829,6 +5155,13 @@ __metadata: languageName: node linkType: hard +"buffer-crc32@npm:^0.2.1, buffer-crc32@npm:^0.2.13": + version: 0.2.13 + resolution: "buffer-crc32@npm:0.2.13" + checksum: 10c0/cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150 + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -5084,6 +5417,15 @@ __metadata: languageName: node linkType: hard +"clap@npm:^3.1.1": + version: 3.1.1 + resolution: "clap@npm:3.1.1" + dependencies: + ansi-colors: "npm:^4.1.1" + checksum: 10c0/c89b15e105b67a765f8eedcfceb7a2ef9126b74264ee7f121aeaaaeaa6f470dcfef44906dcd8f34bbcb40ace40b15fc13aadf33b9dbb683e11e93cd02eabab9b + languageName: node + linkType: hard + "clean-stack@npm:^3.0.1": version: 3.0.1 resolution: "clean-stack@npm:3.0.1" @@ -5156,6 +5498,13 @@ __metadata: languageName: node linkType: hard +"codemirror@npm:^5.65.2": + version: 5.65.20 + resolution: "codemirror@npm:5.65.20" + checksum: 10c0/a1efc27d6c550f65b8ebe9c4229b7c4bb99e3856595779573597773f72aa576750f67765a598cb881d9238128d7b43be287f26e8a83bb2d42c2b2f0c0decb190 + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -5269,6 +5618,18 @@ __metadata: languageName: node linkType: hard +"compress-commons@npm:^4.1.2": + version: 4.1.2 + resolution: "compress-commons@npm:4.1.2" + dependencies: + buffer-crc32: "npm:^0.2.13" + crc32-stream: "npm:^4.0.2" + normalize-path: "npm:^3.0.0" + readable-stream: "npm:^3.6.0" + checksum: 10c0/e5fa03cb374ed89028e20226c70481e87286240392d5c6856f4e7fef40605c1892748648e20ed56597d390d76513b1b9bb4dbd658a1bbff41c9fa60107c74d3f + languageName: node + linkType: hard + "compressible@npm:~2.0.18": version: 2.0.18 resolution: "compressible@npm:2.0.18" @@ -5319,6 +5680,15 @@ __metadata: languageName: node linkType: hard +"content-disposition@npm:0.5.4": + version: 0.5.4 + resolution: "content-disposition@npm:0.5.4" + dependencies: + safe-buffer: "npm:5.2.1" + checksum: 10c0/bac0316ebfeacb8f381b38285dc691c9939bf0a78b0b7c2d5758acadad242d04783cee5337ba7d12a565a19075af1b3c11c728e1e4946de73c6ff7ce45f3f1bb + languageName: node + linkType: hard + "content-disposition@npm:^1.0.0": version: 1.0.0 resolution: "content-disposition@npm:1.0.0" @@ -5328,7 +5698,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.5, content-type@npm:~1.0.5": +"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af @@ -5374,6 +5744,13 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:1.0.6": + version: 1.0.6 + resolution: "cookie-signature@npm:1.0.6" + checksum: 10c0/b36fd0d4e3fef8456915fcf7742e58fbfcc12a17a018e0eb9501c9d5ef6893b596466f03b0564b81af29ff2538fd0aa4b9d54fe5ccbfb4c90ea50ad29fe2d221 + languageName: node + linkType: hard + "cookie-signature@npm:^1.2.1": version: 1.2.2 resolution: "cookie-signature@npm:1.2.2" @@ -5381,6 +5758,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:0.7.1": + version: 0.7.1 + resolution: "cookie@npm:0.7.1" + checksum: 10c0/5de60c67a410e7c8dc8a46a4b72eb0fe925871d057c9a5d2c0e8145c4270a4f81076de83410c4d397179744b478e33cd80ccbcc457abf40a9409ad27dcd21dde + languageName: node + linkType: hard + "cookie@npm:^0.7.1": version: 0.7.2 resolution: "cookie@npm:0.7.2" @@ -5397,6 +5781,23 @@ __metadata: languageName: node linkType: hard +"core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 + languageName: node + linkType: hard + +"cors@npm:^2.8.5": + version: 2.8.5 + resolution: "cors@npm:2.8.5" + dependencies: + object-assign: "npm:^4" + vary: "npm:^1" + checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 + languageName: node + linkType: hard + "cosmiconfig-typescript-loader@npm:^6.1.0": version: 6.1.0 resolution: "cosmiconfig-typescript-loader@npm:6.1.0" @@ -5456,6 +5857,50 @@ __metadata: languageName: node linkType: hard +"crc-32@npm:^1.2.0": + version: 1.2.2 + resolution: "crc-32@npm:1.2.2" + bin: + crc32: bin/crc32.njs + checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0 + languageName: node + linkType: hard + +"crc32-stream@npm:^4.0.2": + version: 4.0.3 + resolution: "crc32-stream@npm:4.0.3" + dependencies: + crc-32: "npm:^1.2.0" + readable-stream: "npm:^3.4.0" + checksum: 10c0/127b0c66a947c54db37054fca86085722140644d3a75ebc61d4477bad19304d2936386b0461e8ee9e1c24b00e804cd7c2e205180e5bcb4632d20eccd60533bc4 + languageName: node + linkType: hard + +"cron-parser@npm:^4.9.0": + version: 4.9.0 + resolution: "cron-parser@npm:4.9.0" + dependencies: + luxon: "npm:^3.2.1" + checksum: 10c0/348622bdcd1a15695b61fc33af8a60133e5913a85cf99f6344367579e7002896514ba3b0a9d6bb569b02667d6b06836722bf2295fcd101b3de378f71d37bed0b + languageName: node + linkType: hard + +"cron-validator@npm:^1.3.1": + version: 1.4.0 + resolution: "cron-validator@npm:1.4.0" + checksum: 10c0/fc81eb2dfdcce0c2e9b8ac44eae5c70ca439eb256d860d10849dfbcebc35e6c7746649a20e86e9a9156569e31d39717d7fc35341bd3fb81bbec9199b885ef945 + languageName: node + linkType: hard + +"cronstrue@npm:^2.51.0": + version: 2.59.0 + resolution: "cronstrue@npm:2.59.0" + bin: + cronstrue: bin/cli.js + checksum: 10c0/f04c9720eacae8cc58ee700a33ced44947c7d722f9deb8a0d0a9a9b533f493b8c2fabed0e72e6bf9d6d1e5191b7b8325e107496ed93a85a2789e57954084b055 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -6113,6 +6558,95 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.25.1": + version: 0.25.10 + resolution: "esbuild@npm:0.25.10" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.10" + "@esbuild/android-arm": "npm:0.25.10" + "@esbuild/android-arm64": "npm:0.25.10" + "@esbuild/android-x64": "npm:0.25.10" + "@esbuild/darwin-arm64": "npm:0.25.10" + "@esbuild/darwin-x64": "npm:0.25.10" + "@esbuild/freebsd-arm64": "npm:0.25.10" + "@esbuild/freebsd-x64": "npm:0.25.10" + "@esbuild/linux-arm": "npm:0.25.10" + "@esbuild/linux-arm64": "npm:0.25.10" + "@esbuild/linux-ia32": "npm:0.25.10" + "@esbuild/linux-loong64": "npm:0.25.10" + "@esbuild/linux-mips64el": "npm:0.25.10" + "@esbuild/linux-ppc64": "npm:0.25.10" + "@esbuild/linux-riscv64": "npm:0.25.10" + "@esbuild/linux-s390x": "npm:0.25.10" + "@esbuild/linux-x64": "npm:0.25.10" + "@esbuild/netbsd-arm64": "npm:0.25.10" + "@esbuild/netbsd-x64": "npm:0.25.10" + "@esbuild/openbsd-arm64": "npm:0.25.10" + "@esbuild/openbsd-x64": "npm:0.25.10" + "@esbuild/openharmony-arm64": "npm:0.25.10" + "@esbuild/sunos-x64": "npm:0.25.10" + "@esbuild/win32-arm64": "npm:0.25.10" + "@esbuild/win32-ia32": "npm:0.25.10" + "@esbuild/win32-x64": "npm:0.25.10" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/8ee5fdd43ed0d4092ce7f41577c63147f54049d5617763f0549c638bbe939e8adaa8f1a2728adb63417eb11df51956b7b0d8eb88ee08c27ad1d42960256158fa + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -6685,6 +7219,45 @@ __metadata: languageName: node linkType: hard +"express@npm:^4.21.1": + version: 4.21.2 + resolution: "express@npm:4.21.2" + dependencies: + accepts: "npm:~1.3.8" + array-flatten: "npm:1.1.1" + body-parser: "npm:1.20.3" + content-disposition: "npm:0.5.4" + content-type: "npm:~1.0.4" + cookie: "npm:0.7.1" + cookie-signature: "npm:1.0.6" + debug: "npm:2.6.9" + depd: "npm:2.0.0" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + etag: "npm:~1.8.1" + finalhandler: "npm:1.3.1" + fresh: "npm:0.5.2" + http-errors: "npm:2.0.0" + merge-descriptors: "npm:1.0.3" + methods: "npm:~1.1.2" + on-finished: "npm:2.4.1" + parseurl: "npm:~1.3.3" + path-to-regexp: "npm:0.1.12" + proxy-addr: "npm:~2.0.7" + qs: "npm:6.13.0" + range-parser: "npm:~1.2.1" + safe-buffer: "npm:5.2.1" + send: "npm:0.19.0" + serve-static: "npm:1.16.2" + setprototypeof: "npm:1.2.0" + statuses: "npm:2.0.1" + type-is: "npm:~1.6.18" + utils-merge: "npm:1.0.1" + vary: "npm:~1.1.2" + checksum: 10c0/38168fd0a32756600b56e6214afecf4fc79ec28eca7f7a91c2ab8d50df4f47562ca3f9dee412da7f5cea6b1a1544b33b40f9f8586dbacfbdada0fe90dbb10a1f + languageName: node + linkType: hard + "express@npm:^5.1.0": version: 5.1.0 resolution: "express@npm:5.1.0" @@ -6873,6 +7446,21 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:1.3.1": + version: 1.3.1 + resolution: "finalhandler@npm:1.3.1" + dependencies: + debug: "npm:2.6.9" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + on-finished: "npm:2.4.1" + parseurl: "npm:~1.3.3" + statuses: "npm:2.0.1" + unpipe: "npm:~1.0.0" + checksum: 10c0/d38035831865a49b5610206a3a9a9aae4e8523cbbcd01175d0480ffbf1278c47f11d89be3ca7f617ae6d94f29cf797546a4619cd84dd109009ef33f12f69019f + languageName: node + linkType: hard + "finalhandler@npm:^2.1.0": version: 2.1.0 resolution: "finalhandler@npm:2.1.0" @@ -7249,6 +7837,13 @@ __metadata: languageName: node linkType: hard +"github-slugger@npm:^2.0.0": + version: 2.0.0 + resolution: "github-slugger@npm:2.0.0" + checksum: 10c0/21b912b6b1e48f1e5a50b2292b48df0ff6abeeb0691b161b3d93d84f4ae6b1acd6ae23702e914af7ea5d441c096453cf0f621b72d57893946618d21dd1a1c486 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -7283,7 +7878,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4": +"glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.2.3": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -7504,6 +8099,22 @@ __metadata: languageName: node linkType: hard +"highcharts@npm:12.2.0": + version: 12.2.0 + resolution: "highcharts@npm:12.2.0" + checksum: 10c0/fb482ef75fda50c30d115f394c534108ea40540bd405dd72f14ddc28ae72b7c3ac924da06fe84d25c215564a9e451043dfe4ac5b44416df635a90b09ee528b43 + languageName: node + linkType: hard + +"hitext@npm:^1.0.0-beta.1": + version: 1.0.0-beta.1 + resolution: "hitext@npm:1.0.0-beta.1" + dependencies: + ansi-styles: "npm:^3.2.1" + checksum: 10c0/a7cff0aa5da17ebc55af1a2de9b5017fb026e13b125685bd84fc82a1d522f7c061efacaab95c83561c846147da5c2871815292422ca9bb4976b4c483f1fbca3e + languageName: node + linkType: hard + "hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" @@ -8130,6 +8741,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -8346,6 +8964,15 @@ __metadata: languageName: node linkType: hard +"jora@npm:1.0.0-beta.13": + version: 1.0.0-beta.13 + resolution: "jora@npm:1.0.0-beta.13" + dependencies: + "@discoveryjs/natural-compare": "npm:^1.1.0" + checksum: 10c0/81936dde230176871a707b10ec9bcaea99866a9ef224d9967b25492756a52f6c62a0cdc6fd1a8541689cdb546ba24ab48d229462a9ebe9846e82921c6b816a31 + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -8556,6 +9183,15 @@ __metadata: languageName: node linkType: hard +"lazystream@npm:^1.0.0": + version: 1.0.1 + resolution: "lazystream@npm:1.0.1" + dependencies: + readable-stream: "npm:^2.0.5" + checksum: 10c0/ea4e509a5226ecfcc303ba6782cc269be8867d372b9bcbd625c88955df1987ea1a20da4643bf9270336415a398d33531ebf0d5f0d393b9283dc7c98bfcbd7b69 + languageName: node + linkType: hard + "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -8648,6 +9284,27 @@ __metadata: languageName: node linkType: hard +"lodash.defaults@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.defaults@npm:4.2.0" + checksum: 10c0/d5b77aeb702caa69b17be1358faece33a84497bcca814897383c58b28a2f8dfc381b1d9edbec239f8b425126a3bbe4916223da2a576bb0411c2cefd67df80707 + languageName: node + linkType: hard + +"lodash.difference@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.difference@npm:4.5.0" + checksum: 10c0/5d52859218a7df427547ff1fadbc397879709fe6c788b037df7d6d92b676122c92bd35ec85d364edb596b65dfc6573132f420c9b4ee22bb6b9600cd454c90637 + languageName: node + linkType: hard + +"lodash.flatten@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.flatten@npm:4.4.0" + checksum: 10c0/97e8f0d6b61fe4723c02ad0c6e67e51784c4a2c48f56ef283483e556ad01594cf9cec9c773e177bbbdbdb5d19e99b09d2487cb6b6e5dc405c2693e93b125bd3a + languageName: node + linkType: hard + "lodash.isplainobject@npm:^4.0.6": version: 4.0.6 resolution: "lodash.isplainobject@npm:4.0.6" @@ -8697,6 +9354,13 @@ __metadata: languageName: node linkType: hard +"lodash.union@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.union@npm:4.6.0" + checksum: 10c0/6da7f72d1facd472f6090b49eefff984c9f9179e13172039c0debca6851d21d37d83c7ad5c43af23bd220f184cd80e6897e8e3206509fae491f9068b02ae6319 + languageName: node + linkType: hard + "lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" @@ -8777,6 +9441,13 @@ __metadata: languageName: node linkType: hard +"luxon@npm:^3.2.1": + version: 3.7.2 + resolution: "luxon@npm:3.7.2" + checksum: 10c0/ed8f0f637826c08c343a29dd478b00628be93bba6f068417b1d8896b61cb61c6deacbe1df1e057dbd9298334044afa150f9aaabbeb3181418ac8520acfdc2ae2 + languageName: node + linkType: hard + "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" @@ -8805,6 +9476,15 @@ __metadata: languageName: node linkType: hard +"marked@npm:^14.1.4": + version: 14.1.4 + resolution: "marked@npm:14.1.4" + bin: + marked: bin/marked.js + checksum: 10c0/7ccc4c9b58d430b68eb878133fc284235ef3022b1a465345d2464712bf7d47507203b54639826839b6cb8d8847cf46f2e382588b9e1fc1d98b657520e16bfa62 + languageName: node + linkType: hard + "marky@npm:^1.2.2": version: 1.2.5 resolution: "marky@npm:1.2.5" @@ -8868,6 +9548,13 @@ __metadata: languageName: node linkType: hard +"merge-descriptors@npm:1.0.3": + version: 1.0.3 + resolution: "merge-descriptors@npm:1.0.3" + checksum: 10c0/866b7094afd9293b5ea5dcd82d71f80e51514bed33b4c4e9f516795dc366612a4cbb4dc94356e943a8a6914889a914530badff27f397191b9b75cda20b6bae93 + languageName: node + linkType: hard + "merge-descriptors@npm:^2.0.0": version: 2.0.0 resolution: "merge-descriptors@npm:2.0.0" @@ -8889,6 +9576,13 @@ __metadata: languageName: node linkType: hard +"methods@npm:~1.1.2": + version: 1.1.2 + resolution: "methods@npm:1.1.2" + checksum: 10c0/bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 + languageName: node + linkType: hard + "metro-babel-transformer@npm:0.82.5": version: 0.82.5 resolution: "metro-babel-transformer@npm:0.82.5" @@ -9240,6 +9934,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^3.0.0": + version: 3.0.0 + resolution: "mime@npm:3.0.0" + bin: + mime: cli.js + checksum: 10c0/402e792a8df1b2cc41cb77f0dcc46472b7944b7ec29cb5bbcd398624b6b97096728f1239766d3fdeb20551dd8d94738344c195a6ea10c4f906eb0356323b0531 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -9263,7 +9966,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^5.0.1": +"minimatch@npm:^5.0.1, minimatch@npm:^5.1.0": version: 5.1.6 resolution: "minimatch@npm:5.1.6" dependencies: @@ -9445,7 +10148,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:3.3.8, nanoid@npm:^3.3.1": +"nanoid@npm:3.3.8": version: 3.3.8 resolution: "nanoid@npm:3.3.8" bin: @@ -9627,7 +10330,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.1.1": +"object-assign@npm:^4, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 @@ -9952,6 +10655,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^2.1.0": + version: 2.1.0 + resolution: "parse-ms@npm:2.1.0" + checksum: 10c0/9c5c0a95c6267c84085685556a6e102ee806c3147ec11cbb9b98e35998eb4a48a757bd6ea7bfd930062de65909a33d24985055b4394e70aa0b65ee40cef16911 + languageName: node + linkType: hard + "parseurl@npm:^1.3.3, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -10018,6 +10728,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:0.1.12": + version: 0.1.12 + resolution: "path-to-regexp@npm:0.1.12" + checksum: 10c0/1c6ff10ca169b773f3bba943bbc6a07182e332464704572962d277b900aeee81ac6aa5d060ff9e01149636c30b1f63af6e69dd7786ba6e0ddb39d4dee1f0645b + languageName: node + linkType: hard + "path-to-regexp@npm:^8.0.0": version: 8.3.0 resolution: "path-to-regexp@npm:8.3.0" @@ -10157,6 +10874,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.5.3": + version: 3.6.2 + resolution: "prettier@npm:3.6.2" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/488cb2f2b99ec13da1e50074912870217c11edaddedeadc649b1244c749d15ba94e846423d062e2c4c9ae683e2d65f754de28889ba06e697ac4f988d44f45812 + languageName: node + linkType: hard + "pretty-format@npm:^26.6.2": version: 26.6.2 resolution: "pretty-format@npm:26.6.2" @@ -10180,6 +10906,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^7.0.0": + version: 7.0.1 + resolution: "pretty-ms@npm:7.0.1" + dependencies: + parse-ms: "npm:^2.1.0" + checksum: 10c0/069aec9d939e7903846b3db53b020bed92e3dc5909e0fef09ec8ab104a0b7f9a846605a1633c60af900d288582fb333f6f30469e59d6487a2330301fad35a89c + languageName: node + linkType: hard + "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -10187,6 +10922,13 @@ __metadata: languageName: node linkType: hard +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 + languageName: node + linkType: hard + "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -10227,7 +10969,7 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:^2.0.7": +"proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" dependencies: @@ -10437,6 +11179,38 @@ __metadata: languageName: node linkType: hard +"react-native-bundle-discovery-rozenite-plugin@npm:^1.0.0": + version: 1.0.0 + resolution: "react-native-bundle-discovery-rozenite-plugin@npm:1.0.0" + dependencies: + "@discoveryjs/cli": "npm:2.14.2" + react-native-bundle-discovery: "npm:*" + checksum: 10c0/7c0950390df6f6da717e4f7ea188904ea7a17b9086e6e6e397b8ba5e7ad313f8465f54c3079e0c3b36930613fe2b6f452339da68215bbec3daf483abeac58385 + languageName: node + linkType: hard + +"react-native-bundle-discovery@npm:*, react-native-bundle-discovery@npm:^1.2.1": + version: 1.2.1 + resolution: "react-native-bundle-discovery@npm:1.2.1" + dependencies: + "@babel/parser": "npm:^7.0.0" + "@discoveryjs/cli": "npm:2.14.2" + "@discoveryjs/discovery": "npm:1.0.0-beta.93" + chalk: "npm:^4.1.2" + highcharts: "npm:12.2.0" + prettier: "npm:^3.5.3" + yargs: "npm:^17.7.2" + peerDependencies: + metro: "*" + peerDependenciesMeta: + metro: + optional: true + bin: + react-native-bundle-discovery: lib/bin.js + checksum: 10c0/6bb5b7ac792af04d9762671737cc2afb068c6bf789116cc03e0b7823230018ec4d17ccdbed6106a6b39f8f7ee8f2387525b5aeee8a5960e2b64df545442d631b + languageName: node + linkType: hard + "react-native-config@npm:1.5.5": version: 1.5.5 resolution: "react-native-config@npm:1.5.5" @@ -10637,6 +11411,17 @@ __metadata: languageName: node linkType: hard +"react-native-teleport@npm:^0.3.0": + version: 0.3.0 + resolution: "react-native-teleport@npm:0.3.0" + peerDependencies: + react: "*" + react-dom: "*" + react-native: "*" + checksum: 10c0/3d4ad82e823178831881c1d47db6518ed935dff93256fb33b2972e5a51cc8073cce925c20796e3f8be0972749b46540120f9ff052865810440795806a5406ef5 + languageName: node + linkType: hard + "react-native-unistyles@npm:3.0.10": version: 3.0.10 resolution: "react-native-unistyles@npm:3.0.10" @@ -10753,7 +11538,22 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.5": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: "npm:~1.0.0" + inherits: "npm:~2.0.3" + isarray: "npm:~1.0.0" + process-nextick-args: "npm:~2.0.0" + safe-buffer: "npm:~5.1.1" + string_decoder: "npm:~1.1.1" + util-deprecate: "npm:~1.0.1" + checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -10764,6 +11564,15 @@ __metadata: languageName: node linkType: hard +"readdir-glob@npm:^1.1.2": + version: 1.1.3 + resolution: "readdir-glob@npm:1.1.3" + dependencies: + minimatch: "npm:^5.1.0" + checksum: 10c0/a37e0716726650845d761f1041387acd93aa91b28dd5381950733f994b6c349ddc1e21e266ec7cc1f9b92e205a7a972232f9b89d5424d07361c2c3753d5dbace + languageName: node + linkType: hard + "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -11086,6 +11895,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + "safe-push-apply@npm:^1.0.0": version: 1.0.0 resolution: "safe-push-apply@npm:1.0.0" @@ -11202,7 +12018,7 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:^1.13.1, serve-static@npm:^1.16.2": +"serve-static@npm:1.16.2, serve-static@npm:^1.13.1, serve-static@npm:^1.16.2": version: 1.16.2 resolution: "serve-static@npm:1.16.2" dependencies: @@ -11758,6 +12574,15 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: "npm:~5.1.0" + checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -11941,7 +12766,7 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^2.1.4": +"tar-stream@npm:^2.1.4, tar-stream@npm:^2.2.0": version: 2.2.0 resolution: "tar-stream@npm:2.2.0" dependencies: @@ -12499,7 +13324,7 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1": +"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 @@ -12522,7 +13347,7 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1.1.2, vary@npm:~1.1.2": +"vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f @@ -12931,7 +13756,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.0, yargs@npm:^17.6.2": +"yargs@npm:^17.0.0, yargs@npm:^17.6.2, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -12960,6 +13785,17 @@ __metadata: languageName: node linkType: hard +"zip-stream@npm:^4.1.0": + version: 4.1.1 + resolution: "zip-stream@npm:4.1.1" + dependencies: + archiver-utils: "npm:^3.0.4" + compress-commons: "npm:^4.1.2" + readable-stream: "npm:^3.6.0" + checksum: 10c0/38f91ca116a38561cf184c29e035e9453b12c30eaf574e0993107a4a5331882b58c9a7f7b97f63910664028089fbde3296d0b3682d1ccb2ad96929e68f1b2b89 + languageName: node + linkType: hard + "zod@npm:3.24.4": version: 3.24.4 resolution: "zod@npm:3.24.4"