@greatapps/common 1.1.774 → 1.1.775
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.
- package/dist/modules/auth/utils/assert-management-permission.mjs +3 -2
- package/dist/modules/auth/utils/assert-management-permission.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-management-subscription.mjs +3 -2
- package/dist/modules/auth/utils/assert-management-subscription.mjs.map +1 -1
- package/package.json +1 -1
- package/src/modules/auth/utils/assert-management-permission.ts +14 -2
- package/src/modules/auth/utils/assert-management-subscription.ts +13 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
+
import { cache } from "react";
|
|
2
3
|
import { UserProfile } from "../../users/schema";
|
|
3
4
|
import { findUserById } from "../../users/action/find-user-by-id.action";
|
|
4
5
|
import { ApiError } from "../../../infra/api/types";
|
|
5
6
|
import { assertManagementSubscription } from "./assert-management-subscription";
|
|
6
|
-
|
|
7
|
+
const getCurrentUserProfile = cache(async () => {
|
|
7
8
|
const result = await findUserById();
|
|
8
9
|
if (!result.success || !result.data) {
|
|
9
10
|
throw new ApiError(
|
|
@@ -13,7 +14,7 @@ async function getCurrentUserProfile() {
|
|
|
13
14
|
);
|
|
14
15
|
}
|
|
15
16
|
return result.data.profile;
|
|
16
|
-
}
|
|
17
|
+
});
|
|
17
18
|
async function assertManagementPermission(permission) {
|
|
18
19
|
const profile = await getCurrentUserProfile();
|
|
19
20
|
switch (permission) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/utils/assert-management-permission.ts"],"sourcesContent":["import 'server-only';\n\nimport { UserProfile } from '../../users/schema';\nimport { findUserById } from '../../users/action/find-user-by-id.action';\nimport { ApiError } from '../../../infra/api/types';\nimport { assertManagementSubscription } from './assert-management-subscription';\nimport type { ManagementPermission } from '../types/management-permission.type';\n\
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/utils/assert-management-permission.ts"],"sourcesContent":["import 'server-only';\n\nimport { cache } from 'react';\n\nimport { UserProfile } from '../../users/schema';\nimport { findUserById } from '../../users/action/find-user-by-id.action';\nimport { ApiError } from '../../../infra/api/types';\nimport { assertManagementSubscription } from './assert-management-subscription';\nimport type { ManagementPermission } from '../types/management-permission.type';\n\n/**\n * Perfil do usuário autenticado, deduplicado por request via React.cache — mesma razão\n * do `requireValidSession`.\n *\n * Este gate abre TODA leitura e escrita gateada, e o perfil não depende da permissão que\n * está sendo checada: uma request que toca N services pagava N round-trips ao backend para\n * reler a mesma linha. Medido em produção (26/08, carregamento da aba de assinatura de uma\n * conta): ~30 GETs de `/accounts/{id}/users/{id}` em 20 s, 200–880 ms cada, competindo pelo\n * mesmo worker de banco que as chamadas de verdade.\n */\nconst getCurrentUserProfile = cache(async () => {\n const result = await findUserById();\n\n if (!result.success || !result.data) {\n throw new ApiError(\n ('error' in result && result.error) || 'Não foi possível identificar o usuário autenticado',\n 'USER_CONTEXT_FAILED',\n 403\n );\n }\n\n return result.data.profile;\n});\n\nexport async function assertManagementPermission(permission: ManagementPermission) {\n const profile = await getCurrentUserProfile();\n\n switch (permission) {\n case 'manage_pages':\n case 'manage_redirects':\n case 'manage_domains':\n case 'manage_ab_tests':\n case 'restore_pages':\n case 'create_pages':\n case 'update_pages':\n case 'delete_pages':\n if (profile === UserProfile.viewer) {\n throw new ApiError('Você não tem permissão para executar esta ação', 'FORBIDDEN', 403);\n }\n break;\n case 'manage_projects':\n case 'delete_leads':\n case 'view_cards':\n case 'manage_cards':\n case 'manage_subscriptions':\n if (profile !== UserProfile.owner && profile !== UserProfile.admin) {\n throw new ApiError('Você não tem permissão para executar esta ação', 'FORBIDDEN', 403);\n }\n break;\n default:\n throw new ApiError('Permissão inválida', 'INVALID_PERMISSION', 500);\n }\n\n const skipSubscriptionCheck: ManagementPermission[] = ['manage_subscriptions', 'manage_cards', 'view_cards'];\n if (!skipSubscriptionCheck.includes(permission)) {\n await assertManagementSubscription();\n }\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,aAAa;AAEtB,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,oCAAoC;AAa7C,MAAM,wBAAwB,MAAM,YAAY;AAC9C,QAAM,SAAS,MAAM,aAAa;AAElC,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,MAAM;AACnC,UAAM,IAAI;AAAA,MACP,WAAW,UAAU,OAAO,SAAU;AAAA,MACvC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,KAAK;AACrB,CAAC;AAED,eAAsB,2BAA2B,YAAkC;AACjF,QAAM,UAAU,MAAM,sBAAsB;AAE5C,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,UAAI,YAAY,YAAY,QAAQ;AAClC,cAAM,IAAI,SAAS,iEAAkD,aAAa,GAAG;AAAA,MACvF;AACA;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,UAAI,YAAY,YAAY,SAAS,YAAY,YAAY,OAAO;AAClE,cAAM,IAAI,SAAS,iEAAkD,aAAa,GAAG;AAAA,MACvF;AACA;AAAA,IACF;AACE,YAAM,IAAI,SAAS,4BAAsB,sBAAsB,GAAG;AAAA,EACtE;AAEA,QAAM,wBAAgD,CAAC,wBAAwB,gBAAgB,YAAY;AAC3G,MAAI,CAAC,sBAAsB,SAAS,UAAU,GAAG;AAC/C,UAAM,6BAA6B;AAAA,EACrC;AACF;","names":[]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
+
import { cache } from "react";
|
|
2
3
|
import { ApiError } from "../../../infra/api/types";
|
|
3
4
|
import { listSubscriptionsAction } from "../../subscriptions/actions/list-subscriptions.action";
|
|
4
5
|
import { getSubscriptionExpiryDate } from "../../subscriptions/utils/get-subscription-expiry-date";
|
|
5
|
-
|
|
6
|
+
const assertManagementSubscription = cache(async () => {
|
|
6
7
|
const result = await listSubscriptionsAction({ active: true });
|
|
7
8
|
if (!result.success) {
|
|
8
9
|
throw new ApiError(
|
|
@@ -28,7 +29,7 @@ async function assertManagementSubscription() {
|
|
|
28
29
|
403
|
|
29
30
|
);
|
|
30
31
|
}
|
|
31
|
-
}
|
|
32
|
+
});
|
|
32
33
|
export {
|
|
33
34
|
assertManagementSubscription
|
|
34
35
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/utils/assert-management-subscription.ts"],"sourcesContent":["import \"server-only\";\n\nimport { ApiError } from \"../../../infra/api/types\";\nimport { listSubscriptionsAction } from \"../../subscriptions/actions/list-subscriptions.action\";\nimport { getSubscriptionExpiryDate } from \"../../subscriptions/utils/get-subscription-expiry-date\";\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/utils/assert-management-subscription.ts"],"sourcesContent":["import \"server-only\";\n\nimport { cache } from \"react\";\n\nimport { ApiError } from \"../../../infra/api/types\";\nimport { listSubscriptionsAction } from \"../../subscriptions/actions/list-subscriptions.action\";\nimport { getSubscriptionExpiryDate } from \"../../subscriptions/utils/get-subscription-expiry-date\";\n\n/**\n * Deduplicado por request via React.cache, como `getCurrentUserProfile` e `requireValidSession`.\n *\n * A leitura por trás é `/accounts/{id}/subscriptions?limit=1`, e ela é MAIS cara que o gate de\n * perfil: para conta Stripe a listagem consulta a API do gateway ao vivo. Em produção (26/08) o\n * mesmo carregamento disparou quatro dessas em paralelo — 727 ms, 4,2 s, 5,0 s e 7,0 s, contra um\n * p50 de 528 ms para o endpoint. Elas se atrasam entre si: são cópias da mesma pergunta disputando\n * a mesma fila.\n */\nexport const assertManagementSubscription = cache(async () => {\n const result = await listSubscriptionsAction({ active: true });\n\n if (!result.success) {\n throw new ApiError(\n result.error || \"Não foi possível validar a assinatura atual\",\n \"SUBSCRIPTION_CONTEXT_FAILED\",\n 403,\n );\n }\n\n const subscription = result.data?.data?.[0];\n\n if (!subscription) {\n throw new ApiError(\n \"Nenhuma assinatura ativa encontrada. Assine um plano para continuar.\",\n \"SUBSCRIPTION_NOT_FOUND\",\n 403,\n );\n }\n\n const expiryDate = getSubscriptionExpiryDate(subscription);\n const isExpired = !!expiryDate && Date.now() >= expiryDate.getTime();\n\n if (isExpired) {\n throw new ApiError(\n \"Sua assinatura está vencida. Assine um novo plano para continuar.\",\n \"SUBSCRIPTION_EXPIRED\",\n 403,\n );\n }\n});\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,aAAa;AAEtB,SAAS,gBAAgB;AACzB,SAAS,+BAA+B;AACxC,SAAS,iCAAiC;AAWnC,MAAM,+BAA+B,MAAM,YAAY;AAC5D,QAAM,SAAS,MAAM,wBAAwB,EAAE,QAAQ,KAAK,CAAC;AAE7D,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR,OAAO,SAAS;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,MAAM,OAAO,CAAC;AAE1C,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,0BAA0B,YAAY;AACzD,QAAM,YAAY,CAAC,CAAC,cAAc,KAAK,IAAI,KAAK,WAAW,QAAQ;AAEnE,MAAI,WAAW;AACb,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF,CAAC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
|
|
3
|
+
import { cache } from 'react';
|
|
4
|
+
|
|
3
5
|
import { UserProfile } from '../../users/schema';
|
|
4
6
|
import { findUserById } from '../../users/action/find-user-by-id.action';
|
|
5
7
|
import { ApiError } from '../../../infra/api/types';
|
|
6
8
|
import { assertManagementSubscription } from './assert-management-subscription';
|
|
7
9
|
import type { ManagementPermission } from '../types/management-permission.type';
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Perfil do usuário autenticado, deduplicado por request via React.cache — mesma razão
|
|
13
|
+
* do `requireValidSession`.
|
|
14
|
+
*
|
|
15
|
+
* Este gate abre TODA leitura e escrita gateada, e o perfil não depende da permissão que
|
|
16
|
+
* está sendo checada: uma request que toca N services pagava N round-trips ao backend para
|
|
17
|
+
* reler a mesma linha. Medido em produção (26/08, carregamento da aba de assinatura de uma
|
|
18
|
+
* conta): ~30 GETs de `/accounts/{id}/users/{id}` em 20 s, 200–880 ms cada, competindo pelo
|
|
19
|
+
* mesmo worker de banco que as chamadas de verdade.
|
|
20
|
+
*/
|
|
21
|
+
const getCurrentUserProfile = cache(async () => {
|
|
10
22
|
const result = await findUserById();
|
|
11
23
|
|
|
12
24
|
if (!result.success || !result.data) {
|
|
@@ -18,7 +30,7 @@ async function getCurrentUserProfile() {
|
|
|
18
30
|
}
|
|
19
31
|
|
|
20
32
|
return result.data.profile;
|
|
21
|
-
}
|
|
33
|
+
});
|
|
22
34
|
|
|
23
35
|
export async function assertManagementPermission(permission: ManagementPermission) {
|
|
24
36
|
const profile = await getCurrentUserProfile();
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
|
|
3
|
+
import { cache } from "react";
|
|
4
|
+
|
|
3
5
|
import { ApiError } from "../../../infra/api/types";
|
|
4
6
|
import { listSubscriptionsAction } from "../../subscriptions/actions/list-subscriptions.action";
|
|
5
7
|
import { getSubscriptionExpiryDate } from "../../subscriptions/utils/get-subscription-expiry-date";
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Deduplicado por request via React.cache, como `getCurrentUserProfile` e `requireValidSession`.
|
|
11
|
+
*
|
|
12
|
+
* A leitura por trás é `/accounts/{id}/subscriptions?limit=1`, e ela é MAIS cara que o gate de
|
|
13
|
+
* perfil: para conta Stripe a listagem consulta a API do gateway ao vivo. Em produção (26/08) o
|
|
14
|
+
* mesmo carregamento disparou quatro dessas em paralelo — 727 ms, 4,2 s, 5,0 s e 7,0 s, contra um
|
|
15
|
+
* p50 de 528 ms para o endpoint. Elas se atrasam entre si: são cópias da mesma pergunta disputando
|
|
16
|
+
* a mesma fila.
|
|
17
|
+
*/
|
|
18
|
+
export const assertManagementSubscription = cache(async () => {
|
|
8
19
|
const result = await listSubscriptionsAction({ active: true });
|
|
9
20
|
|
|
10
21
|
if (!result.success) {
|
|
@@ -35,4 +46,4 @@ export async function assertManagementSubscription() {
|
|
|
35
46
|
403,
|
|
36
47
|
);
|
|
37
48
|
}
|
|
38
|
-
}
|
|
49
|
+
});
|