@greatapps/common 1.1.803 → 1.1.805

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/infra/api/client.mjs +3 -3
  2. package/dist/infra/api/client.mjs.map +1 -1
  3. package/dist/modules/accounts/services/account.service.mjs +13 -8
  4. package/dist/modules/accounts/services/account.service.mjs.map +1 -1
  5. package/dist/modules/accounts/services/two-factor.service.mjs +3 -3
  6. package/dist/modules/accounts/services/two-factor.service.mjs.map +1 -1
  7. package/dist/modules/users/schema.mjs.map +1 -1
  8. package/dist/modules/users/services/user.service.mjs +4 -3
  9. package/dist/modules/users/services/user.service.mjs.map +1 -1
  10. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs +2 -14
  11. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
  12. package/dist/modules/whitelabel/actions/revalidate-whitelabel.action.mjs +1 -2
  13. package/dist/modules/whitelabel/actions/revalidate-whitelabel.action.mjs.map +1 -1
  14. package/dist/modules/whitelabel/utils/find-whitelabel-token.mjs +10 -0
  15. package/dist/modules/whitelabel/utils/find-whitelabel-token.mjs.map +1 -0
  16. package/dist/modules/whitelabel/utils/resolve-whitelabel-for-host.mjs +20 -0
  17. package/dist/modules/whitelabel/utils/resolve-whitelabel-for-host.mjs.map +1 -0
  18. package/dist/providers/query.provider.mjs +1 -1
  19. package/dist/providers/query.provider.mjs.map +1 -1
  20. package/dist/server.mjs +2 -0
  21. package/dist/server.mjs.map +1 -1
  22. package/package.json +1 -1
  23. package/src/infra/api/client.ts +6 -6
  24. package/src/modules/accounts/services/account.service.ts +16 -8
  25. package/src/modules/accounts/services/two-factor.service.ts +3 -3
  26. package/src/modules/accounts/types.ts +1 -3
  27. package/src/modules/auth/schema.ts +0 -1
  28. package/src/modules/users/schema.ts +1 -1
  29. package/src/modules/users/services/user.service.ts +5 -3
  30. package/src/modules/whitelabel/actions/find-whitelabel.action.ts +2 -18
  31. package/src/modules/whitelabel/actions/revalidate-whitelabel.action.ts +1 -2
  32. package/src/modules/whitelabel/schema.ts +0 -1
  33. package/src/modules/whitelabel/utils/find-whitelabel-token.ts +14 -0
  34. package/src/modules/whitelabel/utils/resolve-whitelabel-for-host.ts +27 -0
  35. package/src/providers/query.provider.tsx +1 -1
  36. package/src/server.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import { headers as nextHeaders } from "next/headers";
2
2
  import { ApiError } from "./types";
3
- import { findWhitelabel } from "../../modules/whitelabel/actions/find-whitelabel.action";
3
+ import { findWhitelabelToken } from "../../modules/whitelabel/utils/find-whitelabel-token";
4
4
  const TRACE_HEADERS = ["sentry-trace", "baggage"];
5
5
  class ApiClient {
6
6
  baseUrl;
@@ -63,7 +63,7 @@ class ApiClient {
63
63
  if (this.emitLogs) {
64
64
  console.log("[ApiClient] Building URL and headers...");
65
65
  }
66
- const { id, token } = await findWhitelabel();
66
+ const { id, token } = await findWhitelabelToken();
67
67
  const [url, defaultHeaders] = await Promise.all([
68
68
  this.buildUrl(endpoint, overrideWlId ?? id),
69
69
  this.getDefaultHeaders(overrideToken ?? token, fetchConfig.body instanceof FormData)
@@ -189,7 +189,7 @@ class ApiClient {
189
189
  */
190
190
  async stream(endpoint, config = {}) {
191
191
  const { timeout: _timeout, responseType: _responseType, whiteLabelId: overrideWlId, authToken: overrideToken, ...fetchConfig } = config;
192
- const resolvido = overrideWlId != null && overrideToken != null ? { id: overrideWlId, token: overrideToken } : await findWhitelabel();
192
+ const resolvido = overrideWlId != null && overrideToken != null ? { id: overrideWlId, token: overrideToken } : await findWhitelabelToken();
193
193
  const [url, defaultHeaders] = await Promise.all([
194
194
  this.buildUrl(endpoint, overrideWlId ?? resolvido.id),
195
195
  this.getDefaultHeaders(overrideToken ?? resolvido.token)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/infra/api/client.ts"],"sourcesContent":["import { headers as nextHeaders } from \"next/headers\";\n\nimport { ApiError } from \"./types\";\nimport { findWhitelabel } from \"../../modules/whitelabel/actions/find-whitelabel.action\";\n\n/**\n * Headers de tracing distribuído do Sentry, repassados da requisição que chegou neste worker\n * para a chamada de saída à r3-api.\n *\n * ⚠️ POR QUE PRECISA SER EXPLÍCITO. O browser já gera o trace e já manda `sentry-trace`/`baggage`\n * para o worker Next (same-origin, o browser SDK anexa sozinho). O que quebra é o SEGUNDO hop:\n * este `ApiClient` montava `{ authorization, Content-Type }` do zero e descartava o contexto, e\n * `@sentry/nextjs` rodando em workerd não instrumenta fetch de saída (a auto-instrumentação de\n * `undici` é do runtime Node e não tem onde se enganchar aqui). Sem estas duas linhas, um incidente\n * não se segue do browser até o backend: são dois traces sem ligação nenhuma.\n *\n * Do lado da r3-api os campos entram no log estruturado como `trace_id`/`parent_span_id`\n * (ver `docs/logs-estruturados.md` lá), então o MESMO id aparece no Sentry do front e no Workers\n * Logs do backend — uma busca resolve os dois.\n */\nconst TRACE_HEADERS = [\"sentry-trace\", \"baggage\"] as const;\n\nexport interface ApiClientOptions {\n /**\n * Quando true, monta `{base}/{locale}/{wlId}{endpoint}` (ex.: r2-clone).\n * Padrão false: `{base}/v1/{locale}/{wlId}{endpoint}`.\n */\n omitApiVersion?: boolean;\n\n /** Habilita logs detalhados das requisições (útil para desenvolvimento) */\n emitLogs?: boolean;\n}\n\ninterface ApiErrorResponseBody {\n message?: string | { message?: string };\n code?: string;\n}\n\nexport interface RequestConfig extends RequestInit {\n timeout?: number;\n /** Padrão `json`. Use `text` quando a API devolve corpo não-JSON. */\n responseType?: \"json\" | \"text\";\n /** Força um whiteLabelId específico na URL, ignorando o findWhitelabel(). */\n whiteLabelId?: number;\n /** Força um token específico no header Authorization, ignorando o findWhitelabel(). */\n authToken?: string;\n}\n\nclass ApiClient {\n private readonly baseUrl: string;\n private readonly apiVersion = \"v1\";\n private readonly apiLocale = \"pt-br\";\n private readonly omitApiVersion: boolean;\n private readonly emitLogs: boolean = false;\n\n constructor(baseUrl: string, options?: ApiClientOptions) {\n this.baseUrl = baseUrl.replace(/\\/$/, \"\");\n this.omitApiVersion = options?.omitApiVersion ?? false;\n this.emitLogs = options?.emitLogs ?? false;\n }\n\n private async buildUrl(\n endpoint: string,\n whiteLabelId: number,\n ): Promise<string> {\n const wlPath = this.omitApiVersion\n ? `/${this.apiLocale}/${whiteLabelId}`\n : `/${this.apiVersion}/${this.apiLocale}/${whiteLabelId}`;\n const path = endpoint.startsWith(\"/\") ? endpoint : `/${endpoint}`;\n const url = `${this.baseUrl}${wlPath}${path}`;\n if (this.emitLogs) {\n console.log(\"[ApiClient] buildUrl\", {\n baseURL: this.baseUrl,\n whiteLabelId,\n endpoint,\n fullUrl: url,\n });\n }\n return url;\n }\n\n private async getDefaultHeaders(\n token: string,\n isFormData = false,\n ): Promise<HeadersInit> {\n if (this.emitLogs) {\n console.log(\"[ApiClient] getDefaultHeaders\", {\n token: token.substring(0, 20) + \"...\",\n });\n }\n\n const headers: HeadersInit = {\n authorization: token,\n };\n\n if (!isFormData) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n /**\n * Repassa o tracing quando existe. Sem mecanismo novo: `request()` já aguarda\n * `findWhitelabel()`, que já é um `'use server'` lendo `next/headers` — é a mesma chamada, no\n * mesmo ponto do fluxo. Fica aqui dentro de propósito: os dois call sites de\n * `getDefaultHeaders` passam a propagar sem precisar lembrar disso em cada um.\n *\n * Silencioso por design: fora de um contexto de requisição (build, script, job) `headers()`\n * lança, e uma chamada de API não pode falhar por causa de observabilidade. Sem os headers, a\n * r3-api simplesmente gera o próprio `request_id` e a linha continua correlacionável — só não\n * se liga ao front.\n */\n try {\n const entrada = await nextHeaders();\n\n for (const nome of TRACE_HEADERS) {\n const valor = entrada.get(nome);\n if (valor) headers[nome] = valor;\n }\n } catch {\n /* sem contexto de requisição — segue sem tracing */\n }\n\n return headers;\n }\n\n async request<T>(endpoint: string, config: RequestConfig = {}): Promise<T> {\n if (this.emitLogs) {\n console.log(\"[ApiClient] request called\", {\n endpoint,\n method: config.method,\n });\n }\n\n const { timeout = 30000, responseType = \"json\", whiteLabelId: overrideWlId, authToken: overrideToken, ...fetchConfig } = config;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n if (this.emitLogs) {\n console.log(\"[ApiClient] Building URL and headers...\");\n }\n\n const { id, token } = await findWhitelabel();\n\n const [url, defaultHeaders] = await Promise.all([\n this.buildUrl(endpoint, overrideWlId ?? id),\n this.getDefaultHeaders(overrideToken ?? token, fetchConfig.body instanceof FormData),\n ]);\n\n if (this.emitLogs)\n console.log(\"[ApiClient] Fetching\", {\n url,\n method: fetchConfig.method,\n headers: defaultHeaders,\n });\n\n const response = await fetch(url, {\n ...fetchConfig,\n headers: {\n ...defaultHeaders,\n ...fetchConfig.headers,\n },\n signal: controller.signal,\n });\n\n if (this.emitLogs)\n console.log(\"[ApiClient] Response received\", {\n status: response.status,\n ok: response.ok,\n });\n\n if (!response.ok) {\n const errBody = await response.text();\n let message = `HTTP error ${response.status} ${response.statusText} ${errBody}`;\n let code = \"HTTP_ERROR\";\n try {\n const errorData: ApiErrorResponseBody = JSON.parse(errBody);\n if (typeof errorData.message === \"string\") {\n message = errorData.message;\n } else if (errorData.message?.message) {\n message = errorData.message.message;\n }\n if (typeof errorData.code === \"string\") code = errorData.code;\n } catch {\n if (errBody.trim()) message = errBody.trim();\n }\n const method = fetchConfig.method ?? \"GET\";\n let bodyPreview: unknown;\n if (method !== \"GET\" && fetchConfig.body != null) {\n if (typeof fetchConfig.body === \"string\") {\n try {\n bodyPreview = JSON.parse(fetchConfig.body);\n } catch {\n bodyPreview = fetchConfig.body;\n }\n } else if (fetchConfig.body instanceof FormData) {\n bodyPreview = \"[FormData]\";\n } else {\n bodyPreview = fetchConfig.body;\n }\n }\n console.error(\"[ApiClient] Request failed\", {\n from: url,\n method,\n ...(bodyPreview !== undefined ? { body: bodyPreview } : {}),\n status: response.status,\n message,\n });\n throw new ApiError(message, code, response.status);\n }\n\n if (responseType === \"text\") {\n return (await response.text()) as T;\n }\n\n const data = (await response.json()) as T;\n if (this.emitLogs)\n console.log(\"[ApiClient] Request successful\", { hasData: !!data });\n return data;\n } catch (error) {\n if (this.emitLogs) console.error(\"[ApiClient] Request error\", { error });\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new ApiError(\"Tempo de requisição excedido\", \"TIMEOUT\", 408);\n }\n throw new ApiError(error.message, \"NETWORK_ERROR\", 0);\n }\n\n throw new ApiError(\"Erro desconhecido\", \"UNKNOWN_ERROR\", 500);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async get<T>(endpoint: string, config?: RequestConfig): Promise<T> {\n return this.request<T>(endpoint, { ...config, method: \"GET\" });\n }\n\n async post<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"POST\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async put<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"PUT\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async patch<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"PATCH\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async delete<T>(endpoint: string, config?: RequestConfig): Promise<T> {\n return this.request<T>(endpoint, { ...config, method: \"DELETE\" });\n }\n\n /**\n * Requisição cuja resposta é consumida em stream: devolve a `Response` crua, sem ler o\n * corpo e sem timeout.\n *\n * `request()` não serve para isso por dois motivos. Ele faz `await response.json()`, o\n * que espera o corpo inteiro e mata o propósito do stream; e aborta em 30s, que é o\n * tempo que uma operação longa leva justamente por ser longa — gerar o link de uma\n * página com 132 imagens copia 100 MB e passa disso (ID-5112).\n *\n * O corpo é do chamador: quem recebe decide quando ler e quando cancelar.\n */\n async stream(endpoint: string, config: RequestConfig = {}): Promise<Response> {\n const { timeout: _timeout, responseType: _responseType, whiteLabelId: overrideWlId, authToken: overrideToken, ...fetchConfig } = config;\n\n // Só resolve o whitelabel quando falta algum dos dois: com ambos vindos do chamador, a\n // consulta seria uma ida à rede para descartar o resultado.\n const resolvido = overrideWlId != null && overrideToken != null\n ? { id: overrideWlId, token: overrideToken }\n : await findWhitelabel();\n\n const [url, defaultHeaders] = await Promise.all([\n this.buildUrl(endpoint, overrideWlId ?? resolvido.id),\n this.getDefaultHeaders(overrideToken ?? resolvido.token),\n ]);\n\n const response = await fetch(url, {\n ...fetchConfig,\n headers: { ...defaultHeaders, ...fetchConfig.headers },\n // Sem isto o fetch do Next segura o corpo inteiro antes de devolver, e o stream chega\n // completo de uma vez no fim: medido em 32s até o primeiro evento, contra 0,4s com\n // no-store. O progresso existiria no protocolo e não na tela.\n cache: \"no-store\",\n });\n\n if (!response.ok || !response.body) {\n const detalhe = await response.text().catch(() => \"\");\n throw new ApiError(\n detalhe.trim() || `HTTP error ${response.status} ${response.statusText}`,\n \"HTTP_ERROR\",\n response.status,\n );\n }\n\n return response;\n }\n}\n\nconst api = {\n apps: new ApiClient(\n process.env.GAPPS_R3_API_URL || \"https://r3-api.greatapps.dev.br\",\n ),\n pages: new ApiClient(\n process.env.GPAGES_R3_API_URL || \"https://r3-api.greatpages.dev.br\",\n ),\n};\n\n/** @deprecated use api.apps */\nexport const apiClient = api.apps;\n\nexport { api, ApiClient };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/infra/api/client.ts"],"sourcesContent":["import { headers as nextHeaders } from \"next/headers\";\n\nimport { ApiError } from \"./types\";\nimport { findWhitelabelToken } from \"../../modules/whitelabel/utils/find-whitelabel-token\";\n\n/**\n * Headers de tracing distribuído do Sentry, repassados da requisição que chegou neste worker\n * para a chamada de saída à r3-api.\n *\n * ⚠️ POR QUE PRECISA SER EXPLÍCITO. O browser já gera o trace e já manda `sentry-trace`/`baggage`\n * para o worker Next (same-origin, o browser SDK anexa sozinho). O que quebra é o SEGUNDO hop:\n * este `ApiClient` montava `{ authorization, Content-Type }` do zero e descartava o contexto, e\n * `@sentry/nextjs` rodando em workerd não instrumenta fetch de saída (a auto-instrumentação de\n * `undici` é do runtime Node e não tem onde se enganchar aqui). Sem estas duas linhas, um incidente\n * não se segue do browser até o backend: são dois traces sem ligação nenhuma.\n *\n * Do lado da r3-api os campos entram no log estruturado como `trace_id`/`parent_span_id`\n * (ver `docs/logs-estruturados.md` lá), então o MESMO id aparece no Sentry do front e no Workers\n * Logs do backend — uma busca resolve os dois.\n */\nconst TRACE_HEADERS = [\"sentry-trace\", \"baggage\"] as const;\n\nexport interface ApiClientOptions {\n /**\n * Quando true, monta `{base}/{locale}/{wlId}{endpoint}` (ex.: r2-clone).\n * Padrão false: `{base}/v1/{locale}/{wlId}{endpoint}`.\n */\n omitApiVersion?: boolean;\n\n /** Habilita logs detalhados das requisições (útil para desenvolvimento) */\n emitLogs?: boolean;\n}\n\ninterface ApiErrorResponseBody {\n message?: string | { message?: string };\n code?: string;\n}\n\nexport interface RequestConfig extends RequestInit {\n timeout?: number;\n /** Padrão `json`. Use `text` quando a API devolve corpo não-JSON. */\n responseType?: \"json\" | \"text\";\n /** Força um whiteLabelId específico na URL, ignorando o findWhitelabelToken(). */\n whiteLabelId?: number;\n /** Força um token específico no header Authorization, ignorando o findWhitelabelToken(). */\n authToken?: string;\n}\n\nclass ApiClient {\n private readonly baseUrl: string;\n private readonly apiVersion = \"v1\";\n private readonly apiLocale = \"pt-br\";\n private readonly omitApiVersion: boolean;\n private readonly emitLogs: boolean = false;\n\n constructor(baseUrl: string, options?: ApiClientOptions) {\n this.baseUrl = baseUrl.replace(/\\/$/, \"\");\n this.omitApiVersion = options?.omitApiVersion ?? false;\n this.emitLogs = options?.emitLogs ?? false;\n }\n\n private async buildUrl(\n endpoint: string,\n whiteLabelId: number,\n ): Promise<string> {\n const wlPath = this.omitApiVersion\n ? `/${this.apiLocale}/${whiteLabelId}`\n : `/${this.apiVersion}/${this.apiLocale}/${whiteLabelId}`;\n const path = endpoint.startsWith(\"/\") ? endpoint : `/${endpoint}`;\n const url = `${this.baseUrl}${wlPath}${path}`;\n if (this.emitLogs) {\n console.log(\"[ApiClient] buildUrl\", {\n baseURL: this.baseUrl,\n whiteLabelId,\n endpoint,\n fullUrl: url,\n });\n }\n return url;\n }\n\n private async getDefaultHeaders(\n token: string,\n isFormData = false,\n ): Promise<HeadersInit> {\n if (this.emitLogs) {\n console.log(\"[ApiClient] getDefaultHeaders\", {\n token: token.substring(0, 20) + \"...\",\n });\n }\n\n const headers: HeadersInit = {\n authorization: token,\n };\n\n if (!isFormData) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n /**\n * Repassa o tracing quando existe. Sem mecanismo novo: `request()` já aguarda\n * `findWhitelabelToken()`, que já lê `next/headers` — é a mesma chamada, no\n * mesmo ponto do fluxo. Fica aqui dentro de propósito: os dois call sites de\n * `getDefaultHeaders` passam a propagar sem precisar lembrar disso em cada um.\n *\n * Silencioso por design: fora de um contexto de requisição (build, script, job) `headers()`\n * lança, e uma chamada de API não pode falhar por causa de observabilidade. Sem os headers, a\n * r3-api simplesmente gera o próprio `request_id` e a linha continua correlacionável — só não\n * se liga ao front.\n */\n try {\n const entrada = await nextHeaders();\n\n for (const nome of TRACE_HEADERS) {\n const valor = entrada.get(nome);\n if (valor) headers[nome] = valor;\n }\n } catch {\n /* sem contexto de requisição — segue sem tracing */\n }\n\n return headers;\n }\n\n async request<T>(endpoint: string, config: RequestConfig = {}): Promise<T> {\n if (this.emitLogs) {\n console.log(\"[ApiClient] request called\", {\n endpoint,\n method: config.method,\n });\n }\n\n const { timeout = 30000, responseType = \"json\", whiteLabelId: overrideWlId, authToken: overrideToken, ...fetchConfig } = config;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n if (this.emitLogs) {\n console.log(\"[ApiClient] Building URL and headers...\");\n }\n\n const { id, token } = await findWhitelabelToken();\n\n const [url, defaultHeaders] = await Promise.all([\n this.buildUrl(endpoint, overrideWlId ?? id),\n this.getDefaultHeaders(overrideToken ?? token, fetchConfig.body instanceof FormData),\n ]);\n\n if (this.emitLogs)\n console.log(\"[ApiClient] Fetching\", {\n url,\n method: fetchConfig.method,\n headers: defaultHeaders,\n });\n\n const response = await fetch(url, {\n ...fetchConfig,\n headers: {\n ...defaultHeaders,\n ...fetchConfig.headers,\n },\n signal: controller.signal,\n });\n\n if (this.emitLogs)\n console.log(\"[ApiClient] Response received\", {\n status: response.status,\n ok: response.ok,\n });\n\n if (!response.ok) {\n const errBody = await response.text();\n let message = `HTTP error ${response.status} ${response.statusText} ${errBody}`;\n let code = \"HTTP_ERROR\";\n try {\n const errorData: ApiErrorResponseBody = JSON.parse(errBody);\n if (typeof errorData.message === \"string\") {\n message = errorData.message;\n } else if (errorData.message?.message) {\n message = errorData.message.message;\n }\n if (typeof errorData.code === \"string\") code = errorData.code;\n } catch {\n if (errBody.trim()) message = errBody.trim();\n }\n const method = fetchConfig.method ?? \"GET\";\n let bodyPreview: unknown;\n if (method !== \"GET\" && fetchConfig.body != null) {\n if (typeof fetchConfig.body === \"string\") {\n try {\n bodyPreview = JSON.parse(fetchConfig.body);\n } catch {\n bodyPreview = fetchConfig.body;\n }\n } else if (fetchConfig.body instanceof FormData) {\n bodyPreview = \"[FormData]\";\n } else {\n bodyPreview = fetchConfig.body;\n }\n }\n console.error(\"[ApiClient] Request failed\", {\n from: url,\n method,\n ...(bodyPreview !== undefined ? { body: bodyPreview } : {}),\n status: response.status,\n message,\n });\n throw new ApiError(message, code, response.status);\n }\n\n if (responseType === \"text\") {\n return (await response.text()) as T;\n }\n\n const data = (await response.json()) as T;\n if (this.emitLogs)\n console.log(\"[ApiClient] Request successful\", { hasData: !!data });\n return data;\n } catch (error) {\n if (this.emitLogs) console.error(\"[ApiClient] Request error\", { error });\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new ApiError(\"Tempo de requisição excedido\", \"TIMEOUT\", 408);\n }\n throw new ApiError(error.message, \"NETWORK_ERROR\", 0);\n }\n\n throw new ApiError(\"Erro desconhecido\", \"UNKNOWN_ERROR\", 500);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async get<T>(endpoint: string, config?: RequestConfig): Promise<T> {\n return this.request<T>(endpoint, { ...config, method: \"GET\" });\n }\n\n async post<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"POST\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async put<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"PUT\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async patch<T>(\n endpoint: string,\n data?: unknown,\n config?: RequestConfig,\n ): Promise<T> {\n return this.request<T>(endpoint, {\n ...config,\n method: \"PATCH\",\n body:\n data instanceof FormData\n ? data\n : data\n ? JSON.stringify(data)\n : undefined,\n });\n }\n\n async delete<T>(endpoint: string, config?: RequestConfig): Promise<T> {\n return this.request<T>(endpoint, { ...config, method: \"DELETE\" });\n }\n\n /**\n * Requisição cuja resposta é consumida em stream: devolve a `Response` crua, sem ler o\n * corpo e sem timeout.\n *\n * `request()` não serve para isso por dois motivos. Ele faz `await response.json()`, o\n * que espera o corpo inteiro e mata o propósito do stream; e aborta em 30s, que é o\n * tempo que uma operação longa leva justamente por ser longa — gerar o link de uma\n * página com 132 imagens copia 100 MB e passa disso (ID-5112).\n *\n * O corpo é do chamador: quem recebe decide quando ler e quando cancelar.\n */\n async stream(endpoint: string, config: RequestConfig = {}): Promise<Response> {\n const { timeout: _timeout, responseType: _responseType, whiteLabelId: overrideWlId, authToken: overrideToken, ...fetchConfig } = config;\n\n // Só resolve o whitelabel quando falta algum dos dois: com ambos vindos do chamador, a\n // consulta seria uma ida à rede para descartar o resultado.\n const resolvido = overrideWlId != null && overrideToken != null\n ? { id: overrideWlId, token: overrideToken }\n : await findWhitelabelToken();\n\n const [url, defaultHeaders] = await Promise.all([\n this.buildUrl(endpoint, overrideWlId ?? resolvido.id),\n this.getDefaultHeaders(overrideToken ?? resolvido.token),\n ]);\n\n const response = await fetch(url, {\n ...fetchConfig,\n headers: { ...defaultHeaders, ...fetchConfig.headers },\n // Sem isto o fetch do Next segura o corpo inteiro antes de devolver, e o stream chega\n // completo de uma vez no fim: medido em 32s até o primeiro evento, contra 0,4s com\n // no-store. O progresso existiria no protocolo e não na tela.\n cache: \"no-store\",\n });\n\n if (!response.ok || !response.body) {\n const detalhe = await response.text().catch(() => \"\");\n throw new ApiError(\n detalhe.trim() || `HTTP error ${response.status} ${response.statusText}`,\n \"HTTP_ERROR\",\n response.status,\n );\n }\n\n return response;\n }\n}\n\nconst api = {\n apps: new ApiClient(\n process.env.GAPPS_R3_API_URL || \"https://r3-api.greatapps.dev.br\",\n ),\n pages: new ApiClient(\n process.env.GPAGES_R3_API_URL || \"https://r3-api.greatpages.dev.br\",\n ),\n};\n\n/** @deprecated use api.apps */\nexport const apiClient = api.apps;\n\nexport { api, ApiClient };\n"],"mappings":"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","names":[]}
@@ -18,11 +18,16 @@ class AccountService {
18
18
  400
19
19
  );
20
20
  }
21
- return response.data[0];
21
+ const { user, ...account } = response.data[0];
22
+ return account;
23
+ }
24
+ pickUsersQueryParams(params = {}) {
25
+ const { page, limit, search, name, notInProject, profiles, firstId } = params;
26
+ return { page, limit, search, name, notInProject, profiles, firstId };
22
27
  }
23
28
  async listAccountUsers(params) {
24
29
  const { id_account } = await getUserContext();
25
- const queryParams = buildQueryParams(params);
30
+ const queryParams = buildQueryParams(this.pickUsersQueryParams(params));
26
31
  const endpoint = `/accounts/${id_account}/users?${queryParams}`;
27
32
  const response = await api.apps.get(endpoint);
28
33
  if (response.status === 0) {
@@ -43,7 +48,7 @@ class AccountService {
43
48
  */
44
49
  async listAccountMembers(params) {
45
50
  const { id_account, id_user } = await getUserContext();
46
- const queryParams = buildQueryParams({ ...params, scopeUserId: id_user });
51
+ const queryParams = buildQueryParams({ ...this.pickUsersQueryParams(params), scopeUserId: id_user });
47
52
  const response = await api.apps.get(
48
53
  `/accounts/${id_account}/users?${queryParams}`
49
54
  );
@@ -73,7 +78,7 @@ class AccountService {
73
78
  400
74
79
  );
75
80
  }
76
- return response;
81
+ return { status: response.status, message: response.message };
77
82
  }
78
83
  async deleteAccountUser(userId) {
79
84
  const { id_account } = await getUserContext();
@@ -83,7 +88,7 @@ class AccountService {
83
88
  if (response.status === 0) {
84
89
  throw new ApiError(response.message || "Erro ao deletar usu\xE1rio", "DELETE_USER_FAILED", 400);
85
90
  }
86
- return response;
91
+ return { status: response.status, message: response.message };
87
92
  }
88
93
  async deleteAccount(data) {
89
94
  const { id_account } = await getUserContext();
@@ -108,7 +113,7 @@ class AccountService {
108
113
  if (response.status === 0) {
109
114
  throw new ApiError(response.message || "Erro ao criar usu\xE1rio", "CREATE_USER_FAILED", 400);
110
115
  }
111
- return response;
116
+ return { status: response.status, message: response.message };
112
117
  }
113
118
  async resolvePhotoField(user) {
114
119
  if (user.photo === void 0) return {};
@@ -128,7 +133,7 @@ class AccountService {
128
133
  400
129
134
  );
130
135
  }
131
- return response;
136
+ return { status: response.status, message: response.message };
132
137
  }
133
138
  async updateAccountUserById(userId, user) {
134
139
  const { id_account } = await getUserContext();
@@ -143,7 +148,7 @@ class AccountService {
143
148
  400
144
149
  );
145
150
  }
146
- return response;
151
+ return { status: response.status, message: response.message };
147
152
  }
148
153
  async updateAccount(data) {
149
154
  const { id_account } = await getUserContext();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/accounts/services/account.service.ts"],"sourcesContent":["import 'server-only';\n\nimport { api } from '../../../infra/api/client';\nimport { ApiError } from '../../../infra/api/types';\nimport { buildQueryParams } from '../../../infra/utils/params';\nimport { assertAccountNotFrozen } from '../../auth/utils/assert-account-not-frozen';\nimport { getUserContext } from '../../auth/utils/get-user-context';\nimport { fileToBase64 } from '../../../utils/file/index';\nimport type { RequestConfig } from '../../../infra/api/client';\nimport { buildWlOverride } from '../../auth/utils/build-wl-override';\nimport type {\n Account,\n AccountUserProjectsResponse,\n AccountUsersPaginationParams,\n ChangePasswordRequest,\n ChangePasswordResponse,\n ChangeUserPhotoResponse,\n CreateAccountUserRequest,\n CreateAccountUserResponse,\n DeleteAccountRequest,\n DeleteAccountResponse,\n DeleteAccountUserResponse,\n GetAccountDataResponse,\n ListAccountUsersResponse,\n UpdateAccountRequest,\n UpdateAccountResponse,\n UpdateAccountUserRequest,\n UpdateAccountUserResponse,\n} from '../types';\n\nclass AccountService {\n async findCurrentAccount(config?: RequestConfig): Promise<Account> {\n const { id_wl, id_account } = await getUserContext();\n const effectiveConfig = config ?? await buildWlOverride(id_wl);\n const response = await api.apps.get<GetAccountDataResponse>(`/accounts/${id_account}`, effectiveConfig);\n\n if (response.status === 0 || !response.data?.[0]) {\n throw new ApiError(\n response.message || 'Erro ao buscar dados da conta',\n 'GET_ACCOUNT_FAILED',\n 400\n );\n }\n\n return response.data[0];\n }\n\n async listAccountUsers(params?: Partial<AccountUsersPaginationParams>) {\n const { id_account } = await getUserContext();\n const queryParams = buildQueryParams(params);\n const endpoint = `/accounts/${id_account}/users?${queryParams}`;\n const response = await api.apps.get<ListAccountUsersResponse>(endpoint);\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao listar usuários',\n 'LIST_ACCOUNT_USERS_FAILED',\n 400\n );\n }\n\n return {\n users: response.data || [],\n total: response.total || 0,\n };\n }\n\n /**\n * Usuários da conta com projetos (`total_projects`, `projects`), escopados ao usuário logado:\n * collaborator/viewer só veem quem divide projeto com eles.\n */\n async listAccountMembers(params?: Partial<AccountUsersPaginationParams>) {\n const { id_account, id_user } = await getUserContext();\n const queryParams = buildQueryParams({ ...params, scopeUserId: id_user });\n const response = await api.apps.get<ListAccountUsersResponse>(\n `/accounts/${id_account}/users?${queryParams}`\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao listar usuários',\n 'LIST_ACCOUNT_USERS_FAILED',\n 400\n );\n }\n\n return {\n users: response.data || [],\n total: response.total || 0,\n };\n }\n\n async changeUserPhoto(userId: number, photo: File): Promise<ChangeUserPhotoResponse> {\n const { id_account } = await getUserContext();\n const base64 = await fileToBase64(photo);\n const response = await api.apps.put<ChangeUserPhotoResponse>(\n `/accounts/${id_account}/users/${userId}/file/photo`,\n { file: base64 }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao mudar foto do usuário',\n 'CHANGE_USER_PHOTO_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async deleteAccountUser(userId: number): Promise<DeleteAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.delete<DeleteAccountUserResponse>(\n `/accounts/${id_account}/users/${userId}`\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao deletar usuário', 'DELETE_USER_FAILED', 400);\n }\n\n return response;\n }\n\n async deleteAccount(data: DeleteAccountRequest): Promise<DeleteAccountResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.delete<DeleteAccountResponse>(\n `/accounts/${id_account}`,\n { body: JSON.stringify(data) }\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao deletar conta', 'DELETE_ACCOUNT_FAILED', 400);\n }\n\n return response;\n }\n\n async createAccountUser(user: CreateAccountUserRequest): Promise<CreateAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.post<CreateAccountUserResponse>(\n `/accounts/${id_account}/users`,\n {\n ...user,\n photo: user.photo ? await fileToBase64(user.photo) : null,\n }\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao criar usuário', 'CREATE_USER_FAILED', 400);\n }\n\n return response;\n }\n\n private async resolvePhotoField(user: UpdateAccountUserRequest): Promise<{ photo?: string | null }> {\n if (user.photo === undefined) return {};\n const photo =\n user.photo != null && typeof user.photo !== 'string'\n ? await fileToBase64(user.photo)\n : user.photo;\n return { photo };\n }\n\n async updateAccountUser(user: UpdateAccountUserRequest): Promise<UpdateAccountUserResponse> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.put<UpdateAccountUserResponse>(\n `/accounts/${id_account}/users/${id_user}`,\n { ...user, ...(await this.resolvePhotoField(user)) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar usuário',\n 'UPDATE_USER_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async updateAccountUserById(\n userId: number,\n user: UpdateAccountUserRequest\n ): Promise<UpdateAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.put<UpdateAccountUserResponse>(\n `/accounts/${id_account}/users/${userId}`,\n { ...user, ...(await this.resolvePhotoField(user)) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar usuário',\n 'UPDATE_USER_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async updateAccount(data: UpdateAccountRequest): Promise<UpdateAccountResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.put<UpdateAccountResponse>(`/accounts/${id_account}`, data);\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar conta',\n 'UPDATE_ACCOUNT_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async requestContactReset(type: 'email' | 'phone', newContact: string, ddi?: string): Promise<void> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.post<{ status: number; message: string }>(\n `/accounts/${id_account}/users/${id_user}/resetContact/request`,\n { type, newContact, ...(ddi ? { ddi } : {}) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao solicitar alteração',\n 'REQUEST_CONTACT_RESET_FAILED',\n 400\n );\n }\n }\n\n async confirmContactReset(type: 'email' | 'phone', token: string, newContact: string, ddi?: string): Promise<void> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.post<{ status: number; message: string }>(\n `/accounts/${id_account}/users/${id_user}/resetContact/confirm`,\n { type, token, newContact, ...(ddi ? { ddi } : {}) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Código inválido ou expirado',\n 'CONFIRM_CONTACT_RESET_FAILED',\n 400\n );\n }\n }\n\n /** Checagem de e-mail já cadastrado, usada no cadastro de usuário antes de avançar de passo. */\n async checkUserExists(email: string): Promise<{ exists: boolean }> {\n const response = await api.apps.post<{ exist: boolean }>('/users/action/exists', { email });\n\n return { exists: response.exist };\n }\n\n async addUserProjects(userId: number, projectIds: number[]): Promise<AccountUserProjectsResponse> {\n await assertAccountNotFrozen();\n const { id_account } = await getUserContext();\n const response = await api.apps.post<AccountUserProjectsResponse>(\n `/accounts/${id_account}/users/${userId}/action/addProjectsBatch`,\n { projects: projectIds }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao vincular projetos ao usuário',\n 'ADD_USER_PROJECTS_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async removeUserProjects(userId: number, projectIds: number[]): Promise<AccountUserProjectsResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.post<AccountUserProjectsResponse>(\n `/accounts/${id_account}/users/${userId}/action/removeProjectsBatch`,\n { projects: projectIds }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao desvincular projetos do usuário',\n 'REMOVE_USER_PROJECTS_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async changePassword(data: ChangePasswordRequest): Promise<ChangePasswordResponse> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.put<ChangePasswordResponse>(\n `/accounts/${id_account}/users/${id_user}/action/changePassword`,\n data\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao alterar senha',\n 'CHANGE_PASSWORD_FAILED',\n 400\n );\n }\n\n return response;\n }\n}\n\nexport const accountService = new AccountService();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/accounts/services/account.service.ts"],"sourcesContent":["import 'server-only';\n\nimport { api } from '../../../infra/api/client';\nimport { ApiError } from '../../../infra/api/types';\nimport { buildQueryParams } from '../../../infra/utils/params';\nimport { assertAccountNotFrozen } from '../../auth/utils/assert-account-not-frozen';\nimport { getUserContext } from '../../auth/utils/get-user-context';\nimport { fileToBase64 } from '../../../utils/file/index';\nimport type { RequestConfig } from '../../../infra/api/client';\nimport { buildWlOverride } from '../../auth/utils/build-wl-override';\nimport type {\n Account,\n AccountUserProjectsResponse,\n AccountUsersPaginationParams,\n ChangePasswordRequest,\n ChangePasswordResponse,\n ChangeUserPhotoResponse,\n CreateAccountUserRequest,\n CreateAccountUserResponse,\n DeleteAccountRequest,\n DeleteAccountResponse,\n DeleteAccountUserResponse,\n GetAccountDataResponse,\n ListAccountUsersResponse,\n UpdateAccountRequest,\n UpdateAccountResponse,\n UpdateAccountUserRequest,\n UpdateAccountUserResponse,\n} from '../types';\n\nclass AccountService {\n async findCurrentAccount(config?: RequestConfig): Promise<Account> {\n const { id_wl, id_account } = await getUserContext();\n const effectiveConfig = config ?? await buildWlOverride(id_wl);\n const response = await api.apps.get<GetAccountDataResponse>(`/accounts/${id_account}`, effectiveConfig);\n\n if (response.status === 0 || !response.data?.[0]) {\n throw new ApiError(\n response.message || 'Erro ao buscar dados da conta',\n 'GET_ACCOUNT_FAILED',\n 400\n );\n }\n\n const { user, ...account } = response.data[0];\n\n return account;\n }\n\n private pickUsersQueryParams(params: Partial<AccountUsersPaginationParams> = {}) {\n const { page, limit, search, name, notInProject, profiles, firstId } = params;\n\n return { page, limit, search, name, notInProject, profiles, firstId };\n }\n\n async listAccountUsers(params?: Partial<AccountUsersPaginationParams>) {\n const { id_account } = await getUserContext();\n const queryParams = buildQueryParams(this.pickUsersQueryParams(params));\n const endpoint = `/accounts/${id_account}/users?${queryParams}`;\n const response = await api.apps.get<ListAccountUsersResponse>(endpoint);\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao listar usuários',\n 'LIST_ACCOUNT_USERS_FAILED',\n 400\n );\n }\n\n return {\n users: response.data || [],\n total: response.total || 0,\n };\n }\n\n /**\n * Usuários da conta com projetos (`total_projects`, `projects`), escopados ao usuário logado:\n * collaborator/viewer só veem quem divide projeto com eles.\n */\n async listAccountMembers(params?: Partial<AccountUsersPaginationParams>) {\n const { id_account, id_user } = await getUserContext();\n const queryParams = buildQueryParams({ ...this.pickUsersQueryParams(params), scopeUserId: id_user });\n const response = await api.apps.get<ListAccountUsersResponse>(\n `/accounts/${id_account}/users?${queryParams}`\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao listar usuários',\n 'LIST_ACCOUNT_USERS_FAILED',\n 400\n );\n }\n\n return {\n users: response.data || [],\n total: response.total || 0,\n };\n }\n\n async changeUserPhoto(userId: number, photo: File): Promise<ChangeUserPhotoResponse> {\n const { id_account } = await getUserContext();\n const base64 = await fileToBase64(photo);\n const response = await api.apps.put<ChangeUserPhotoResponse>(\n `/accounts/${id_account}/users/${userId}/file/photo`,\n { file: base64 }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao mudar foto do usuário',\n 'CHANGE_USER_PHOTO_FAILED',\n 400\n );\n }\n\n return { status: response.status, message: response.message };\n }\n\n async deleteAccountUser(userId: number): Promise<DeleteAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.delete<DeleteAccountUserResponse>(\n `/accounts/${id_account}/users/${userId}`\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao deletar usuário', 'DELETE_USER_FAILED', 400);\n }\n\n return { status: response.status, message: response.message };\n }\n\n async deleteAccount(data: DeleteAccountRequest): Promise<DeleteAccountResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.delete<DeleteAccountResponse>(\n `/accounts/${id_account}`,\n { body: JSON.stringify(data) }\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao deletar conta', 'DELETE_ACCOUNT_FAILED', 400);\n }\n\n return response;\n }\n\n async createAccountUser(user: CreateAccountUserRequest): Promise<CreateAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.post<CreateAccountUserResponse>(\n `/accounts/${id_account}/users`,\n {\n ...user,\n photo: user.photo ? await fileToBase64(user.photo) : null,\n }\n );\n\n if (response.status === 0) {\n throw new ApiError(response.message || 'Erro ao criar usuário', 'CREATE_USER_FAILED', 400);\n }\n\n return { status: response.status, message: response.message };\n }\n\n private async resolvePhotoField(user: UpdateAccountUserRequest): Promise<{ photo?: string | null }> {\n if (user.photo === undefined) return {};\n const photo =\n user.photo != null && typeof user.photo !== 'string'\n ? await fileToBase64(user.photo)\n : user.photo;\n return { photo };\n }\n\n async updateAccountUser(user: UpdateAccountUserRequest): Promise<UpdateAccountUserResponse> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.put<UpdateAccountUserResponse>(\n `/accounts/${id_account}/users/${id_user}`,\n { ...user, ...(await this.resolvePhotoField(user)) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar usuário',\n 'UPDATE_USER_FAILED',\n 400\n );\n }\n\n return { status: response.status, message: response.message };\n }\n\n async updateAccountUserById(\n userId: number,\n user: UpdateAccountUserRequest\n ): Promise<UpdateAccountUserResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.put<UpdateAccountUserResponse>(\n `/accounts/${id_account}/users/${userId}`,\n { ...user, ...(await this.resolvePhotoField(user)) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar usuário',\n 'UPDATE_USER_FAILED',\n 400\n );\n }\n\n return { status: response.status, message: response.message };\n }\n\n async updateAccount(data: UpdateAccountRequest): Promise<UpdateAccountResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.put<UpdateAccountResponse>(`/accounts/${id_account}`, data);\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao atualizar conta',\n 'UPDATE_ACCOUNT_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async requestContactReset(type: 'email' | 'phone', newContact: string, ddi?: string): Promise<void> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.post<{ status: number; message: string }>(\n `/accounts/${id_account}/users/${id_user}/resetContact/request`,\n { type, newContact, ...(ddi ? { ddi } : {}) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao solicitar alteração',\n 'REQUEST_CONTACT_RESET_FAILED',\n 400\n );\n }\n }\n\n async confirmContactReset(type: 'email' | 'phone', token: string, newContact: string, ddi?: string): Promise<void> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.post<{ status: number; message: string }>(\n `/accounts/${id_account}/users/${id_user}/resetContact/confirm`,\n { type, token, newContact, ...(ddi ? { ddi } : {}) }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Código inválido ou expirado',\n 'CONFIRM_CONTACT_RESET_FAILED',\n 400\n );\n }\n }\n\n /** Checagem de e-mail já cadastrado, usada no cadastro de usuário antes de avançar de passo. */\n async checkUserExists(email: string): Promise<{ exists: boolean }> {\n const response = await api.apps.post<{ exist: boolean }>('/users/action/exists', { email });\n\n return { exists: response.exist };\n }\n\n async addUserProjects(userId: number, projectIds: number[]): Promise<AccountUserProjectsResponse> {\n await assertAccountNotFrozen();\n const { id_account } = await getUserContext();\n const response = await api.apps.post<AccountUserProjectsResponse>(\n `/accounts/${id_account}/users/${userId}/action/addProjectsBatch`,\n { projects: projectIds }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao vincular projetos ao usuário',\n 'ADD_USER_PROJECTS_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async removeUserProjects(userId: number, projectIds: number[]): Promise<AccountUserProjectsResponse> {\n const { id_account } = await getUserContext();\n const response = await api.apps.post<AccountUserProjectsResponse>(\n `/accounts/${id_account}/users/${userId}/action/removeProjectsBatch`,\n { projects: projectIds }\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao desvincular projetos do usuário',\n 'REMOVE_USER_PROJECTS_FAILED',\n 400\n );\n }\n\n return response;\n }\n\n async changePassword(data: ChangePasswordRequest): Promise<ChangePasswordResponse> {\n const { id_account, id_user } = await getUserContext();\n const response = await api.apps.put<ChangePasswordResponse>(\n `/accounts/${id_account}/users/${id_user}/action/changePassword`,\n data\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao alterar senha',\n 'CHANGE_PASSWORD_FAILED',\n 400\n );\n }\n\n return response;\n }\n}\n\nexport const accountService = new AccountService();\n"],"mappings":"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","names":[]}
@@ -1,11 +1,11 @@
1
1
  import "server-only";
2
2
  import { ApiError } from "../../../infra/api/types";
3
3
  import { getUserContext } from "../../auth/utils/get-user-context";
4
- import { findWhitelabel } from "../../whitelabel/actions/find-whitelabel.action";
4
+ import { findWhitelabelToken } from "../../whitelabel/utils/find-whitelabel-token";
5
5
  const TWO_FA_BASE_URL = process.env.R2_2FA_URL || "https://r2-2fa.greatapps.dev.br";
6
6
  class TwoFactorService {
7
7
  async request(path, body) {
8
- const { id, token } = await findWhitelabel();
8
+ const { id, token } = await findWhitelabelToken();
9
9
  const { id_account, id_user } = await getUserContext();
10
10
  const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa/${path}`;
11
11
  const response = await fetch(url, {
@@ -49,7 +49,7 @@ class TwoFactorService {
49
49
  return response;
50
50
  }
51
51
  async disable() {
52
- const { id, token } = await findWhitelabel();
52
+ const { id, token } = await findWhitelabelToken();
53
53
  const { id_account, id_user } = await getUserContext();
54
54
  const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa`;
55
55
  const response = await fetch(url, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/accounts/services/two-factor.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\nimport type { TwoFactorActionResponse, TwoFactorGenerateResponse } from '../types';\r\n\r\nconst TWO_FA_BASE_URL = process.env.R2_2FA_URL || 'https://r2-2fa.greatapps.dev.br';\r\n\r\nclass TwoFactorService {\r\n private async request<T>(path: string, body?: object): Promise<T> {\r\n const { id, token } = await findWhitelabel();\r\n const { id_account, id_user } = await getUserContext();\r\n\r\n const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa/${path}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: token,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\r\n throw new ApiError(\r\n (errorData.message as string) || `HTTP error ${response.status}`,\r\n 'HTTP_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n async generate(): Promise<TwoFactorGenerateResponse> {\r\n const response = await this.request<TwoFactorGenerateResponse>('generate');\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao gerar QR Code', 'GENERATE_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async confirm(code: string, options?: { window?: number }): Promise<TwoFactorActionResponse> {\r\n const path = options?.window !== undefined ? `confirm?window=${options.window}` : 'confirm';\r\n const response = await this.request<TwoFactorActionResponse>(path, { code });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código inválido', 'CONFIRM_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async verify(code: string): Promise<TwoFactorActionResponse> {\r\n const response = await this.request<TwoFactorActionResponse>('verify', { code });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código inválido', 'VERIFY_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async disable(): Promise<TwoFactorActionResponse> {\r\n const { id, token } = await findWhitelabel();\r\n const { id_account, id_user } = await getUserContext();\r\n\r\n const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa`;\r\n\r\n const response = await fetch(url, {\r\n method: 'DELETE',\r\n headers: { authorization: token },\r\n });\r\n\r\n if (!response.ok) {\r\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\r\n throw new ApiError(\r\n (errorData.message as string) || `HTTP error ${response.status}`,\r\n 'HTTP_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n const data = await response.json() as TwoFactorActionResponse;\r\n\r\n if (data.status === 0) {\r\n throw new ApiError(data.message || 'Erro ao desabilitar 2FA', 'DISABLE_2FA_FAILED', 400);\r\n }\r\n\r\n return data;\r\n }\r\n}\r\n\r\nexport const twoFactorService = new TwoFactorService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAG/B,MAAM,kBAAkB,QAAQ,IAAI,cAAc;AAElD,MAAM,iBAAiB;AAAA,EACrB,MAAc,QAAW,MAAc,MAA2B;AAChE,UAAM,EAAE,IAAI,MAAM,IAAI,MAAM,eAAe;AAC3C,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,MAAM,GAAG,eAAe,OAAO,EAAE,YAAY,UAAU,UAAU,OAAO,QAAQ,IAAI;AAE1F,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,MACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACxD,YAAM,IAAI;AAAA,QACP,UAAU,WAAsB,cAAc,SAAS,MAAM;AAAA,QAC9D;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA,EAEA,MAAM,WAA+C;AACnD,UAAM,WAAW,MAAM,KAAK,QAAmC,UAAU;AAEzE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAyB,uBAAuB,GAAG;AAAA,IAC5F;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,MAAc,SAAiE;AAC3F,UAAM,OAAO,SAAS,WAAW,SAAY,kBAAkB,QAAQ,MAAM,KAAK;AAClF,UAAM,WAAW,MAAM,KAAK,QAAiC,MAAM,EAAE,KAAK,CAAC;AAE3E,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAmB,sBAAsB,GAAG;AAAA,IACrF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,MAAgD;AAC3D,UAAM,WAAW,MAAM,KAAK,QAAiC,UAAU,EAAE,KAAK,CAAC;AAE/E,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAmB,qBAAqB,GAAG;AAAA,IACpF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAA4C;AAChD,UAAM,EAAE,IAAI,MAAM,IAAI,MAAM,eAAe;AAC3C,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,MAAM,GAAG,eAAe,OAAO,EAAE,YAAY,UAAU,UAAU,OAAO;AAE9E,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,eAAe,MAAM;AAAA,IAClC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACxD,YAAM,IAAI;AAAA,QACP,UAAU,WAAsB,cAAc,SAAS,MAAM;AAAA,QAC9D;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,WAAW,GAAG;AACrB,YAAM,IAAI,SAAS,KAAK,WAAW,2BAA2B,sBAAsB,GAAG;AAAA,IACzF;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,mBAAmB,IAAI,iBAAiB;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/accounts/services/two-factor.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { findWhitelabelToken } from '../../whitelabel/utils/find-whitelabel-token';\r\nimport type { TwoFactorActionResponse, TwoFactorGenerateResponse } from '../types';\r\n\r\nconst TWO_FA_BASE_URL = process.env.R2_2FA_URL || 'https://r2-2fa.greatapps.dev.br';\r\n\r\nclass TwoFactorService {\r\n private async request<T>(path: string, body?: object): Promise<T> {\r\n const { id, token } = await findWhitelabelToken();\r\n const { id_account, id_user } = await getUserContext();\r\n\r\n const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa/${path}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: token,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\r\n throw new ApiError(\r\n (errorData.message as string) || `HTTP error ${response.status}`,\r\n 'HTTP_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n async generate(): Promise<TwoFactorGenerateResponse> {\r\n const response = await this.request<TwoFactorGenerateResponse>('generate');\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao gerar QR Code', 'GENERATE_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async confirm(code: string, options?: { window?: number }): Promise<TwoFactorActionResponse> {\r\n const path = options?.window !== undefined ? `confirm?window=${options.window}` : 'confirm';\r\n const response = await this.request<TwoFactorActionResponse>(path, { code });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código inválido', 'CONFIRM_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async verify(code: string): Promise<TwoFactorActionResponse> {\r\n const response = await this.request<TwoFactorActionResponse>('verify', { code });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código inválido', 'VERIFY_2FA_FAILED', 400);\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async disable(): Promise<TwoFactorActionResponse> {\r\n const { id, token } = await findWhitelabelToken();\r\n const { id_account, id_user } = await getUserContext();\r\n\r\n const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa`;\r\n\r\n const response = await fetch(url, {\r\n method: 'DELETE',\r\n headers: { authorization: token },\r\n });\r\n\r\n if (!response.ok) {\r\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\r\n throw new ApiError(\r\n (errorData.message as string) || `HTTP error ${response.status}`,\r\n 'HTTP_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n const data = await response.json() as TwoFactorActionResponse;\r\n\r\n if (data.status === 0) {\r\n throw new ApiError(data.message || 'Erro ao desabilitar 2FA', 'DISABLE_2FA_FAILED', 400);\r\n }\r\n\r\n return data;\r\n }\r\n}\r\n\r\nexport const twoFactorService = new TwoFactorService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAGpC,MAAM,kBAAkB,QAAQ,IAAI,cAAc;AAElD,MAAM,iBAAiB;AAAA,EACrB,MAAc,QAAW,MAAc,MAA2B;AAChE,UAAM,EAAE,IAAI,MAAM,IAAI,MAAM,oBAAoB;AAChD,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,MAAM,GAAG,eAAe,OAAO,EAAE,YAAY,UAAU,UAAU,OAAO,QAAQ,IAAI;AAE1F,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,MACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACxD,YAAM,IAAI;AAAA,QACP,UAAU,WAAsB,cAAc,SAAS,MAAM;AAAA,QAC9D;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA,EAEA,MAAM,WAA+C;AACnD,UAAM,WAAW,MAAM,KAAK,QAAmC,UAAU;AAEzE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAyB,uBAAuB,GAAG;AAAA,IAC5F;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,MAAc,SAAiE;AAC3F,UAAM,OAAO,SAAS,WAAW,SAAY,kBAAkB,QAAQ,MAAM,KAAK;AAClF,UAAM,WAAW,MAAM,KAAK,QAAiC,MAAM,EAAE,KAAK,CAAC;AAE3E,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAmB,sBAAsB,GAAG;AAAA,IACrF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,MAAgD;AAC3D,UAAM,WAAW,MAAM,KAAK,QAAiC,UAAU,EAAE,KAAK,CAAC;AAE/E,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,SAAS,WAAW,yBAAmB,qBAAqB,GAAG;AAAA,IACpF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAA4C;AAChD,UAAM,EAAE,IAAI,MAAM,IAAI,MAAM,oBAAoB;AAChD,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,MAAM,GAAG,eAAe,OAAO,EAAE,YAAY,UAAU,UAAU,OAAO;AAE9E,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,eAAe,MAAM;AAAA,IAClC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACxD,YAAM,IAAI;AAAA,QACP,UAAU,WAAsB,cAAc,SAAS,MAAM;AAAA,QAC9D;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,WAAW,GAAG;AACrB,YAAM,IAAI,SAAS,KAAK,WAAW,2BAA2B,sBAAsB,GAAG;AAAA,IACzF;AAEA,WAAO;AAAA,EACT;AACF;AAEO,MAAM,mBAAmB,IAAI,iBAAiB;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/modules/users/schema.ts"],"sourcesContent":["export enum UserProfile {\r\n viewer = 'viewer',\r\n collaborator = 'collaborator',\r\n admin = 'admin',\r\n owner = 'owner',\r\n}\r\n\r\nexport interface User {\r\n // Identificação\r\n id: number;\r\n id_wl: number;\r\n id_account: number;\r\n id_api: number;\r\n\r\n // Dados pessoais\r\n name: string;\r\n last_name: string;\r\n email: string;\r\n ddi: string;\r\n phone: string;\r\n rg: string | null;\r\n cpf: string | null;\r\n gender: number;\r\n\r\n // Autenticação e segurança\r\n two_factor_authentication: boolean;\r\n google_sub?: string | null;\r\n google_linked_at?: string | null;\r\n\r\n // Perfil e permissões\r\n profile: UserProfile;\r\n\r\n // Preferências\r\n language: string;\r\n receive_sms: boolean;\r\n receive_email: boolean;\r\n photo: string | null;\r\n\r\n // Metadados\r\n deleted: number;\r\n datetime_alt: string;\r\n datetime_del: string | null;\r\n datetime_add: string;\r\n\r\n total_projects: number;\r\n projects: { id: number; title: string }[];\r\n\r\n initials?: string;\r\n emailVerified?: boolean;\r\n createdAt?: string;\r\n updatedAt?: string;\r\n}\r\n\r\nexport interface GetUserDataResponse {\r\n status: 0 | 1;\r\n total: number;\r\n data: User[];\r\n}\r\n\r\nexport interface JWTPayload {\r\n session: {\r\n location: {\r\n continent: string;\r\n country: string;\r\n region: string;\r\n city: string;\r\n latitude: string;\r\n longitude: string;\r\n };\r\n ip: string;\r\n timezone: string;\r\n agent: string;\r\n code: string | null;\r\n };\r\n id_wl: string;\r\n id_account: number;\r\n id_user: number;\r\n iss: string;\r\n aud: string;\r\n iat: number;\r\n}\r\n"],"mappings":"AAAO,IAAK,cAAL,kBAAKA,iBAAL;AACL,EAAAA,aAAA,YAAS;AACT,EAAAA,aAAA,kBAAe;AACf,EAAAA,aAAA,WAAQ;AACR,EAAAA,aAAA,WAAQ;AAJE,SAAAA;AAAA,GAAA;","names":["UserProfile"]}
1
+ {"version":3,"sources":["../../../src/modules/users/schema.ts"],"sourcesContent":["export enum UserProfile {\r\n viewer = 'viewer',\r\n collaborator = 'collaborator',\r\n admin = 'admin',\r\n owner = 'owner',\r\n}\r\n\r\nexport interface User {\r\n // Identificação\r\n id: number;\r\n id_wl: number;\r\n id_account: number;\r\n id_api: number;\r\n\r\n // Dados pessoais\r\n name: string;\r\n last_name: string;\r\n email: string;\r\n ddi: string;\r\n phone: string;\r\n rg: string | null;\r\n cpf: string | null;\r\n gender: number;\r\n\r\n // Autenticação e segurança\r\n two_factor_authentication: boolean;\r\n google_sub?: string | null;\r\n google_linked_at?: string | null;\r\n\r\n // Perfil e permissões\r\n profile: UserProfile;\r\n\r\n // Preferências\r\n language: string;\r\n receive_sms: boolean;\r\n receive_email: boolean;\r\n photo: string | null;\r\n\r\n // Metadados\r\n deleted: number;\r\n datetime_alt: string;\r\n datetime_del: string | null;\r\n datetime_add: string;\r\n\r\n total_projects: number;\r\n projects: { id: number; title: string }[];\r\n\r\n initials?: string;\r\n emailVerified?: boolean;\r\n createdAt?: string;\r\n updatedAt?: string;\r\n}\r\n\r\nexport interface GetUserDataResponse {\r\n status: 0 | 1;\r\n total: number;\r\n data: Array<User & { password?: string }>;\r\n}\r\n\r\nexport interface JWTPayload {\r\n session: {\r\n location: {\r\n continent: string;\r\n country: string;\r\n region: string;\r\n city: string;\r\n latitude: string;\r\n longitude: string;\r\n };\r\n ip: string;\r\n timezone: string;\r\n agent: string;\r\n code: string | null;\r\n };\r\n id_wl: string;\r\n id_account: number;\r\n id_user: number;\r\n iss: string;\r\n aud: string;\r\n iat: number;\r\n}\r\n"],"mappings":"AAAO,IAAK,cAAL,kBAAKA,iBAAL;AACL,EAAAA,aAAA,YAAS;AACT,EAAAA,aAAA,kBAAe;AACf,EAAAA,aAAA,WAAQ;AACR,EAAAA,aAAA,WAAQ;AAJE,SAAAA;AAAA,GAAA;","names":["UserProfile"]}
@@ -1,7 +1,7 @@
1
1
  import { cookies } from "next/headers";
2
2
  import { ApiError } from "../../../infra/api/types";
3
3
  import { decodeJwtPayload } from "../../../utils/jwt-payload";
4
- import { findWhitelabel } from "../../whitelabel/actions/find-whitelabel.action";
4
+ import { findWhitelabelToken } from "../../whitelabel/utils/find-whitelabel-token";
5
5
  import { buildWlOverride } from "../../auth/utils/build-wl-override";
6
6
  const AUTH_COOKIE_NAME = "greatapps";
7
7
  const API_BASE_URL = process.env.GAPPS_R3_API_URL || "https://r3-api.greatapps.dev.br";
@@ -27,7 +27,7 @@ class UserService {
27
27
  const payload = this.decodeJWT(token);
28
28
  const { id_wl, id_account, id_user } = payload;
29
29
  const wlOverride = overrides ? void 0 : await buildWlOverride(Number(id_wl));
30
- const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabel()).token;
30
+ const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabelToken()).token;
31
31
  const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;
32
32
  const response = await fetch(url, {
33
33
  method: "GET",
@@ -43,7 +43,8 @@ class UserService {
43
43
  if (data.status === 0 || !data.data || data.data.length === 0) {
44
44
  throw new ApiError("Dados do usu\xE1rio n\xE3o encontrados", "USER_NOT_FOUND", 404);
45
45
  }
46
- return data.data[0];
46
+ const { password, ...user } = data.data[0];
47
+ return user;
47
48
  }
48
49
  }
49
50
  const userService = new UserService();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { decodeJwtPayload } from '../../../utils/jwt-payload';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\nimport { buildWlOverride } from '../../auth/utils/build-wl-override';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';\r\n\r\nclass UserService {\r\n private async getAuthToken(): Promise<string> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Não autenticado', 'NOT_AUTHENTICATED_GAT', 401);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private decodeJWT(token: string): JWTPayload {\r\n try {\r\n return decodeJwtPayload<JWTPayload>(token);\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n }\r\n\r\n async findById(overrides?: { authToken?: string }): Promise<User> {\r\n const token = await this.getAuthToken();\r\n const payload = this.decodeJWT(token);\r\n\r\n const { id_wl, id_account, id_user } = payload;\r\n const wlOverride = overrides ? undefined : await buildWlOverride(Number(id_wl));\r\n const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabel()).token;\r\n\r\n const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: wlToken,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ApiError('Erro ao buscar dados do usuário', 'FETCH_ERROR', response.status);\r\n }\r\n\r\n const data = (await response.json()) as GetUserDataResponse;\r\n\r\n if (data.status === 0 || !data.data || data.data.length === 0) {\r\n throw new ApiError('Dados do usuário não encontrados', 'USER_NOT_FOUND', 404);\r\n }\r\n\r\n return data.data[0];\r\n }\r\n}\r\n\r\nexport const userService = new UserService();\r\n"],"mappings":"AACA,SAAS,eAAe;AAExB,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAEhC,MAAM,mBAAmB;AACzB,MAAM,eAAe,QAAQ,IAAI,oBAAoB;AAErD,MAAM,YAAY;AAAA,EAChB,MAAc,eAAgC;AAC5C,QAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,QAAQ,YAAY,IAAI,gBAAgB,GAAG;AAEjD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,sBAAmB,yBAAyB,GAAG;AAAA,IACpE;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,OAA2B;AAC3C,QAAI;AACF,aAAO,iBAA6B,KAAK;AAAA,IAC3C,QAAQ;AACN,YAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,WAAmD;AAChE,UAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,UAAM,UAAU,KAAK,UAAU,KAAK;AAEpC,UAAM,EAAE,OAAO,YAAY,QAAQ,IAAI;AACvC,UAAM,aAAa,YAAY,SAAY,MAAM,gBAAgB,OAAO,KAAK,CAAC;AAC9E,UAAM,UAAU,WAAW,aAAa,YAAY,cAAc,MAAM,eAAe,GAAG;AAE1F,UAAM,MAAM,GAAG,YAAY,aAAa,KAAK,aAAa,UAAU,UAAU,OAAO;AAErF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,SAAS,sCAAmC,eAAe,SAAS,MAAM;AAAA,IACtF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,WAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AAC7D,YAAM,IAAI,SAAS,0CAAoC,kBAAkB,GAAG;AAAA,IAC9E;AAEA,WAAO,KAAK,KAAK,CAAC;AAAA,EACpB;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { decodeJwtPayload } from '../../../utils/jwt-payload';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabelToken } from '../../whitelabel/utils/find-whitelabel-token';\r\nimport { buildWlOverride } from '../../auth/utils/build-wl-override';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';\r\n\r\nclass UserService {\r\n private async getAuthToken(): Promise<string> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Não autenticado', 'NOT_AUTHENTICATED_GAT', 401);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private decodeJWT(token: string): JWTPayload {\r\n try {\r\n return decodeJwtPayload<JWTPayload>(token);\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n }\r\n\r\n async findById(overrides?: { authToken?: string }): Promise<User> {\r\n const token = await this.getAuthToken();\r\n const payload = this.decodeJWT(token);\r\n\r\n const { id_wl, id_account, id_user } = payload;\r\n const wlOverride = overrides ? undefined : await buildWlOverride(Number(id_wl));\r\n const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabelToken()).token;\r\n\r\n const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: wlToken,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ApiError('Erro ao buscar dados do usuário', 'FETCH_ERROR', response.status);\r\n }\r\n\r\n const data = (await response.json()) as GetUserDataResponse;\r\n\r\n if (data.status === 0 || !data.data || data.data.length === 0) {\r\n throw new ApiError('Dados do usuário não encontrados', 'USER_NOT_FOUND', 404);\r\n }\r\n\r\n const { password, ...user } = data.data[0];\r\n\r\n return user;\r\n }\r\n}\r\n\r\nexport const userService = new UserService();\r\n"],"mappings":"AACA,SAAS,eAAe;AAExB,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAEhC,MAAM,mBAAmB;AACzB,MAAM,eAAe,QAAQ,IAAI,oBAAoB;AAErD,MAAM,YAAY;AAAA,EAChB,MAAc,eAAgC;AAC5C,QAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,QAAQ,YAAY,IAAI,gBAAgB,GAAG;AAEjD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,sBAAmB,yBAAyB,GAAG;AAAA,IACpE;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,OAA2B;AAC3C,QAAI;AACF,aAAO,iBAA6B,KAAK;AAAA,IAC3C,QAAQ;AACN,YAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,WAAmD;AAChE,UAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,UAAM,UAAU,KAAK,UAAU,KAAK;AAEpC,UAAM,EAAE,OAAO,YAAY,QAAQ,IAAI;AACvC,UAAM,aAAa,YAAY,SAAY,MAAM,gBAAgB,OAAO,KAAK,CAAC;AAC9E,UAAM,UAAU,WAAW,aAAa,YAAY,cAAc,MAAM,oBAAoB,GAAG;AAE/F,UAAM,MAAM,GAAG,YAAY,aAAa,KAAK,aAAa,UAAU,UAAU,OAAO;AAErF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,SAAS,sCAAmC,eAAe,SAAS,MAAM;AAAA,IACtF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,WAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AAC7D,YAAM,IAAI,SAAS,0CAAoC,kBAAkB,GAAG;AAAA,IAC9E;AAEA,UAAM,EAAE,UAAU,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AAEzC,WAAO;AAAA,EACT;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]}
@@ -1,19 +1,7 @@
1
1
  "use server";
2
- import { headers } from "next/headers";
3
- import { whitelabelService } from "../services/whitelabel.service";
4
- import { ApiError } from "../../../infra/api/types";
5
- import { cache } from "react";
6
- const findWhitelabelByHost = cache(async (host) => {
7
- return whitelabelService.getTokenByDomain(host);
8
- });
2
+ import { resolveWhitelabelForHost } from "../utils/resolve-whitelabel-for-host";
9
3
  const findWhitelabel = async () => {
10
- const headersList = await headers();
11
- const host = headersList.get("host");
12
- if (!host) {
13
- throw new ApiError("Host header not found", "HOST_NOT_FOUND", 400);
14
- }
15
- const whitelabel = await findWhitelabelByHost(host);
16
- Object.defineProperty(whitelabel, "token", { enumerable: false });
4
+ const { token, ...whitelabel } = await resolveWhitelabelForHost();
17
5
  return whitelabel;
18
6
  };
19
7
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/whitelabel/actions/find-whitelabel.action.ts"],"sourcesContent":["'use server';\n\n\nimport { headers } from \"next/headers\";\nimport { whitelabelService } from \"../services/whitelabel.service\";\nimport { ApiError } from \"../../../infra/api/types\";\nimport { cache } from \"react\";\n\nconst findWhitelabelByHost = cache(async (host: string) => {\n return whitelabelService.getTokenByDomain(host);\n});\n\nexport const findWhitelabel = async () => {\n const headersList = await headers();\n const host = headersList.get('host');\n\n if (!host) {\n throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);\n }\n\n const whitelabel = await findWhitelabelByHost(host);\n Object.defineProperty(whitelabel, 'token', { enumerable: false });\n\n return whitelabel;\n};\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AACzB,SAAS,aAAa;AAEtB,MAAM,uBAAuB,MAAM,OAAO,SAAiB;AACvD,SAAO,kBAAkB,iBAAiB,IAAI;AAClD,CAAC;AAEM,MAAM,iBAAiB,YAAY;AACtC,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,OAAO,YAAY,IAAI,MAAM;AAEnC,MAAI,CAAC,MAAM;AACP,UAAM,IAAI,SAAS,yBAAyB,kBAAkB,GAAG;AAAA,EACrE;AAEA,QAAM,aAAa,MAAM,qBAAqB,IAAI;AAClD,SAAO,eAAe,YAAY,SAAS,EAAE,YAAY,MAAM,CAAC;AAEhE,SAAO;AACX;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/whitelabel/actions/find-whitelabel.action.ts"],"sourcesContent":["'use server';\n\nimport { resolveWhitelabelForHost } from '../utils/resolve-whitelabel-for-host';\n\nexport const findWhitelabel = async () => {\n const { token, ...whitelabel } = await resolveWhitelabelForHost();\n\n return whitelabel;\n};\n"],"mappings":";AAEA,SAAS,gCAAgC;AAElC,MAAM,iBAAiB,YAAY;AACtC,QAAM,EAAE,OAAO,GAAG,WAAW,IAAI,MAAM,yBAAyB;AAEhE,SAAO;AACX;","names":[]}
@@ -10,8 +10,7 @@ async function revalidateWhitelabelAction() {
10
10
  if (!host) {
11
11
  throw new ApiError("Host header not found", "HOST_NOT_FOUND", 400);
12
12
  }
13
- const whitelabel = await whitelabelService.revalidateByDomain(host);
14
- Object.defineProperty(whitelabel, "token", { enumerable: false });
13
+ const { token, ...whitelabel } = await whitelabelService.revalidateByDomain(host);
15
14
  return whitelabel;
16
15
  });
17
16
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/whitelabel/actions/revalidate-whitelabel.action.ts"],"sourcesContent":["'use server';\n\nimport { headers } from 'next/headers';\nimport { whitelabelService } from '../services/whitelabel.service';\nimport { ApiError } from '../../../infra/api/types';\nimport { safeServerAction } from '../../../utils/safeServerAction';\n\nexport async function revalidateWhitelabelAction() {\n return safeServerAction(async () => {\n const headersList = await headers();\n const host = headersList.get('host');\n\n if (!host) {\n throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);\n }\n\n const whitelabel = await whitelabelService.revalidateByDomain(host);\n Object.defineProperty(whitelabel, 'token', { enumerable: false });\n\n return whitelabel;\n });\n}\n"],"mappings":";AAEA,SAAS,eAAe;AACxB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,eAAsB,6BAA6B;AACjD,SAAO,iBAAiB,YAAY;AAClC,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,OAAO,YAAY,IAAI,MAAM;AAEnC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,SAAS,yBAAyB,kBAAkB,GAAG;AAAA,IACnE;AAEA,UAAM,aAAa,MAAM,kBAAkB,mBAAmB,IAAI;AAClE,WAAO,eAAe,YAAY,SAAS,EAAE,YAAY,MAAM,CAAC;AAEhE,WAAO;AAAA,EACT,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/whitelabel/actions/revalidate-whitelabel.action.ts"],"sourcesContent":["'use server';\n\nimport { headers } from 'next/headers';\nimport { whitelabelService } from '../services/whitelabel.service';\nimport { ApiError } from '../../../infra/api/types';\nimport { safeServerAction } from '../../../utils/safeServerAction';\n\nexport async function revalidateWhitelabelAction() {\n return safeServerAction(async () => {\n const headersList = await headers();\n const host = headersList.get('host');\n\n if (!host) {\n throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);\n }\n\n const { token, ...whitelabel } = await whitelabelService.revalidateByDomain(host);\n\n return whitelabel;\n });\n}\n"],"mappings":";AAEA,SAAS,eAAe;AACxB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,eAAsB,6BAA6B;AACjD,SAAO,iBAAiB,YAAY;AAClC,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,OAAO,YAAY,IAAI,MAAM;AAEnC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,SAAS,yBAAyB,kBAAkB,GAAG;AAAA,IACnE;AAEA,UAAM,EAAE,OAAO,GAAG,WAAW,IAAI,MAAM,kBAAkB,mBAAmB,IAAI;AAEhF,WAAO;AAAA,EACT,CAAC;AACH;","names":[]}
@@ -0,0 +1,10 @@
1
+ import "server-only";
2
+ import { resolveWhitelabelForHost } from "./resolve-whitelabel-for-host";
3
+ async function findWhitelabelToken() {
4
+ const { id, token } = await resolveWhitelabelForHost();
5
+ return { id, token };
6
+ }
7
+ export {
8
+ findWhitelabelToken
9
+ };
10
+ //# sourceMappingURL=find-whitelabel-token.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/whitelabel/utils/find-whitelabel-token.ts"],"sourcesContent":["import 'server-only';\n\nimport { resolveWhitelabelForHost } from './resolve-whitelabel-for-host';\n\n/**\n * Único ponto de leitura do token de serviço do whitelabel. Server-only por construção: sem\n * `'use server'`, o Next não gera endpoint algum para esta função, então ela nunca é chamável\n * pelo client.\n */\nexport async function findWhitelabelToken(): Promise<{ id: number; token: string }> {\n const { id, token } = await resolveWhitelabelForHost();\n\n return { id, token };\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,gCAAgC;AAOzC,eAAsB,sBAA8D;AAClF,QAAM,EAAE,IAAI,MAAM,IAAI,MAAM,yBAAyB;AAErD,SAAO,EAAE,IAAI,MAAM;AACrB;","names":[]}
@@ -0,0 +1,20 @@
1
+ import "server-only";
2
+ import { headers } from "next/headers";
3
+ import { cache } from "react";
4
+ import { whitelabelService } from "../services/whitelabel.service";
5
+ import { ApiError } from "../../../infra/api/types";
6
+ const resolveWhitelabelByHost = cache(async (host) => {
7
+ return whitelabelService.getTokenByDomain(host);
8
+ });
9
+ async function resolveWhitelabelForHost() {
10
+ const headersList = await headers();
11
+ const host = headersList.get("host");
12
+ if (!host) {
13
+ throw new ApiError("Host header not found", "HOST_NOT_FOUND", 400);
14
+ }
15
+ return resolveWhitelabelByHost(host);
16
+ }
17
+ export {
18
+ resolveWhitelabelForHost
19
+ };
20
+ //# sourceMappingURL=resolve-whitelabel-for-host.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/whitelabel/utils/resolve-whitelabel-for-host.ts"],"sourcesContent":["import 'server-only';\n\nimport { headers } from 'next/headers';\nimport { cache } from 'react';\nimport { whitelabelService } from '../services/whitelabel.service';\nimport { ApiError } from '../../../infra/api/types';\nimport type { WhitelabelTokenData } from '../schema';\n\nconst resolveWhitelabelByHost = cache(async (host: string): Promise<WhitelabelTokenData> => {\n return whitelabelService.getTokenByDomain(host);\n});\n\n/**\n * Resolução por host da requisição atual, deduplicada via React.cache. Base compartilhada de\n * `findWhitelabel()` (sem token) e `findWhitelabelToken()` (com token) — as duas leem o mesmo\n * whitelabel resolvido, uma vez por request.\n */\nexport async function resolveWhitelabelForHost(): Promise<WhitelabelTokenData> {\n const headersList = await headers();\n const host = headersList.get('host');\n\n if (!host) {\n throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);\n }\n\n return resolveWhitelabelByHost(host);\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AAGzB,MAAM,0BAA0B,MAAM,OAAO,SAA+C;AAC1F,SAAO,kBAAkB,iBAAiB,IAAI;AAChD,CAAC;AAOD,eAAsB,2BAAyD;AAC7E,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,OAAO,YAAY,IAAI,MAAM;AAEnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,SAAS,yBAAyB,kBAAkB,GAAG;AAAA,EACnE;AAEA,SAAO,wBAAwB,IAAI;AACrC;","names":[]}
@@ -43,7 +43,7 @@ const persister = {
43
43
  };
44
44
  function QueryProvider({
45
45
  children,
46
- persisterVersion = "v1"
46
+ persisterVersion = "v2"
47
47
  }) {
48
48
  const [queryClient] = useState(
49
49
  () => new QueryClient({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/query.provider.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n QueryCache,\r\n QueryClient,\r\n QueryClientProvider,\r\n} from \"@tanstack/react-query\";\r\nimport { ReactNode, useEffect, useState } from \"react\";\r\nimport dynamic from \"next/dynamic\";\r\nimport { toast } from \"sonner\";\r\nimport {\r\n PersistedClient,\r\n PersistQueryClientProvider,\r\n} from \"@tanstack/react-query-persist-client\";\r\nimport { set, get, del } from \"idb-keyval\";\r\nimport { isShareableQuery, shareQueryCacheBetweenTabs } from \"./share-query-cache\";\r\n\r\n// React Query Devtools só em desenvolvimento - remove do bundle de produção\r\nconst ReactQueryDevtools =\r\n process.env.NODE_ENV === \"development\"\r\n ? dynamic(\r\n () =>\r\n import(\"@tanstack/react-query-devtools\").then((mod) => ({\r\n default: mod.ReactQueryDevtools,\r\n })),\r\n { ssr: false },\r\n )\r\n : () => null;\r\n\r\nexport const persister = {\r\n persistClient: async (client: PersistedClient) => {\r\n try {\r\n await set(\"rq-cache\", client);\r\n } catch {\r\n console.warn(\"Falha ao persistir cache\");\r\n }\r\n },\r\n restoreClient: async (): Promise<PersistedClient | undefined> => {\r\n try {\r\n return await get(\"rq-cache\");\r\n } catch {\r\n await del(\"rq-cache\").catch(() => {});\r\n return undefined;\r\n }\r\n },\r\n removeClient: async () => {\r\n try {\r\n await del(\"rq-cache\");\r\n } catch {\r\n console.warn(\"Falha ao remover cache\");\r\n }\r\n },\r\n};\r\n\r\ninterface QueryProviderProps {\r\n children: ReactNode;\r\n persisterVersion?: string;\r\n}\r\n\r\nexport function QueryProvider({\r\n children,\r\n persisterVersion = \"v1\",\r\n}: QueryProviderProps) {\r\n const [queryClient] = useState(\r\n () =>\r\n new QueryClient({\r\n defaultOptions: {\r\n queries: {\r\n staleTime: 15 * 1000,\r\n gcTime: 5 * 60 * 1000,\r\n refetchOnWindowFocus: false,\r\n refetchOnReconnect: true,\r\n retry: 2,\r\n retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),\r\n },\r\n mutations: {\r\n retry: false,\r\n },\r\n },\r\n }),\r\n );\r\n\r\n useEffect(() => shareQueryCacheBetweenTabs(queryClient), [queryClient]);\r\n\r\n return (\r\n <PersistQueryClientProvider\r\n client={queryClient}\r\n persistOptions={{\r\n persister,\r\n maxAge: 2 * 60 * 60 * 1000,\r\n buster: persisterVersion,\r\n dehydrateOptions: {\r\n shouldDehydrateQuery: isShareableQuery,\r\n },\r\n }}\r\n >\r\n {children}\r\n <ReactQueryDevtools initialIsOpen={false} />\r\n </PersistQueryClientProvider>\r\n );\r\n}\r\n"],"mappings":";AAqFI,SAYE,KAZF;AAnFJ;AAAA,EAEE;AAAA,OAEK;AACP,SAAoB,WAAW,gBAAgB;AAC/C,OAAO,aAAa;AAEpB;AAAA,EAEE;AAAA,OACK;AACP,SAAS,KAAK,KAAK,WAAW;AAC9B,SAAS,kBAAkB,kCAAkC;AAG7D,MAAM,qBACJ,QAAQ,IAAI,aAAa,gBACrB;AAAA,EACE,MACE,OAAO,gCAAgC,EAAE,KAAK,CAAC,SAAS;AAAA,IACtD,SAAS,IAAI;AAAA,EACf,EAAE;AAAA,EACJ,EAAE,KAAK,MAAM;AACf,IACA,MAAM;AAEL,MAAM,YAAY;AAAA,EACvB,eAAe,OAAO,WAA4B;AAChD,QAAI;AACF,YAAM,IAAI,YAAY,MAAM;AAAA,IAC9B,QAAQ;AACN,cAAQ,KAAK,0BAA0B;AAAA,IACzC;AAAA,EACF;AAAA,EACA,eAAe,YAAkD;AAC/D,QAAI;AACF,aAAO,MAAM,IAAI,UAAU;AAAA,IAC7B,QAAQ;AACN,YAAM,IAAI,UAAU,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,cAAc,YAAY;AACxB,QAAI;AACF,YAAM,IAAI,UAAU;AAAA,IACtB,QAAQ;AACN,cAAQ,KAAK,wBAAwB;AAAA,IACvC;AAAA,EACF;AACF;AAOO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,mBAAmB;AACrB,GAAuB;AACrB,QAAM,CAAC,WAAW,IAAI;AAAA,IACpB,MACE,IAAI,YAAY;AAAA,MACd,gBAAgB;AAAA,QACd,SAAS;AAAA,UACP,WAAW,KAAK;AAAA,UAChB,QAAQ,IAAI,KAAK;AAAA,UACjB,sBAAsB;AAAA,UACtB,oBAAoB;AAAA,UACpB,OAAO;AAAA,UACP,YAAY,CAAC,YAAY,KAAK,IAAI,MAAO,KAAK,SAAS,GAAK;AAAA,QAC9D;AAAA,QACA,WAAW;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAEA,YAAU,MAAM,2BAA2B,WAAW,GAAG,CAAC,WAAW,CAAC;AAEtE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,gBAAgB;AAAA,QACd;AAAA,QACA,QAAQ,IAAI,KAAK,KAAK;AAAA,QACtB,QAAQ;AAAA,QACR,kBAAkB;AAAA,UAChB,sBAAsB;AAAA,QACxB;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,QACD,oBAAC,sBAAmB,eAAe,OAAO;AAAA;AAAA;AAAA,EAC5C;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/query.provider.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n QueryCache,\r\n QueryClient,\r\n QueryClientProvider,\r\n} from \"@tanstack/react-query\";\r\nimport { ReactNode, useEffect, useState } from \"react\";\r\nimport dynamic from \"next/dynamic\";\r\nimport { toast } from \"sonner\";\r\nimport {\r\n PersistedClient,\r\n PersistQueryClientProvider,\r\n} from \"@tanstack/react-query-persist-client\";\r\nimport { set, get, del } from \"idb-keyval\";\r\nimport { isShareableQuery, shareQueryCacheBetweenTabs } from \"./share-query-cache\";\r\n\r\n// React Query Devtools só em desenvolvimento - remove do bundle de produção\r\nconst ReactQueryDevtools =\r\n process.env.NODE_ENV === \"development\"\r\n ? dynamic(\r\n () =>\r\n import(\"@tanstack/react-query-devtools\").then((mod) => ({\r\n default: mod.ReactQueryDevtools,\r\n })),\r\n { ssr: false },\r\n )\r\n : () => null;\r\n\r\nexport const persister = {\r\n persistClient: async (client: PersistedClient) => {\r\n try {\r\n await set(\"rq-cache\", client);\r\n } catch {\r\n console.warn(\"Falha ao persistir cache\");\r\n }\r\n },\r\n restoreClient: async (): Promise<PersistedClient | undefined> => {\r\n try {\r\n return await get(\"rq-cache\");\r\n } catch {\r\n await del(\"rq-cache\").catch(() => {});\r\n return undefined;\r\n }\r\n },\r\n removeClient: async () => {\r\n try {\r\n await del(\"rq-cache\");\r\n } catch {\r\n console.warn(\"Falha ao remover cache\");\r\n }\r\n },\r\n};\r\n\r\ninterface QueryProviderProps {\r\n children: ReactNode;\r\n persisterVersion?: string;\r\n}\r\n\r\nexport function QueryProvider({\r\n children,\r\n persisterVersion = \"v2\",\r\n}: QueryProviderProps) {\r\n const [queryClient] = useState(\r\n () =>\r\n new QueryClient({\r\n defaultOptions: {\r\n queries: {\r\n staleTime: 15 * 1000,\r\n gcTime: 5 * 60 * 1000,\r\n refetchOnWindowFocus: false,\r\n refetchOnReconnect: true,\r\n retry: 2,\r\n retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),\r\n },\r\n mutations: {\r\n retry: false,\r\n },\r\n },\r\n }),\r\n );\r\n\r\n useEffect(() => shareQueryCacheBetweenTabs(queryClient), [queryClient]);\r\n\r\n return (\r\n <PersistQueryClientProvider\r\n client={queryClient}\r\n persistOptions={{\r\n persister,\r\n maxAge: 2 * 60 * 60 * 1000,\r\n buster: persisterVersion,\r\n dehydrateOptions: {\r\n shouldDehydrateQuery: isShareableQuery,\r\n },\r\n }}\r\n >\r\n {children}\r\n <ReactQueryDevtools initialIsOpen={false} />\r\n </PersistQueryClientProvider>\r\n );\r\n}\r\n"],"mappings":";AAqFI,SAYE,KAZF;AAnFJ;AAAA,EAEE;AAAA,OAEK;AACP,SAAoB,WAAW,gBAAgB;AAC/C,OAAO,aAAa;AAEpB;AAAA,EAEE;AAAA,OACK;AACP,SAAS,KAAK,KAAK,WAAW;AAC9B,SAAS,kBAAkB,kCAAkC;AAG7D,MAAM,qBACJ,QAAQ,IAAI,aAAa,gBACrB;AAAA,EACE,MACE,OAAO,gCAAgC,EAAE,KAAK,CAAC,SAAS;AAAA,IACtD,SAAS,IAAI;AAAA,EACf,EAAE;AAAA,EACJ,EAAE,KAAK,MAAM;AACf,IACA,MAAM;AAEL,MAAM,YAAY;AAAA,EACvB,eAAe,OAAO,WAA4B;AAChD,QAAI;AACF,YAAM,IAAI,YAAY,MAAM;AAAA,IAC9B,QAAQ;AACN,cAAQ,KAAK,0BAA0B;AAAA,IACzC;AAAA,EACF;AAAA,EACA,eAAe,YAAkD;AAC/D,QAAI;AACF,aAAO,MAAM,IAAI,UAAU;AAAA,IAC7B,QAAQ;AACN,YAAM,IAAI,UAAU,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,cAAc,YAAY;AACxB,QAAI;AACF,YAAM,IAAI,UAAU;AAAA,IACtB,QAAQ;AACN,cAAQ,KAAK,wBAAwB;AAAA,IACvC;AAAA,EACF;AACF;AAOO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,mBAAmB;AACrB,GAAuB;AACrB,QAAM,CAAC,WAAW,IAAI;AAAA,IACpB,MACE,IAAI,YAAY;AAAA,MACd,gBAAgB;AAAA,QACd,SAAS;AAAA,UACP,WAAW,KAAK;AAAA,UAChB,QAAQ,IAAI,KAAK;AAAA,UACjB,sBAAsB;AAAA,UACtB,oBAAoB;AAAA,UACpB,OAAO;AAAA,UACP,YAAY,CAAC,YAAY,KAAK,IAAI,MAAO,KAAK,SAAS,GAAK;AAAA,QAC9D;AAAA,QACA,WAAW;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAEA,YAAU,MAAM,2BAA2B,WAAW,GAAG,CAAC,WAAW,CAAC;AAEtE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,gBAAgB;AAAA,QACd;AAAA,QACA,QAAQ,IAAI,KAAK,KAAK;AAAA,QACtB,QAAQ;AAAA,QACR,kBAAkB;AAAA,UAChB,sBAAsB;AAAA,QACxB;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,QACD,oBAAC,sBAAmB,eAAe,OAAO;AAAA;AAAA;AAAA,EAC5C;AAEJ;","names":[]}
package/dist/server.mjs CHANGED
@@ -3,6 +3,7 @@ import { ApiClient, api, apiClient } from "./infra/api/client";
3
3
  import { authService } from "./modules/auth/services/auth.service";
4
4
  import { whitelabelService } from "./modules/whitelabel/services/whitelabel.service";
5
5
  import { revalidateWhitelabelAction } from "./modules/whitelabel/actions/revalidate-whitelabel.action";
6
+ import { findWhitelabelToken } from "./modules/whitelabel/utils/find-whitelabel-token";
6
7
  import { assertManagementPermission } from "./modules/auth/utils/assert-management-permission";
7
8
  import { assertManagementSubscription } from "./modules/auth/utils/assert-management-subscription";
8
9
  import { assertSubscriptionAddon } from "./modules/auth/utils/assert-subscription-addon";
@@ -114,6 +115,7 @@ export {
114
115
  findProjectAction,
115
116
  findUserById,
116
117
  findWhitelabel,
118
+ findWhitelabelToken,
117
119
  generateTwoFactorAction,
118
120
  getAccountTokenAction,
119
121
  getClientInfoFromRequest,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\n\n// API Client\nexport { ApiClient, api, apiClient } from './infra/api/client';\n\n// Services\nexport { authService } from './modules/auth/services/auth.service';\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\nexport { revalidateWhitelabelAction } from './modules/whitelabel/actions/revalidate-whitelabel.action';\nexport { assertManagementPermission } from './modules/auth/utils/assert-management-permission';\nexport { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';\nexport { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';\nexport { assertPaidSubscription } from './modules/auth/utils/assert-paid-subscription';\nexport { assertAccountNotFrozen } from './modules/auth/utils/assert-account-not-frozen';\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\nexport { plansService } from './modules/plans/services/plans.service';\nexport { cardsService } from './modules/cards/services/cards.service';\nexport { chargesService } from './modules/charges/services/charges.service';\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\n\n// Actions\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\nexport { socialGoogleLoginAction } from './modules/auth/actions/social-google-login.action';\nexport { socialGoogleOnboardingAction } from './modules/auth/actions/social-google-onboarding.action';\nexport { unlinkGoogleAction } from './modules/auth/actions/unlink-google.action';\nexport { findUserById } from './modules/users/action/find-user-by-id.action';\nexport { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';\nexport { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\nexport { getCurrentSubscriptionAction } from './modules/subscriptions/actions/get-current-subscription.action';\nexport { readCurrentSubscription } from './modules/subscriptions/utils/read-current-subscription';\nexport { ackFreezeNoticeAction } from './modules/subscriptions/actions/ack-freeze-notice.action';\nexport { calculateSubscriptionAction } from './modules/subscriptions/actions/calculate-subscription.action';\nexport { updateSubscriptionPlanAction } from './modules/subscriptions/actions/update-subscription-plan.action';\nexport { updateSubscriptionPaymentAction } from './modules/subscriptions/actions/update-subscription-payment.action';\nexport { createCardAction } from './modules/cards/actions/create-card.action';\nexport { createSetupIntentAction } from './modules/cards/actions/create-setup-intent.action';\nexport { chargeActionAction } from './modules/charges/actions/charge-action.action';\nexport { resolvePlanExtrasPrices } from './modules/subscriptions/utils/resolve-plan-extras-prices';\nexport { hasSubscriptionExpired } from './modules/subscriptions/utils/has-subscription-expired';\nexport { hasActivePaidSubscription } from './modules/subscriptions/utils/has-active-paid-subscription';\n\n// Project Services & Actions (server-only)\nexport { projectsService } from './modules/projects/services/projects.service';\nexport { listProjectsAction } from './modules/projects/actions/list-projects.action';\nexport { findProjectAction } from './modules/projects/actions/find-project.action';\nexport { createProjectAction } from './modules/projects/actions/create-project.action';\nexport { updateProjectAction } from './modules/projects/actions/update-project.action';\nexport { deleteProjectAction } from './modules/projects/actions/delete-project.action';\n\n// Project Users Services & Actions (server-only)\nexport { projectUsersService } from './modules/projects/services/project-users.service';\nexport { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';\nexport { addProjectUserAction } from './modules/projects/actions/add-project-user.action';\nexport { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';\n\n// Account Services & Actions (server-only)\nexport { accountService } from './modules/accounts/services/account.service';\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\nexport {\n listAccountUsersAction,\n updateUserAction,\n updateAccountAction,\n updateAccountUserByIdAction,\n updateBillingDataAction,\n deleteAccountUserAction,\n deleteAccountAction,\n createAccountUserAction,\n checkUserExistsAction,\n addUserProjectsAction,\n removeUserProjectsAction,\n changePasswordAction,\n requestEmailChangeAction,\n confirmEmailChangeAction,\n requestPhoneChangeAction,\n confirmPhoneChangeAction,\n generateTwoFactorAction,\n confirmTwoFactorAction,\n disableTwoFactorAction,\n} from './modules/accounts/actions/account-management.action';\n\n// Server Utils\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\nexport { getUserContext } from './modules/auth/utils/get-user-context';\nexport { resolveLocale } from './i18n/resolve-locale';\nexport type { ResolveLocaleOptions } from './i18n/resolve-locale';\nexport { requireValidSession } from './modules/auth/utils/require-valid-session';\nexport { requireTokenNotExpired } from './modules/auth/utils/require-token-not-expired';\nexport { buildWlOverride, buildWlOverrideFromJwt } from './modules/auth/utils/build-wl-override';\nexport { safeServerAction } from './utils/safeServerAction';\nexport { safeMutationAction } from './utils/safeMutationAction';\n\n// Image Processing (server-side)\nexport { processImageAction } from './modules/images/actions/process-image.action';\nexport { processImage } from './modules/images/services/image-processing.service';\nexport type {\n ProcessImageInput,\n ProcessImageOutput,\n ProcessImageActionInput,\n ProcessImageActionOutput,\n} from './modules/images/types/image.type';\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kCAAkC;AAC3C,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,uCAAuC;AAChD,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAG1C,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAGpC,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AAGxC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAE9B,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,iBAAiB,8BAA8B;AACxD,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAGnC,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\n\n// API Client\nexport { ApiClient, api, apiClient } from './infra/api/client';\n\n// Services\nexport { authService } from './modules/auth/services/auth.service';\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\nexport { revalidateWhitelabelAction } from './modules/whitelabel/actions/revalidate-whitelabel.action';\nexport { findWhitelabelToken } from './modules/whitelabel/utils/find-whitelabel-token';\nexport { assertManagementPermission } from './modules/auth/utils/assert-management-permission';\nexport { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';\nexport { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';\nexport { assertPaidSubscription } from './modules/auth/utils/assert-paid-subscription';\nexport { assertAccountNotFrozen } from './modules/auth/utils/assert-account-not-frozen';\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\nexport { plansService } from './modules/plans/services/plans.service';\nexport { cardsService } from './modules/cards/services/cards.service';\nexport { chargesService } from './modules/charges/services/charges.service';\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\n\n// Actions\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\nexport { socialGoogleLoginAction } from './modules/auth/actions/social-google-login.action';\nexport { socialGoogleOnboardingAction } from './modules/auth/actions/social-google-onboarding.action';\nexport { unlinkGoogleAction } from './modules/auth/actions/unlink-google.action';\nexport { findUserById } from './modules/users/action/find-user-by-id.action';\nexport { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';\nexport { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\nexport { getCurrentSubscriptionAction } from './modules/subscriptions/actions/get-current-subscription.action';\nexport { readCurrentSubscription } from './modules/subscriptions/utils/read-current-subscription';\nexport { ackFreezeNoticeAction } from './modules/subscriptions/actions/ack-freeze-notice.action';\nexport { calculateSubscriptionAction } from './modules/subscriptions/actions/calculate-subscription.action';\nexport { updateSubscriptionPlanAction } from './modules/subscriptions/actions/update-subscription-plan.action';\nexport { updateSubscriptionPaymentAction } from './modules/subscriptions/actions/update-subscription-payment.action';\nexport { createCardAction } from './modules/cards/actions/create-card.action';\nexport { createSetupIntentAction } from './modules/cards/actions/create-setup-intent.action';\nexport { chargeActionAction } from './modules/charges/actions/charge-action.action';\nexport { resolvePlanExtrasPrices } from './modules/subscriptions/utils/resolve-plan-extras-prices';\nexport { hasSubscriptionExpired } from './modules/subscriptions/utils/has-subscription-expired';\nexport { hasActivePaidSubscription } from './modules/subscriptions/utils/has-active-paid-subscription';\n\n// Project Services & Actions (server-only)\nexport { projectsService } from './modules/projects/services/projects.service';\nexport { listProjectsAction } from './modules/projects/actions/list-projects.action';\nexport { findProjectAction } from './modules/projects/actions/find-project.action';\nexport { createProjectAction } from './modules/projects/actions/create-project.action';\nexport { updateProjectAction } from './modules/projects/actions/update-project.action';\nexport { deleteProjectAction } from './modules/projects/actions/delete-project.action';\n\n// Project Users Services & Actions (server-only)\nexport { projectUsersService } from './modules/projects/services/project-users.service';\nexport { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';\nexport { addProjectUserAction } from './modules/projects/actions/add-project-user.action';\nexport { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';\n\n// Account Services & Actions (server-only)\nexport { accountService } from './modules/accounts/services/account.service';\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\nexport {\n listAccountUsersAction,\n updateUserAction,\n updateAccountAction,\n updateAccountUserByIdAction,\n updateBillingDataAction,\n deleteAccountUserAction,\n deleteAccountAction,\n createAccountUserAction,\n checkUserExistsAction,\n addUserProjectsAction,\n removeUserProjectsAction,\n changePasswordAction,\n requestEmailChangeAction,\n confirmEmailChangeAction,\n requestPhoneChangeAction,\n confirmPhoneChangeAction,\n generateTwoFactorAction,\n confirmTwoFactorAction,\n disableTwoFactorAction,\n} from './modules/accounts/actions/account-management.action';\n\n// Server Utils\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\nexport { getUserContext } from './modules/auth/utils/get-user-context';\nexport { resolveLocale } from './i18n/resolve-locale';\nexport type { ResolveLocaleOptions } from './i18n/resolve-locale';\nexport { requireValidSession } from './modules/auth/utils/require-valid-session';\nexport { requireTokenNotExpired } from './modules/auth/utils/require-token-not-expired';\nexport { buildWlOverride, buildWlOverrideFromJwt } from './modules/auth/utils/build-wl-override';\nexport { safeServerAction } from './utils/safeServerAction';\nexport { safeMutationAction } from './utils/safeMutationAction';\n\n// Image Processing (server-side)\nexport { processImageAction } from './modules/images/actions/process-image.action';\nexport { processImage } from './modules/images/services/image-processing.service';\nexport type {\n ProcessImageInput,\n ProcessImageOutput,\n ProcessImageActionInput,\n ProcessImageActionOutput,\n} from './modules/images/types/image.type';\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AACpC,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,oCAAoC;AAC7C,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,uCAAuC;AAChD,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAG1C,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAGpC,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AAGxC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAE9B,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,iBAAiB,8BAA8B;AACxD,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAGnC,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.803",
3
+ "version": "1.1.805",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -1,7 +1,7 @@
1
1
  import { headers as nextHeaders } from "next/headers";
2
2
 
3
3
  import { ApiError } from "./types";
4
- import { findWhitelabel } from "../../modules/whitelabel/actions/find-whitelabel.action";
4
+ import { findWhitelabelToken } from "../../modules/whitelabel/utils/find-whitelabel-token";
5
5
 
6
6
  /**
7
7
  * Headers de tracing distribuído do Sentry, repassados da requisição que chegou neste worker
@@ -40,9 +40,9 @@ export interface RequestConfig extends RequestInit {
40
40
  timeout?: number;
41
41
  /** Padrão `json`. Use `text` quando a API devolve corpo não-JSON. */
42
42
  responseType?: "json" | "text";
43
- /** Força um whiteLabelId específico na URL, ignorando o findWhitelabel(). */
43
+ /** Força um whiteLabelId específico na URL, ignorando o findWhitelabelToken(). */
44
44
  whiteLabelId?: number;
45
- /** Força um token específico no header Authorization, ignorando o findWhitelabel(). */
45
+ /** Força um token específico no header Authorization, ignorando o findWhitelabelToken(). */
46
46
  authToken?: string;
47
47
  }
48
48
 
@@ -99,7 +99,7 @@ class ApiClient {
99
99
 
100
100
  /**
101
101
  * Repassa o tracing quando existe. Sem mecanismo novo: `request()` já aguarda
102
- * `findWhitelabel()`, que já é um `'use server'` lendo `next/headers` — é a mesma chamada, no
102
+ * `findWhitelabelToken()`, que já lê `next/headers` — é a mesma chamada, no
103
103
  * mesmo ponto do fluxo. Fica aqui dentro de propósito: os dois call sites de
104
104
  * `getDefaultHeaders` passam a propagar sem precisar lembrar disso em cada um.
105
105
  *
@@ -140,7 +140,7 @@ class ApiClient {
140
140
  console.log("[ApiClient] Building URL and headers...");
141
141
  }
142
142
 
143
- const { id, token } = await findWhitelabel();
143
+ const { id, token } = await findWhitelabelToken();
144
144
 
145
145
  const [url, defaultHeaders] = await Promise.all([
146
146
  this.buildUrl(endpoint, overrideWlId ?? id),
@@ -314,7 +314,7 @@ class ApiClient {
314
314
  // consulta seria uma ida à rede para descartar o resultado.
315
315
  const resolvido = overrideWlId != null && overrideToken != null
316
316
  ? { id: overrideWlId, token: overrideToken }
317
- : await findWhitelabel();
317
+ : await findWhitelabelToken();
318
318
 
319
319
  const [url, defaultHeaders] = await Promise.all([
320
320
  this.buildUrl(endpoint, overrideWlId ?? resolvido.id),
@@ -42,12 +42,20 @@ class AccountService {
42
42
  );
43
43
  }
44
44
 
45
- return response.data[0];
45
+ const { user, ...account } = response.data[0];
46
+
47
+ return account;
48
+ }
49
+
50
+ private pickUsersQueryParams(params: Partial<AccountUsersPaginationParams> = {}) {
51
+ const { page, limit, search, name, notInProject, profiles, firstId } = params;
52
+
53
+ return { page, limit, search, name, notInProject, profiles, firstId };
46
54
  }
47
55
 
48
56
  async listAccountUsers(params?: Partial<AccountUsersPaginationParams>) {
49
57
  const { id_account } = await getUserContext();
50
- const queryParams = buildQueryParams(params);
58
+ const queryParams = buildQueryParams(this.pickUsersQueryParams(params));
51
59
  const endpoint = `/accounts/${id_account}/users?${queryParams}`;
52
60
  const response = await api.apps.get<ListAccountUsersResponse>(endpoint);
53
61
 
@@ -71,7 +79,7 @@ class AccountService {
71
79
  */
72
80
  async listAccountMembers(params?: Partial<AccountUsersPaginationParams>) {
73
81
  const { id_account, id_user } = await getUserContext();
74
- const queryParams = buildQueryParams({ ...params, scopeUserId: id_user });
82
+ const queryParams = buildQueryParams({ ...this.pickUsersQueryParams(params), scopeUserId: id_user });
75
83
  const response = await api.apps.get<ListAccountUsersResponse>(
76
84
  `/accounts/${id_account}/users?${queryParams}`
77
85
  );
@@ -106,7 +114,7 @@ class AccountService {
106
114
  );
107
115
  }
108
116
 
109
- return response;
117
+ return { status: response.status, message: response.message };
110
118
  }
111
119
 
112
120
  async deleteAccountUser(userId: number): Promise<DeleteAccountUserResponse> {
@@ -119,7 +127,7 @@ class AccountService {
119
127
  throw new ApiError(response.message || 'Erro ao deletar usuário', 'DELETE_USER_FAILED', 400);
120
128
  }
121
129
 
122
- return response;
130
+ return { status: response.status, message: response.message };
123
131
  }
124
132
 
125
133
  async deleteAccount(data: DeleteAccountRequest): Promise<DeleteAccountResponse> {
@@ -150,7 +158,7 @@ class AccountService {
150
158
  throw new ApiError(response.message || 'Erro ao criar usuário', 'CREATE_USER_FAILED', 400);
151
159
  }
152
160
 
153
- return response;
161
+ return { status: response.status, message: response.message };
154
162
  }
155
163
 
156
164
  private async resolvePhotoField(user: UpdateAccountUserRequest): Promise<{ photo?: string | null }> {
@@ -177,7 +185,7 @@ class AccountService {
177
185
  );
178
186
  }
179
187
 
180
- return response;
188
+ return { status: response.status, message: response.message };
181
189
  }
182
190
 
183
191
  async updateAccountUserById(
@@ -198,7 +206,7 @@ class AccountService {
198
206
  );
199
207
  }
200
208
 
201
- return response;
209
+ return { status: response.status, message: response.message };
202
210
  }
203
211
 
204
212
  async updateAccount(data: UpdateAccountRequest): Promise<UpdateAccountResponse> {
@@ -2,14 +2,14 @@ import 'server-only';
2
2
 
3
3
  import { ApiError } from '../../../infra/api/types';
4
4
  import { getUserContext } from '../../auth/utils/get-user-context';
5
- import { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';
5
+ import { findWhitelabelToken } from '../../whitelabel/utils/find-whitelabel-token';
6
6
  import type { TwoFactorActionResponse, TwoFactorGenerateResponse } from '../types';
7
7
 
8
8
  const TWO_FA_BASE_URL = process.env.R2_2FA_URL || 'https://r2-2fa.greatapps.dev.br';
9
9
 
10
10
  class TwoFactorService {
11
11
  private async request<T>(path: string, body?: object): Promise<T> {
12
- const { id, token } = await findWhitelabel();
12
+ const { id, token } = await findWhitelabelToken();
13
13
  const { id_account, id_user } = await getUserContext();
14
14
 
15
15
  const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa/${path}`;
@@ -67,7 +67,7 @@ class TwoFactorService {
67
67
  }
68
68
 
69
69
  async disable(): Promise<TwoFactorActionResponse> {
70
- const { id, token } = await findWhitelabel();
70
+ const { id, token } = await findWhitelabelToken();
71
71
  const { id_account, id_user } = await getUserContext();
72
72
 
73
73
  const url = `${TWO_FA_BASE_URL}/v1/${id}/account/${id_account}/users/${id_user}/2fa`;
@@ -55,7 +55,7 @@ export interface AccountUsersPaginationParams {
55
55
  export interface GetAccountDataResponse {
56
56
  status: 0 | 1;
57
57
  message: string;
58
- data: Account[];
58
+ data: Array<Account & { user?: User }>;
59
59
  total: number;
60
60
  }
61
61
 
@@ -92,7 +92,6 @@ export interface CreateAccountUserRequest {
92
92
  export interface CreateAccountUserResponse {
93
93
  status: 0 | 1;
94
94
  message: string;
95
- data: User[];
96
95
  }
97
96
 
98
97
  export interface UpdateAccountUserRequest {
@@ -118,7 +117,6 @@ export interface UpdateAccountUserRequest {
118
117
  export interface UpdateAccountUserResponse {
119
118
  status: 0 | 1;
120
119
  message: string;
121
- data: User[];
122
120
  }
123
121
 
124
122
  export interface ChangeUserPhotoResponse {
@@ -166,7 +166,6 @@ export interface RegisterApiResponse {
166
166
  ddi: string;
167
167
  phone: string;
168
168
  email: string;
169
- password: string;
170
169
  gender: number;
171
170
  two_factor_authentication: boolean;
172
171
  profile: string;
@@ -54,7 +54,7 @@ export interface User {
54
54
  export interface GetUserDataResponse {
55
55
  status: 0 | 1;
56
56
  total: number;
57
- data: User[];
57
+ data: Array<User & { password?: string }>;
58
58
  }
59
59
 
60
60
  export interface JWTPayload {
@@ -4,7 +4,7 @@ import { cookies } from 'next/headers';
4
4
  import { ApiError } from '../../../infra/api/types';
5
5
  import { decodeJwtPayload } from '../../../utils/jwt-payload';
6
6
  import { GetUserDataResponse, JWTPayload, User } from '../schema';
7
- import { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';
7
+ import { findWhitelabelToken } from '../../whitelabel/utils/find-whitelabel-token';
8
8
  import { buildWlOverride } from '../../auth/utils/build-wl-override';
9
9
 
10
10
  const AUTH_COOKIE_NAME = 'greatapps';
@@ -37,7 +37,7 @@ class UserService {
37
37
 
38
38
  const { id_wl, id_account, id_user } = payload;
39
39
  const wlOverride = overrides ? undefined : await buildWlOverride(Number(id_wl));
40
- const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabel()).token;
40
+ const wlToken = overrides?.authToken ?? wlOverride?.authToken ?? (await findWhitelabelToken()).token;
41
41
 
42
42
  const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;
43
43
 
@@ -59,7 +59,9 @@ class UserService {
59
59
  throw new ApiError('Dados do usuário não encontrados', 'USER_NOT_FOUND', 404);
60
60
  }
61
61
 
62
- return data.data[0];
62
+ const { password, ...user } = data.data[0];
63
+
64
+ return user;
63
65
  }
64
66
  }
65
67
 
@@ -1,25 +1,9 @@
1
1
  'use server';
2
2
 
3
-
4
- import { headers } from "next/headers";
5
- import { whitelabelService } from "../services/whitelabel.service";
6
- import { ApiError } from "../../../infra/api/types";
7
- import { cache } from "react";
8
-
9
- const findWhitelabelByHost = cache(async (host: string) => {
10
- return whitelabelService.getTokenByDomain(host);
11
- });
3
+ import { resolveWhitelabelForHost } from '../utils/resolve-whitelabel-for-host';
12
4
 
13
5
  export const findWhitelabel = async () => {
14
- const headersList = await headers();
15
- const host = headersList.get('host');
16
-
17
- if (!host) {
18
- throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);
19
- }
20
-
21
- const whitelabel = await findWhitelabelByHost(host);
22
- Object.defineProperty(whitelabel, 'token', { enumerable: false });
6
+ const { token, ...whitelabel } = await resolveWhitelabelForHost();
23
7
 
24
8
  return whitelabel;
25
9
  };
@@ -14,8 +14,7 @@ export async function revalidateWhitelabelAction() {
14
14
  throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);
15
15
  }
16
16
 
17
- const whitelabel = await whitelabelService.revalidateByDomain(host);
18
- Object.defineProperty(whitelabel, 'token', { enumerable: false });
17
+ const { token, ...whitelabel } = await whitelabelService.revalidateByDomain(host);
19
18
 
20
19
  return whitelabel;
21
20
  });
@@ -63,7 +63,6 @@ export interface WhitelabelData {
63
63
  video_url: string | null;
64
64
  external_contracting_url: string | null;
65
65
  external_plans_url: string | null;
66
- token?: string;
67
66
  }
68
67
 
69
68
 
@@ -0,0 +1,14 @@
1
+ import 'server-only';
2
+
3
+ import { resolveWhitelabelForHost } from './resolve-whitelabel-for-host';
4
+
5
+ /**
6
+ * Único ponto de leitura do token de serviço do whitelabel. Server-only por construção: sem
7
+ * `'use server'`, o Next não gera endpoint algum para esta função, então ela nunca é chamável
8
+ * pelo client.
9
+ */
10
+ export async function findWhitelabelToken(): Promise<{ id: number; token: string }> {
11
+ const { id, token } = await resolveWhitelabelForHost();
12
+
13
+ return { id, token };
14
+ }
@@ -0,0 +1,27 @@
1
+ import 'server-only';
2
+
3
+ import { headers } from 'next/headers';
4
+ import { cache } from 'react';
5
+ import { whitelabelService } from '../services/whitelabel.service';
6
+ import { ApiError } from '../../../infra/api/types';
7
+ import type { WhitelabelTokenData } from '../schema';
8
+
9
+ const resolveWhitelabelByHost = cache(async (host: string): Promise<WhitelabelTokenData> => {
10
+ return whitelabelService.getTokenByDomain(host);
11
+ });
12
+
13
+ /**
14
+ * Resolução por host da requisição atual, deduplicada via React.cache. Base compartilhada de
15
+ * `findWhitelabel()` (sem token) e `findWhitelabelToken()` (com token) — as duas leem o mesmo
16
+ * whitelabel resolvido, uma vez por request.
17
+ */
18
+ export async function resolveWhitelabelForHost(): Promise<WhitelabelTokenData> {
19
+ const headersList = await headers();
20
+ const host = headersList.get('host');
21
+
22
+ if (!host) {
23
+ throw new ApiError('Host header not found', 'HOST_NOT_FOUND', 400);
24
+ }
25
+
26
+ return resolveWhitelabelByHost(host);
27
+ }
@@ -59,7 +59,7 @@ interface QueryProviderProps {
59
59
 
60
60
  export function QueryProvider({
61
61
  children,
62
- persisterVersion = "v1",
62
+ persisterVersion = "v2",
63
63
  }: QueryProviderProps) {
64
64
  const [queryClient] = useState(
65
65
  () =>
package/src/server.ts CHANGED
@@ -7,6 +7,7 @@ export { ApiClient, api, apiClient } from './infra/api/client';
7
7
  export { authService } from './modules/auth/services/auth.service';
8
8
  export { whitelabelService } from './modules/whitelabel/services/whitelabel.service';
9
9
  export { revalidateWhitelabelAction } from './modules/whitelabel/actions/revalidate-whitelabel.action';
10
+ export { findWhitelabelToken } from './modules/whitelabel/utils/find-whitelabel-token';
10
11
  export { assertManagementPermission } from './modules/auth/utils/assert-management-permission';
11
12
  export { assertManagementSubscription } from './modules/auth/utils/assert-management-subscription';
12
13
  export { assertSubscriptionAddon } from './modules/auth/utils/assert-subscription-addon';