@greatapps/common 1.1.726 → 1.1.728

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.
@@ -1,40 +1,14 @@
1
1
  import "server-only";
2
2
  import { api, getUserContext } from "@greatapps/common/server";
3
3
  import { ApiError, buildQueryParams, PlanSchema } from "@greatapps/common";
4
- import greatCache from "@greatapps/cache";
5
- const PLANS_CACHE_TTL = 604800;
6
4
  class PlansService {
7
- cache = new greatCache({
8
- service: "plans",
9
- version: "1.0",
10
- domain: "whitelabel-cache.greatapps.com.br",
11
- ambient: process.env.NODE_ENV || "development"
12
- });
13
- buildCacheKey(key, params) {
14
- const idWl = params?.id_wl ?? "";
15
- const idAccount = params?.id_account ?? "";
16
- const sort = params?.sort ?? "id:ASC";
17
- const active = params?.active ?? "";
18
- const search = params?.search ?? "";
19
- return `${key}-${idWl}-${idAccount}-${sort}-${active}-${search}-v5`;
20
- }
21
5
  /**
22
6
  * Lista planos do whitelabel.
23
7
  * Exemplo:
24
8
  * GET /{id_wl}/plans?active=true&search=client&sort=id:ASC
25
9
  */
26
10
  async listPlans(params) {
27
- const { id_wl, id_account } = await getUserContext();
28
- const cacheKey = this.buildCacheKey("plans", {
29
- ...params,
30
- id_wl,
31
- id_account
32
- });
33
- const cachedData = await this.cache.select(cacheKey);
34
- if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
35
- const data2 = JSON.parse(cachedData.data);
36
- return { data: data2, total: data2.length, success: true };
37
- }
11
+ const { id_account } = await getUserContext();
38
12
  const query = buildQueryParams({
39
13
  sort: params?.sort ?? "id:ASC",
40
14
  active: params?.active,
@@ -52,7 +26,6 @@ class PlansService {
52
26
  }
53
27
  const rawData = response.data;
54
28
  const data = Array.isArray(rawData) ? rawData.map((item) => PlanSchema.parse(item)) : [];
55
- await this.cache.insert(cacheKey, JSON.stringify(data), PLANS_CACHE_TTL);
56
29
  return {
57
30
  data,
58
31
  total: response.total,
@@ -60,16 +33,7 @@ class PlansService {
60
33
  };
61
34
  }
62
35
  async findById(idPlan) {
63
- const { id_wl, id_account } = await getUserContext();
64
- const cacheKey = this.buildCacheKey(`plan-${idPlan}-v2`, {
65
- id_wl,
66
- id_account: String(id_account)
67
- });
68
- const cachedData = await this.cache.select(cacheKey);
69
- if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
70
- const data = JSON.parse(cachedData.data);
71
- return { data, success: true };
72
- }
36
+ const { id_account } = await getUserContext();
73
37
  const query = buildQueryParams({ type: "client", id_account });
74
38
  const response = await api.apps.get(
75
39
  `/plans/${idPlan}?${query}`
@@ -85,7 +49,6 @@ class PlansService {
85
49
  throw new ApiError("Plano n\xE3o encontrado", "PLAN_NOT_FOUND", 404);
86
50
  }
87
51
  const plan = PlanSchema.parse(response.data[0]);
88
- await this.cache.insert(cacheKey, JSON.stringify(plan), PLANS_CACHE_TTL);
89
52
  return {
90
53
  success: true,
91
54
  data: plan
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/plans/services/plans.service.ts"],"sourcesContent":["import \"server-only\";\n\nimport { api, apiClient, getUserContext } from \"@greatapps/common/server\";\nimport { ApiError, buildQueryParams, PlanSchema } from \"@greatapps/common\";\nimport type {\n ApiPaginatedActionResult,\n PaginatedSuccessResult,\n Plan,\n SuccessResult,\n} from \"@greatapps/common\";\nimport greatCache from \"@greatapps/cache\";\n\nexport type ListPlansParams = {\n sort?: string;\n active?: boolean;\n search?: string;\n};\n\nconst PLANS_CACHE_TTL = 604800;\n\nclass PlansService {\n private cache = new greatCache({\n service: \"plans\",\n version: \"1.0\",\n domain: \"whitelabel-cache.greatapps.com.br\",\n ambient: process.env.NODE_ENV || \"development\",\n });\n\n private buildCacheKey(key: string, params?: Record<string, unknown>): string {\n const idWl = params?.id_wl ?? \"\";\n const idAccount = params?.id_account ?? \"\";\n const sort = params?.sort ?? \"id:ASC\";\n const active = params?.active ?? \"\";\n const search = params?.search ?? \"\";\n // v5: itens do plano passaram a carregar o flag `base` (PR #188 da API)\n return `${key}-${idWl}-${idAccount}-${sort}-${active}-${search}-v5`;\n }\n\n /**\n * Lista planos do whitelabel.\n * Exemplo:\n * GET /{id_wl}/plans?active=true&search=client&sort=id:ASC\n */\n async listPlans(\n params?: ListPlansParams,\n ): Promise<PaginatedSuccessResult<Plan>> {\n const { id_wl, id_account } = await getUserContext();\n const cacheKey = this.buildCacheKey(\"plans\", {\n ...params,\n id_wl,\n id_account,\n });\n\n const cachedData = await this.cache.select(cacheKey);\n\n if (cachedData.status == 1 && \"data\" in cachedData && cachedData.data) {\n const data = JSON.parse(cachedData.data) as Plan[];\n return { data, total: data.length, success: true };\n }\n\n const query = buildQueryParams({\n sort: params?.sort ?? \"id:ASC\",\n active: params?.active,\n search: params?.search,\n id_account: id_account,\n });\n const url = `/plans${query ? `?${query}` : \"\"}`;\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan[]>>(url);\n\n if (response.status === 0) {\n throw new ApiError(\n (response as { message?: string }).message || \"Erro ao listar planos\",\n \"LIST_PLANS_FAILED\",\n 400,\n );\n }\n\n const rawData = (response as { data?: unknown }).data;\n const data = Array.isArray(rawData)\n ? rawData.map((item) => PlanSchema.parse(item))\n : [];\n\n await this.cache.insert(cacheKey, JSON.stringify(data), PLANS_CACHE_TTL);\n\n return {\n data,\n total: response.total,\n success: true,\n } satisfies PaginatedSuccessResult<Plan>;\n }\n\n async findById(idPlan: number | string): Promise<SuccessResult<Plan>> {\n const { id_wl, id_account } = await getUserContext();\n const cacheKey = this.buildCacheKey(`plan-${idPlan}-v2`, {\n id_wl,\n id_account: String(id_account),\n });\n\n const cachedData = await this.cache.select(cacheKey);\n\n if (cachedData.status == 1 && \"data\" in cachedData && cachedData.data) {\n const data = JSON.parse(cachedData.data) as Plan;\n return { data, success: true };\n }\n\n const query = buildQueryParams({ type: \"client\", id_account });\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan>>(\n `/plans/${idPlan}?${query}`,\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || \"Erro ao buscar plano\",\n \"FIND_PLAN_FAILED\",\n 400,\n );\n }\n\n if (!response.data?.length) {\n throw new ApiError(\"Plano não encontrado\", \"PLAN_NOT_FOUND\", 404);\n }\n\n const plan = PlanSchema.parse(response.data[0]);\n\n await this.cache.insert(cacheKey, JSON.stringify(plan), PLANS_CACHE_TTL);\n\n return {\n success: true,\n data: plan,\n };\n }\n}\n\nexport const plansService = new PlansService();\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,KAAgB,sBAAsB;AAC/C,SAAS,UAAU,kBAAkB,kBAAkB;AAOvD,OAAO,gBAAgB;AAQvB,MAAM,kBAAkB;AAExB,MAAM,aAAa;AAAA,EACT,QAAQ,IAAI,WAAW;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,QAAQ,IAAI,YAAY;AAAA,EACnC,CAAC;AAAA,EAEO,cAAc,KAAa,QAA0C;AAC3E,UAAM,OAAO,QAAQ,SAAS;AAC9B,UAAM,YAAY,QAAQ,cAAc;AACxC,UAAM,OAAO,QAAQ,QAAQ;AAC7B,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,SAAS,QAAQ,UAAU;AAEjC,WAAO,GAAG,GAAG,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UACJ,QACuC;AACvC,UAAM,EAAE,OAAO,WAAW,IAAI,MAAM,eAAe;AACnD,UAAM,WAAW,KAAK,cAAc,SAAS;AAAA,MAC3C,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,aAAa,MAAM,KAAK,MAAM,OAAO,QAAQ;AAEnD,QAAI,WAAW,UAAU,KAAK,UAAU,cAAc,WAAW,MAAM;AACrE,YAAMA,QAAO,KAAK,MAAM,WAAW,IAAI;AACvC,aAAO,EAAE,MAAAA,OAAM,OAAOA,MAAK,QAAQ,SAAS,KAAK;AAAA,IACnD;AAEA,UAAM,QAAQ,iBAAiB;AAAA,MAC7B,MAAM,QAAQ,QAAQ;AAAA,MACtB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACF,CAAC;AACD,UAAM,MAAM,SAAS,QAAQ,IAAI,KAAK,KAAK,EAAE;AAE7C,UAAM,WAAW,MAAM,IAAI,KAAK,IAAsC,GAAG;AAEzE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACP,SAAkC,WAAW;AAAA,QAC9C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAW,SAAgC;AACjD,UAAM,OAAO,MAAM,QAAQ,OAAO,IAC9B,QAAQ,IAAI,CAAC,SAAS,WAAW,MAAM,IAAI,CAAC,IAC5C,CAAC;AAEL,UAAM,KAAK,MAAM,OAAO,UAAU,KAAK,UAAU,IAAI,GAAG,eAAe;AAEvE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,QAAuD;AACpE,UAAM,EAAE,OAAO,WAAW,IAAI,MAAM,eAAe;AACnD,UAAM,WAAW,KAAK,cAAc,QAAQ,MAAM,OAAO;AAAA,MACvD;AAAA,MACA,YAAY,OAAO,UAAU;AAAA,IAC/B,CAAC;AAED,UAAM,aAAa,MAAM,KAAK,MAAM,OAAO,QAAQ;AAEnD,QAAI,WAAW,UAAU,KAAK,UAAU,cAAc,WAAW,MAAM;AACrE,YAAM,OAAO,KAAK,MAAM,WAAW,IAAI;AACvC,aAAO,EAAE,MAAM,SAAS,KAAK;AAAA,IAC/B;AAEA,UAAM,QAAQ,iBAAiB,EAAE,MAAM,UAAU,WAAW,CAAC;AAE7D,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B,UAAU,MAAM,IAAI,KAAK;AAAA,IAC3B;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM,QAAQ;AAC1B,YAAM,IAAI,SAAS,2BAAwB,kBAAkB,GAAG;AAAA,IAClE;AAEA,UAAM,OAAO,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC;AAE9C,UAAM,KAAK,MAAM,OAAO,UAAU,KAAK,UAAU,IAAI,GAAG,eAAe;AAEvE,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,MAAM,eAAe,IAAI,aAAa;","names":["data"]}
1
+ {"version":3,"sources":["../../../../src/modules/plans/services/plans.service.ts"],"sourcesContent":["import \"server-only\";\n\nimport { api, getUserContext } from \"@greatapps/common/server\";\nimport { ApiError, buildQueryParams, PlanSchema } from \"@greatapps/common\";\nimport type {\n ApiPaginatedActionResult,\n PaginatedSuccessResult,\n Plan,\n SuccessResult,\n} from \"@greatapps/common\";\n\nexport type ListPlansParams = {\n sort?: string;\n active?: boolean;\n search?: string;\n};\n\nclass PlansService {\n /**\n * Lista planos do whitelabel.\n * Exemplo:\n * GET /{id_wl}/plans?active=true&search=client&sort=id:ASC\n */\n async listPlans(\n params?: ListPlansParams,\n ): Promise<PaginatedSuccessResult<Plan>> {\n const { id_account } = await getUserContext();\n\n const query = buildQueryParams({\n sort: params?.sort ?? \"id:ASC\",\n active: params?.active,\n search: params?.search,\n id_account: id_account,\n });\n const url = `/plans${query ? `?${query}` : \"\"}`;\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan[]>>(url);\n\n if (response.status === 0) {\n throw new ApiError(\n (response as { message?: string }).message || \"Erro ao listar planos\",\n \"LIST_PLANS_FAILED\",\n 400,\n );\n }\n\n const rawData = (response as { data?: unknown }).data;\n const data = Array.isArray(rawData)\n ? rawData.map((item) => PlanSchema.parse(item))\n : [];\n\n return {\n data,\n total: response.total,\n success: true,\n } satisfies PaginatedSuccessResult<Plan>;\n }\n\n async findById(idPlan: number | string): Promise<SuccessResult<Plan>> {\n const { id_account } = await getUserContext();\n\n const query = buildQueryParams({ type: \"client\", id_account });\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan>>(\n `/plans/${idPlan}?${query}`,\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || \"Erro ao buscar plano\",\n \"FIND_PLAN_FAILED\",\n 400,\n );\n }\n\n if (!response.data?.length) {\n throw new ApiError(\"Plano não encontrado\", \"PLAN_NOT_FOUND\", 404);\n }\n\n const plan = PlanSchema.parse(response.data[0]);\n\n return {\n success: true,\n data: plan,\n };\n }\n}\n\nexport const plansService = new PlansService();\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,KAAK,sBAAsB;AACpC,SAAS,UAAU,kBAAkB,kBAAkB;AAcvD,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,MAAM,UACJ,QACuC;AACvC,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,QAAQ,iBAAiB;AAAA,MAC7B,MAAM,QAAQ,QAAQ;AAAA,MACtB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACF,CAAC;AACD,UAAM,MAAM,SAAS,QAAQ,IAAI,KAAK,KAAK,EAAE;AAE7C,UAAM,WAAW,MAAM,IAAI,KAAK,IAAsC,GAAG;AAEzE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACP,SAAkC,WAAW;AAAA,QAC9C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAW,SAAgC;AACjD,UAAM,OAAO,MAAM,QAAQ,OAAO,IAC9B,QAAQ,IAAI,CAAC,SAAS,WAAW,MAAM,IAAI,CAAC,IAC5C,CAAC;AAEL,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,QAAuD;AACpE,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,QAAQ,iBAAiB,EAAE,MAAM,UAAU,WAAW,CAAC;AAE7D,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B,UAAU,MAAM,IAAI,KAAK;AAAA,IAC3B;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM,QAAQ;AAC1B,YAAM,IAAI,SAAS,2BAAwB,kBAAkB,GAAG;AAAA,IAClE;AAEA,UAAM,OAAO,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC;AAE9C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,MAAM,eAAe,IAAI,aAAa;","names":[]}
@@ -6,7 +6,7 @@ const PixPendingDataSchema = z.object({
6
6
  expires_at: z.string().nullable().optional()
7
7
  });
8
8
  const SubscriptionPendingPixResponseSchema = z.object({
9
- id: z.null(),
9
+ id: z.union([z.string(), z.null()]).optional(),
10
10
  pending: z.literal(true),
11
11
  payment_method: z.literal(3),
12
12
  pix: PixPendingDataSchema
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/subscriptions/types/pix-pending.type.ts"],"sourcesContent":["import z from \"zod\";\n\n/**\n * Shape efêmero do pix gerado pelo backend quando uma operação de subscription\n * (create ou update com cobrança imediata) produz uma cobrança via pix.\n */\nexport const PixPendingDataSchema = z.object({\n qr_code: z.string().nullable().optional(),\n payment_link: z.string().nullable().optional(),\n correlation_id: z.string(),\n expires_at: z.string().nullable().optional(),\n});\n\nexport type PixPendingData = z.infer<typeof PixPendingDataSchema>;\n\n/**\n * Resposta especial que o backend devolve no lugar da subscription quando\n * a operação dispara um pix pendente. `id: null` + `pending: true` é o sinal\n * de discriminação. Vem com `passthrough()` pra não perder campos extras.\n */\nexport const SubscriptionPendingPixResponseSchema = z\n .object({\n id: z.null(),\n pending: z.literal(true),\n payment_method: z.literal(3),\n pix: PixPendingDataSchema,\n })\n .passthrough();\n\nexport type SubscriptionPendingPixResponse = z.infer<\n typeof SubscriptionPendingPixResponseSchema\n>;\n\nexport function isSubscriptionPendingPixResponse(\n value: unknown,\n): value is SubscriptionPendingPixResponse {\n return SubscriptionPendingPixResponseSchema.safeParse(value).success;\n}\n"],"mappings":"AAAA,OAAO,OAAO;AAMP,MAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACxC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7C,gBAAgB,EAAE,OAAO;AAAA,EACzB,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC7C,CAAC;AASM,MAAM,uCAAuC,EACjD,OAAO;AAAA,EACN,IAAI,EAAE,KAAK;AAAA,EACX,SAAS,EAAE,QAAQ,IAAI;AAAA,EACvB,gBAAgB,EAAE,QAAQ,CAAC;AAAA,EAC3B,KAAK;AACP,CAAC,EACA,YAAY;AAMR,SAAS,iCACd,OACyC;AACzC,SAAO,qCAAqC,UAAU,KAAK,EAAE;AAC/D;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/subscriptions/types/pix-pending.type.ts"],"sourcesContent":["import z from \"zod\";\n\n/**\n * Shape efêmero do pix gerado pelo backend quando uma operação de subscription\n * (create ou update com cobrança imediata) produz uma cobrança via pix.\n */\nexport const PixPendingDataSchema = z.object({\n qr_code: z.string().nullable().optional(),\n payment_link: z.string().nullable().optional(),\n correlation_id: z.string(),\n expires_at: z.string().nullable().optional(),\n});\n\nexport type PixPendingData = z.infer<typeof PixPendingDataSchema>;\n\n/**\n * Resposta especial que o backend devolve no lugar da subscription quando\n * a operação dispara um pix pendente. Discrimina por `pending` + `payment_method`\n * + presença de `pix` — nenhuma subscription real carrega esses três juntos.\n *\n * `id` é aceito como null OU string: as trilhas de pix do backend divergem no\n * campo (a de re-autorização de mandato manda null, a de addons manda o id da\n * invoice Stripe). Exigir null aqui fazia o safeParse falhar nessa segunda, o\n * objeto era reparseado como subscription comum e o `pix` sumia cobrança\n * criada e cliente sem QR (ID-4779).\n */\nexport const SubscriptionPendingPixResponseSchema = z\n .object({\n id: z.union([z.string(), z.null()]).optional(),\n pending: z.literal(true),\n payment_method: z.literal(3),\n pix: PixPendingDataSchema,\n })\n .passthrough();\n\nexport type SubscriptionPendingPixResponse = z.infer<\n typeof SubscriptionPendingPixResponseSchema\n>;\n\nexport function isSubscriptionPendingPixResponse(\n value: unknown,\n): value is SubscriptionPendingPixResponse {\n return SubscriptionPendingPixResponseSchema.safeParse(value).success;\n}\n"],"mappings":"AAAA,OAAO,OAAO;AAMP,MAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACxC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7C,gBAAgB,EAAE,OAAO;AAAA,EACzB,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC7C,CAAC;AAeM,MAAM,uCAAuC,EACjD,OAAO;AAAA,EACN,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA,EAC7C,SAAS,EAAE,QAAQ,IAAI;AAAA,EACvB,gBAAgB,EAAE,QAAQ,CAAC;AAAA,EAC3B,KAAK;AACP,CAAC,EACA,YAAY;AAMR,SAAS,iCACd,OACyC;AACzC,SAAO,qCAAqC,UAAU,KAAK,EAAE;AAC/D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.726",
3
+ "version": "1.1.728",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -46,6 +46,12 @@
46
46
  "dist",
47
47
  "src"
48
48
  ],
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "typecheck": "tsc --noEmit",
53
+ "prepublishOnly": "npm run build"
54
+ },
49
55
  "keywords": [],
50
56
  "author": "",
51
57
  "license": "ISC",
@@ -129,10 +135,5 @@
129
135
  "@faker-js/faker": {
130
136
  "optional": true
131
137
  }
132
- },
133
- "scripts": {
134
- "build": "tsup",
135
- "dev": "tsup --watch",
136
- "typecheck": "tsc --noEmit"
137
138
  }
138
- }
139
+ }
@@ -1,6 +1,6 @@
1
1
  import "server-only";
2
2
 
3
- import { api, apiClient, getUserContext } from "@greatapps/common/server";
3
+ import { api, getUserContext } from "@greatapps/common/server";
4
4
  import { ApiError, buildQueryParams, PlanSchema } from "@greatapps/common";
5
5
  import type {
6
6
  ApiPaginatedActionResult,
@@ -8,7 +8,6 @@ import type {
8
8
  Plan,
9
9
  SuccessResult,
10
10
  } from "@greatapps/common";
11
- import greatCache from "@greatapps/cache";
12
11
 
13
12
  export type ListPlansParams = {
14
13
  sort?: string;
@@ -16,26 +15,7 @@ export type ListPlansParams = {
16
15
  search?: string;
17
16
  };
18
17
 
19
- const PLANS_CACHE_TTL = 604800;
20
-
21
18
  class PlansService {
22
- private cache = new greatCache({
23
- service: "plans",
24
- version: "1.0",
25
- domain: "whitelabel-cache.greatapps.com.br",
26
- ambient: process.env.NODE_ENV || "development",
27
- });
28
-
29
- private buildCacheKey(key: string, params?: Record<string, unknown>): string {
30
- const idWl = params?.id_wl ?? "";
31
- const idAccount = params?.id_account ?? "";
32
- const sort = params?.sort ?? "id:ASC";
33
- const active = params?.active ?? "";
34
- const search = params?.search ?? "";
35
- // v5: itens do plano passaram a carregar o flag `base` (PR #188 da API)
36
- return `${key}-${idWl}-${idAccount}-${sort}-${active}-${search}-v5`;
37
- }
38
-
39
19
  /**
40
20
  * Lista planos do whitelabel.
41
21
  * Exemplo:
@@ -44,19 +24,7 @@ class PlansService {
44
24
  async listPlans(
45
25
  params?: ListPlansParams,
46
26
  ): Promise<PaginatedSuccessResult<Plan>> {
47
- const { id_wl, id_account } = await getUserContext();
48
- const cacheKey = this.buildCacheKey("plans", {
49
- ...params,
50
- id_wl,
51
- id_account,
52
- });
53
-
54
- const cachedData = await this.cache.select(cacheKey);
55
-
56
- if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
57
- const data = JSON.parse(cachedData.data) as Plan[];
58
- return { data, total: data.length, success: true };
59
- }
27
+ const { id_account } = await getUserContext();
60
28
 
61
29
  const query = buildQueryParams({
62
30
  sort: params?.sort ?? "id:ASC",
@@ -81,8 +49,6 @@ class PlansService {
81
49
  ? rawData.map((item) => PlanSchema.parse(item))
82
50
  : [];
83
51
 
84
- await this.cache.insert(cacheKey, JSON.stringify(data), PLANS_CACHE_TTL);
85
-
86
52
  return {
87
53
  data,
88
54
  total: response.total,
@@ -91,18 +57,7 @@ class PlansService {
91
57
  }
92
58
 
93
59
  async findById(idPlan: number | string): Promise<SuccessResult<Plan>> {
94
- const { id_wl, id_account } = await getUserContext();
95
- const cacheKey = this.buildCacheKey(`plan-${idPlan}-v2`, {
96
- id_wl,
97
- id_account: String(id_account),
98
- });
99
-
100
- const cachedData = await this.cache.select(cacheKey);
101
-
102
- if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
103
- const data = JSON.parse(cachedData.data) as Plan;
104
- return { data, success: true };
105
- }
60
+ const { id_account } = await getUserContext();
106
61
 
107
62
  const query = buildQueryParams({ type: "client", id_account });
108
63
 
@@ -124,8 +79,6 @@ class PlansService {
124
79
 
125
80
  const plan = PlanSchema.parse(response.data[0]);
126
81
 
127
- await this.cache.insert(cacheKey, JSON.stringify(plan), PLANS_CACHE_TTL);
128
-
129
82
  return {
130
83
  success: true,
131
84
  data: plan,
@@ -15,12 +15,18 @@ export type PixPendingData = z.infer<typeof PixPendingDataSchema>;
15
15
 
16
16
  /**
17
17
  * Resposta especial que o backend devolve no lugar da subscription quando
18
- * a operação dispara um pix pendente. `id: null` + `pending: true` é o sinal
19
- * de discriminação. Vem com `passthrough()` pra não perder campos extras.
18
+ * a operação dispara um pix pendente. Discrimina por `pending` + `payment_method`
19
+ * + presença de `pix` nenhuma subscription real carrega esses três juntos.
20
+ *
21
+ * `id` é aceito como null OU string: as trilhas de pix do backend divergem no
22
+ * campo (a de re-autorização de mandato manda null, a de addons manda o id da
23
+ * invoice Stripe). Exigir null aqui fazia o safeParse falhar nessa segunda, o
24
+ * objeto era reparseado como subscription comum e o `pix` sumia — cobrança
25
+ * criada e cliente sem QR (ID-4779).
20
26
  */
21
27
  export const SubscriptionPendingPixResponseSchema = z
22
28
  .object({
23
- id: z.null(),
29
+ id: z.union([z.string(), z.null()]).optional(),
24
30
  pending: z.literal(true),
25
31
  payment_method: z.literal(3),
26
32
  pix: PixPendingDataSchema,