@eva_solutions/auth-sdk 0.0.0-stage → 3.0.0-dev-20261109133200
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/CHANGELOG.md +290 -0
- package/LICENSE +21 -0
- package/README.md +481 -2
- package/dist/admin/index.cjs +4 -0
- package/dist/admin/index.d.cts +2 -0
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.js +1 -0
- package/dist/admin-DjvuvuI8.js +408 -0
- package/dist/admin-DjvuvuI8.js.map +1 -0
- package/dist/admin-Q6lbWqLM.cjs +419 -0
- package/dist/admin-Q6lbWqLM.cjs.map +1 -0
- package/dist/api-path-2Ulruz7R.cjs +34 -0
- package/dist/api-path-2Ulruz7R.cjs.map +1 -0
- package/dist/api-path-B-vSkL2H.js +29 -0
- package/dist/api-path-B-vSkL2H.js.map +1 -0
- package/dist/auth-19r-Q6X2.js +84 -0
- package/dist/auth-19r-Q6X2.js.map +1 -0
- package/dist/auth-DX1N5JA4.cjs +131 -0
- package/dist/auth-DX1N5JA4.cjs.map +1 -0
- package/dist/auth-handlers-B3iJaPln.js +343 -0
- package/dist/auth-handlers-B3iJaPln.js.map +1 -0
- package/dist/auth-handlers-BTbXKJms.d.ts +15 -0
- package/dist/auth-handlers-BTbXKJms.d.ts.map +1 -0
- package/dist/auth-handlers-CDzGFDTu.cjs +404 -0
- package/dist/auth-handlers-CDzGFDTu.cjs.map +1 -0
- package/dist/auth-handlers-DRUUTEtW.d.cts +15 -0
- package/dist/auth-handlers-DRUUTEtW.d.cts.map +1 -0
- package/dist/catalog-CHPqldcj.cjs +172 -0
- package/dist/catalog-CHPqldcj.cjs.map +1 -0
- package/dist/catalog-CIqpzgsM.d.cts +75 -0
- package/dist/catalog-CIqpzgsM.d.cts.map +1 -0
- package/dist/catalog-CIqpzgsM.d.ts +75 -0
- package/dist/catalog-CIqpzgsM.d.ts.map +1 -0
- package/dist/catalog-DqPhtCKZ.js +95 -0
- package/dist/catalog-DqPhtCKZ.js.map +1 -0
- package/dist/config-3avoUa9e.d.cts +95 -0
- package/dist/config-3avoUa9e.d.cts.map +1 -0
- package/dist/config-COX7rGAP.d.ts +95 -0
- package/dist/config-COX7rGAP.d.ts.map +1 -0
- package/dist/constants-BE1_9Tod.cjs +52 -0
- package/dist/constants-BE1_9Tod.cjs.map +1 -0
- package/dist/constants-BY7QZokc.js +29 -0
- package/dist/constants-BY7QZokc.js.map +1 -0
- package/dist/constants-CcbhOaAP.cjs +153 -0
- package/dist/constants-CcbhOaAP.cjs.map +1 -0
- package/dist/constants-rNuD5qJn.js +94 -0
- package/dist/constants-rNuD5qJn.js.map +1 -0
- package/dist/contracts/index.cjs +1006 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +488 -0
- package/dist/contracts/index.d.cts.map +1 -0
- package/dist/contracts/index.d.ts +488 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +817 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/cookies-DCIcr7uy.cjs +94 -0
- package/dist/cookies-DCIcr7uy.cjs.map +1 -0
- package/dist/cookies-DKEC7AWv.js +71 -0
- package/dist/cookies-DKEC7AWv.js.map +1 -0
- package/dist/delegated-token-CVNbMNfy.js +426 -0
- package/dist/delegated-token-CVNbMNfy.js.map +1 -0
- package/dist/delegated-token-DHSK4rHI.cjs +461 -0
- package/dist/delegated-token-DHSK4rHI.cjs.map +1 -0
- package/dist/error-helpers-0woh13Wd.d.cts +105 -0
- package/dist/error-helpers-0woh13Wd.d.cts.map +1 -0
- package/dist/error-helpers-Ct3AUK1I.d.ts +105 -0
- package/dist/error-helpers-Ct3AUK1I.d.ts.map +1 -0
- package/dist/error-helpers-XCh4ZJ-g.cjs +282 -0
- package/dist/error-helpers-XCh4ZJ-g.cjs.map +1 -0
- package/dist/error-helpers-lnwgNOw9.js +145 -0
- package/dist/error-helpers-lnwgNOw9.js.map +1 -0
- package/dist/error-messages-CGpW1fsg.d.cts +48 -0
- package/dist/error-messages-CGpW1fsg.d.cts.map +1 -0
- package/dist/error-messages-CGpW1fsg.d.ts +48 -0
- package/dist/error-messages-CGpW1fsg.d.ts.map +1 -0
- package/dist/event-codes-BBJHon-I.cjs +48 -0
- package/dist/event-codes-BBJHon-I.cjs.map +1 -0
- package/dist/event-codes-BgcJWsov.d.cts +42 -0
- package/dist/event-codes-BgcJWsov.d.cts.map +1 -0
- package/dist/event-codes-BgcJWsov.d.ts +42 -0
- package/dist/event-codes-BgcJWsov.d.ts.map +1 -0
- package/dist/event-codes-DR5_VlaR.js +43 -0
- package/dist/event-codes-DR5_VlaR.js.map +1 -0
- package/dist/generic/index.cjs +91 -0
- package/dist/generic/index.cjs.map +1 -0
- package/dist/generic/index.d.cts +27 -0
- package/dist/generic/index.d.cts.map +1 -0
- package/dist/generic/index.d.ts +27 -0
- package/dist/generic/index.d.ts.map +1 -0
- package/dist/generic/index.js +80 -0
- package/dist/generic/index.js.map +1 -0
- package/dist/hono/index.cjs +309 -0
- package/dist/hono/index.cjs.map +1 -0
- package/dist/hono/index.d.cts +272 -0
- package/dist/hono/index.d.cts.map +1 -0
- package/dist/hono/index.d.ts +272 -0
- package/dist/hono/index.d.ts.map +1 -0
- package/dist/hono/index.js +290 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/hono-openapi/index.cjs +326 -0
- package/dist/hono-openapi/index.cjs.map +1 -0
- package/dist/hono-openapi/index.d.cts +14 -0
- package/dist/hono-openapi/index.d.cts.map +1 -0
- package/dist/hono-openapi/index.d.ts +14 -0
- package/dist/hono-openapi/index.d.ts.map +1 -0
- package/dist/hono-openapi/index.js +307 -0
- package/dist/hono-openapi/index.js.map +1 -0
- package/dist/http-client-BVF3iktR.cjs +211 -0
- package/dist/http-client-BVF3iktR.cjs.map +1 -0
- package/dist/http-client-Da0-OMfc.js +206 -0
- package/dist/http-client-Da0-OMfc.js.map +1 -0
- package/dist/index-CIH_2t7Y.d.ts +240 -0
- package/dist/index-CIH_2t7Y.d.ts.map +1 -0
- package/dist/index-CZru7c5T.d.cts +1711 -0
- package/dist/index-CZru7c5T.d.cts.map +1 -0
- package/dist/index-CZru7c5T.d.ts +1711 -0
- package/dist/index-CZru7c5T.d.ts.map +1 -0
- package/dist/index-DMVe5IJA.d.cts +240 -0
- package/dist/index-DMVe5IJA.d.cts.map +1 -0
- package/dist/index-DRWKobSp.d.ts +312 -0
- package/dist/index-DRWKobSp.d.ts.map +1 -0
- package/dist/index-DU9wJ-P2.d.cts +312 -0
- package/dist/index-DU9wJ-P2.d.cts.map +1 -0
- package/dist/index-DbiXllNy.d.cts +66 -0
- package/dist/index-DbiXllNy.d.cts.map +1 -0
- package/dist/index-z9r98qlk.d.ts +66 -0
- package/dist/index-z9r98qlk.d.ts.map +1 -0
- package/dist/index.cjs +89 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +114 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt-BBNqk0TV.cjs +155 -0
- package/dist/jwt-BBNqk0TV.cjs.map +1 -0
- package/dist/jwt-DhqgH94B.js +150 -0
- package/dist/jwt-DhqgH94B.js.map +1 -0
- package/dist/key-resolver-CESqj4-P.cjs +45 -0
- package/dist/key-resolver-CESqj4-P.cjs.map +1 -0
- package/dist/key-resolver-D56I2Zpz.js +34 -0
- package/dist/key-resolver-D56I2Zpz.js.map +1 -0
- package/dist/parse-error-response-6qOQS5y9.cjs +316 -0
- package/dist/parse-error-response-6qOQS5y9.cjs.map +1 -0
- package/dist/parse-error-response-BM9-kjs0.js +239 -0
- package/dist/parse-error-response-BM9-kjs0.js.map +1 -0
- package/dist/path-segment-C25i6aaH.cjs +29 -0
- package/dist/path-segment-C25i6aaH.cjs.map +1 -0
- package/dist/path-segment-CyqnaFrP.js +24 -0
- package/dist/path-segment-CyqnaFrP.js.map +1 -0
- package/dist/react/index.cjs +336 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +151 -0
- package/dist/react/index.d.cts.map +1 -0
- package/dist/react/index.d.ts +151 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +300 -0
- package/dist/react/index.js.map +1 -0
- package/dist/refresh-dedup-CKaHHe7m.js +14 -0
- package/dist/refresh-dedup-CKaHHe7m.js.map +1 -0
- package/dist/refresh-dedup-CLdACQXR.cjs +19 -0
- package/dist/refresh-dedup-CLdACQXR.cjs.map +1 -0
- package/dist/rolldown-runtime-CmQyd0Gu.cjs +27 -0
- package/dist/routes-DpAzgY1V.cjs +424 -0
- package/dist/routes-DpAzgY1V.cjs.map +1 -0
- package/dist/routes-F1g5aVqP.js +347 -0
- package/dist/routes-F1g5aVqP.js.map +1 -0
- package/dist/s2s/index.cjs +24 -0
- package/dist/s2s/index.d.cts +5 -0
- package/dist/s2s/index.d.ts +5 -0
- package/dist/s2s/index.js +5 -0
- package/dist/s2s-6wbotr78.cjs +926 -0
- package/dist/s2s-6wbotr78.cjs.map +1 -0
- package/dist/s2s-B_0SIQzn.js +897 -0
- package/dist/s2s-B_0SIQzn.js.map +1 -0
- package/dist/sign-C7y6xdvT.cjs +324 -0
- package/dist/sign-C7y6xdvT.cjs.map +1 -0
- package/dist/sign-HFtcYwa-.js +259 -0
- package/dist/sign-HFtcYwa-.js.map +1 -0
- package/dist/tokens-C1nzkn21.cjs +232 -0
- package/dist/tokens-C1nzkn21.cjs.map +1 -0
- package/dist/tokens-C3Z40qd7.js +107 -0
- package/dist/tokens-C3Z40qd7.js.map +1 -0
- package/dist/types-Ai3iIFlB.d.cts +538 -0
- package/dist/types-Ai3iIFlB.d.cts.map +1 -0
- package/dist/types-Bxg4hCMc.d.cts +52 -0
- package/dist/types-Bxg4hCMc.d.cts.map +1 -0
- package/dist/types-CEABh1Zf.d.ts +96 -0
- package/dist/types-CEABh1Zf.d.ts.map +1 -0
- package/dist/types-Ci0Jq0xB.d.cts +96 -0
- package/dist/types-Ci0Jq0xB.d.cts.map +1 -0
- package/dist/types-DXg8BvEh.d.ts +52 -0
- package/dist/types-DXg8BvEh.d.ts.map +1 -0
- package/dist/types-_zY7QbM5.d.ts +538 -0
- package/dist/types-_zY7QbM5.d.ts.map +1 -0
- package/dist/webhooks/index.cjs +8 -0
- package/dist/webhooks/index.d.cts +5 -0
- package/dist/webhooks/index.d.ts +5 -0
- package/dist/webhooks/index.js +4 -0
- package/dist/webhooks-B5sAWC9W.js +74 -0
- package/dist/webhooks-B5sAWC9W.js.map +1 -0
- package/dist/webhooks-Cx11psg1.cjs +79 -0
- package/dist/webhooks-Cx11psg1.cjs.map +1 -0
- package/package.json +192 -3
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-CmQyd0Gu.cjs");
|
|
2
|
+
const require_http_client = require("./http-client-BVF3iktR.cjs");
|
|
3
|
+
const require_cookies = require("./cookies-DCIcr7uy.cjs");
|
|
4
|
+
const require_refresh_dedup = require("./refresh-dedup-CLdACQXR.cjs");
|
|
5
|
+
const require_parse_error_response = require("./parse-error-response-6qOQS5y9.cjs");
|
|
6
|
+
const require_auth = require("./auth-DX1N5JA4.cjs");
|
|
7
|
+
let zod = require("zod");
|
|
8
|
+
let bowser = require("bowser");
|
|
9
|
+
bowser = require_rolldown_runtime.__toESM(bowser, 1);
|
|
10
|
+
// src/hono/device-info.ts
|
|
11
|
+
function parseDeviceInfo(request) {
|
|
12
|
+
const userAgent = request.headers.get("user-agent") || "";
|
|
13
|
+
const parsed = bowser.default.parse(userAgent);
|
|
14
|
+
return {
|
|
15
|
+
deviceType: parsed.platform?.type || "desktop",
|
|
16
|
+
os: parsed.os?.name || "Unknown",
|
|
17
|
+
browser: parsed.browser?.name || "Unknown",
|
|
18
|
+
userAgent: userAgent.slice(0, 500)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// src/schemas.ts
|
|
22
|
+
/**
|
|
23
|
+
* Schemas Zod 4 compartidos — fuente canónica (B1 confirmado por T-00 probe).
|
|
24
|
+
* Usados por auth-handlers.ts (validación runtime) y hono-openapi/index.ts (OpenAPI doc).
|
|
25
|
+
* Importar desde aquí evita duplicación y garantiza consistencia entre variantes.
|
|
26
|
+
*
|
|
27
|
+
* `parseErrorResponse` vive en `parse-error-response.ts` (módulo puro, D-35): este archivo no es
|
|
28
|
+
* alcanzable desde `src/react/index.ts`.
|
|
29
|
+
*/
|
|
30
|
+
const GetCodeSchema = zod.z.object({ phone: zod.z.string().min(1) });
|
|
31
|
+
/**
|
|
32
|
+
* Cuerpo de POST /login. `challengeId` es el identificador opaco que devolvió
|
|
33
|
+
* POST /get-code para este código: el navegador lo conserva en memoria y lo
|
|
34
|
+
* reenvía junto con el código. Sin él, /login responde 400 (`malformed`).
|
|
35
|
+
*/
|
|
36
|
+
const LoginSchema = zod.z.object({
|
|
37
|
+
phone: zod.z.string().min(1),
|
|
38
|
+
code: zod.z.string().min(1),
|
|
39
|
+
challengeId: zod.z.string().min(1),
|
|
40
|
+
empresaId: zod.z.string().min(1).optional()
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Cuerpo de POST /empresa-activa: el id de la empresa que queda activa o `null` para ninguna.
|
|
44
|
+
* El campo es obligatorio (un body `{}` es inválido): `null` es una decisión, no un faltante.
|
|
45
|
+
*/
|
|
46
|
+
const ActiveEmpresaSchema = zod.z.object({ empresaId: zod.z.string().min(1).nullable() });
|
|
47
|
+
/**
|
|
48
|
+
* Schema para PATCH /me — record no vacío.
|
|
49
|
+
* Validación extra con .refine() para rechazar body vacío.
|
|
50
|
+
*/
|
|
51
|
+
const UpdateUserSchema = zod.z.record(zod.z.string(), zod.z.unknown()).refine((obj) => Object.keys(obj).length > 0, "Cuerpo de actualización vacío");
|
|
52
|
+
/** Wire de error `{ error: { code, message } }` (componente `ErrorBody`). */
|
|
53
|
+
const ErrorResponseSchema = require_auth.errorResponseSchema;
|
|
54
|
+
/** Wire de POST /login/get-code (200). `challengeId` es opaco; cada get-code nuevo invalida el anterior. */
|
|
55
|
+
const GetCodeResponseSchema = require_auth.getCodeResponseSchema;
|
|
56
|
+
/** Wire de POST /login (200). */
|
|
57
|
+
const LoginResponseSchema = require_auth.loginResponseSchema;
|
|
58
|
+
/** Wire de POST /login/refresh (200): el contrato reutiliza la respuesta de login. */
|
|
59
|
+
const RefreshResponseSchema = require_auth.loginResponseSchema;
|
|
60
|
+
// src/auth-handlers.ts
|
|
61
|
+
const KNOWN_ERROR_STATUSES = /* @__PURE__ */ new Set([
|
|
62
|
+
400,
|
|
63
|
+
401,
|
|
64
|
+
403,
|
|
65
|
+
404,
|
|
66
|
+
409,
|
|
67
|
+
429,
|
|
68
|
+
500,
|
|
69
|
+
502,
|
|
70
|
+
503
|
|
71
|
+
]);
|
|
72
|
+
const REASON_TO_CODE = {
|
|
73
|
+
auth_required: "unauthorized",
|
|
74
|
+
token_invalid: "unauthorized",
|
|
75
|
+
refresh_no_tokens: "unauthorized",
|
|
76
|
+
verify_failed: "unauthorized",
|
|
77
|
+
network: "service_unavailable",
|
|
78
|
+
malformed: "bad_request"
|
|
79
|
+
};
|
|
80
|
+
function resolveCode(evaError) {
|
|
81
|
+
if (evaError.kind === "api") return evaError.code;
|
|
82
|
+
return REASON_TO_CODE[evaError.reason];
|
|
83
|
+
}
|
|
84
|
+
function errorResponse(c, evaError, status) {
|
|
85
|
+
const safeStatus = KNOWN_ERROR_STATUSES.has(status) ? status : 500;
|
|
86
|
+
if (require_parse_error_response.getErrorWire() === "api") return c.json({ error: {
|
|
87
|
+
code: resolveCode(evaError),
|
|
88
|
+
message: evaError.message
|
|
89
|
+
} }, safeStatus);
|
|
90
|
+
return c.json({ error: evaError.message }, safeStatus);
|
|
91
|
+
}
|
|
92
|
+
const SAFE_METHODS = /* @__PURE__ */ new Set([
|
|
93
|
+
"GET",
|
|
94
|
+
"HEAD",
|
|
95
|
+
"OPTIONS"
|
|
96
|
+
]);
|
|
97
|
+
/**
|
|
98
|
+
* Origen serializado de un esquema que no es http(s) (`tauri://localhost`, `capacitor://localhost`):
|
|
99
|
+
* `esquema://host[:puerto]` sin userinfo, path, query ni fragmento (una `/` final se tolera).
|
|
100
|
+
*/
|
|
101
|
+
const CUSTOM_SCHEME_ORIGIN = /^([a-z][a-z0-9+.-]*):\/\/([^\s/?#@\\]+)\/?$/i;
|
|
102
|
+
/**
|
|
103
|
+
* `new URL(...).origin` de un esquema no especial es `"null"`, así que http(s) se normaliza con el
|
|
104
|
+
* parser y el resto se compara por su forma serializada en minúsculas (la que manda el navegador).
|
|
105
|
+
*/
|
|
106
|
+
function normalizeAllowedOrigins(origins) {
|
|
107
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
108
|
+
for (const entry of origins) {
|
|
109
|
+
let url;
|
|
110
|
+
try {
|
|
111
|
+
url = new URL(entry);
|
|
112
|
+
} catch {}
|
|
113
|
+
const custom = url !== void 0 && !/^https?:$/.test(url.protocol) ? CUSTOM_SCHEME_ORIGIN.exec(entry) : null;
|
|
114
|
+
if (url === void 0 || custom === null && !/^https?:$/.test(url.protocol)) throw new Error(`[eva-auth-sdk] allowedOrigins inválido: ${JSON.stringify(entry)} (se espera un origen serializado esquema://host[:puerto], p. ej. https://app.example.com o tauri://localhost)`);
|
|
115
|
+
normalized.add(custom === null ? url.origin : `${custom[1].toLowerCase()}://${custom[2].toLowerCase()}`);
|
|
116
|
+
}
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Mismo origen = mismo host:puerto que la request; el esquema no cuenta porque tras un proxy que
|
|
121
|
+
* termina TLS el servidor ve `http://` mientras el navegador manda `https://`.
|
|
122
|
+
*/
|
|
123
|
+
function isOriginAllowed(origin, requestUrl, allowed) {
|
|
124
|
+
let parsed;
|
|
125
|
+
try {
|
|
126
|
+
parsed = new URL(origin);
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return allowed.has(parsed.origin) || allowed.has(origin.toLowerCase()) || parsed.host === new URL(requestUrl).host;
|
|
131
|
+
}
|
|
132
|
+
function sdkError(reason, message, status) {
|
|
133
|
+
return {
|
|
134
|
+
kind: "sdk",
|
|
135
|
+
reason,
|
|
136
|
+
message,
|
|
137
|
+
status
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Construye los 12 handlers de auth con las opciones provistas.
|
|
142
|
+
* Validación temprana de errorMessages si se proveen (lanza si key inválida o valor no-string).
|
|
143
|
+
*
|
|
144
|
+
* Decisión M2 (ADR-012): messages() se resuelve por-request (closure evalúa
|
|
145
|
+
* getErrorMessages() en cada llamada). Permite que configureEvaAuth() post-factory
|
|
146
|
+
* tome efecto en el siguiente request. Tradeoff: ~3 spreads + 2 fn calls per request.
|
|
147
|
+
*/
|
|
148
|
+
function buildAuthHandlers(opts = {}) {
|
|
149
|
+
if (opts.errorMessages !== void 0) require_parse_error_response.validateErrorMessagesInput(opts.errorMessages);
|
|
150
|
+
const allowedOrigins = normalizeAllowedOrigins(opts.allowedOrigins ?? []);
|
|
151
|
+
const client = require_http_client.createHttpClient();
|
|
152
|
+
const messages = () => require_parse_error_response.resolveErrorMessages(opts.errorMessages, require_parse_error_response.getErrorMessages());
|
|
153
|
+
const bodyGuard = (invalidMessage) => ({
|
|
154
|
+
middleware: async (c, next) => {
|
|
155
|
+
c.header("Cache-Control", "no-store");
|
|
156
|
+
try {
|
|
157
|
+
await c.req.json();
|
|
158
|
+
} catch {
|
|
159
|
+
return errorResponse(c, sdkError("malformed", messages().invalidJsonBody, 400), 400);
|
|
160
|
+
}
|
|
161
|
+
await next();
|
|
162
|
+
},
|
|
163
|
+
onInvalid: (result, c) => {
|
|
164
|
+
if (result.success) return void 0;
|
|
165
|
+
c.header("Cache-Control", "no-store");
|
|
166
|
+
return errorResponse(c, sdkError("malformed", invalidMessage(), 400), 400);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const originGuard = async (c, next) => {
|
|
170
|
+
const origin = c.req.header("origin");
|
|
171
|
+
if (SAFE_METHODS.has(c.req.method) || origin === void 0 || isOriginAllowed(origin, c.req.url, allowedOrigins)) return next();
|
|
172
|
+
return errorResponse(c, {
|
|
173
|
+
kind: "api",
|
|
174
|
+
code: "forbidden",
|
|
175
|
+
message: messages().originNotAllowed,
|
|
176
|
+
status: 403
|
|
177
|
+
}, 403);
|
|
178
|
+
};
|
|
179
|
+
return {
|
|
180
|
+
originGuard,
|
|
181
|
+
openApiGuards: {
|
|
182
|
+
getCode: bodyGuard(() => messages().invalidPhone),
|
|
183
|
+
login: bodyGuard(() => messages().loginFailed)
|
|
184
|
+
},
|
|
185
|
+
getCode: async (c) => {
|
|
186
|
+
c.header("Cache-Control", "no-store");
|
|
187
|
+
let raw;
|
|
188
|
+
try {
|
|
189
|
+
raw = await c.req.json();
|
|
190
|
+
} catch {
|
|
191
|
+
return errorResponse(c, sdkError("malformed", messages().invalidJsonBody, 400), 400);
|
|
192
|
+
}
|
|
193
|
+
const parsed = GetCodeSchema.safeParse(raw);
|
|
194
|
+
if (!parsed.success) return errorResponse(c, sdkError("malformed", messages().invalidPhone, 400), 400);
|
|
195
|
+
const result = await client.getCode(parsed.data);
|
|
196
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
197
|
+
return c.json({ data: result.data });
|
|
198
|
+
},
|
|
199
|
+
login: async (c) => {
|
|
200
|
+
c.header("Cache-Control", "no-store");
|
|
201
|
+
let raw;
|
|
202
|
+
try {
|
|
203
|
+
raw = await c.req.json();
|
|
204
|
+
} catch {
|
|
205
|
+
return errorResponse(c, sdkError("malformed", messages().invalidJsonBody, 400), 400);
|
|
206
|
+
}
|
|
207
|
+
const parsed = LoginSchema.safeParse(raw);
|
|
208
|
+
if (!parsed.success) return errorResponse(c, sdkError("malformed", messages().loginFailed, 400), 400);
|
|
209
|
+
const deviceInfo = parseDeviceInfo(c.req.raw);
|
|
210
|
+
const result = await client.login({
|
|
211
|
+
...parsed.data,
|
|
212
|
+
...deviceInfo
|
|
213
|
+
});
|
|
214
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
215
|
+
if (result.data.tokens) {
|
|
216
|
+
const cookieHeaders = require_cookies.setTokenCookies(result.data.tokens);
|
|
217
|
+
for (const cookie of cookieHeaders) c.header("Set-Cookie", cookie, { append: true });
|
|
218
|
+
}
|
|
219
|
+
return c.json({ data: { user: { id: result.data.user.id } } });
|
|
220
|
+
},
|
|
221
|
+
refresh: async (c) => {
|
|
222
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
223
|
+
const { refreshToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
224
|
+
if (!refreshToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
225
|
+
const result = await require_refresh_dedup.deduplicateRefresh(refreshToken, () => client.refresh({ refreshToken }));
|
|
226
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
227
|
+
if (result.data.tokens) {
|
|
228
|
+
const cookieHeaders = require_cookies.setTokenCookies(result.data.tokens);
|
|
229
|
+
for (const cookie of cookieHeaders) c.header("Set-Cookie", cookie, { append: true });
|
|
230
|
+
}
|
|
231
|
+
return c.json({ data: { user: { id: result.data.user.id } } });
|
|
232
|
+
},
|
|
233
|
+
logout: async (c) => {
|
|
234
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
235
|
+
const { refreshToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
236
|
+
if (!refreshToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
237
|
+
const result = await client.logout({ refreshToken });
|
|
238
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
239
|
+
const clearHeaders = require_cookies.clearTokenCookies();
|
|
240
|
+
for (const cookie of clearHeaders) c.header("Set-Cookie", cookie, { append: true });
|
|
241
|
+
return c.json({ data: result.data });
|
|
242
|
+
},
|
|
243
|
+
getMe: async (c) => {
|
|
244
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
245
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
246
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
247
|
+
const result = await client.getUser({ accessToken });
|
|
248
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
249
|
+
return c.json({ data: result.data });
|
|
250
|
+
},
|
|
251
|
+
updateMe: async (c) => {
|
|
252
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
253
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
254
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
255
|
+
let raw;
|
|
256
|
+
try {
|
|
257
|
+
raw = await c.req.json();
|
|
258
|
+
} catch {
|
|
259
|
+
return errorResponse(c, sdkError("malformed", messages().invalidJsonBody, 400), 400);
|
|
260
|
+
}
|
|
261
|
+
const parsed = UpdateUserSchema.safeParse(raw);
|
|
262
|
+
if (!parsed.success) return errorResponse(c, sdkError("malformed", messages().invalidUpdateBody, 400), 400);
|
|
263
|
+
const result = await client.updateUser({
|
|
264
|
+
accessToken,
|
|
265
|
+
data: parsed.data
|
|
266
|
+
});
|
|
267
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
268
|
+
return c.json({ data: result.data });
|
|
269
|
+
},
|
|
270
|
+
deleteMe: async (c) => {
|
|
271
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
272
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
273
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
274
|
+
const result = await client.deleteUser({ accessToken });
|
|
275
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
276
|
+
const clearHeaders = require_cookies.clearTokenCookies();
|
|
277
|
+
for (const cookie of clearHeaders) c.header("Set-Cookie", cookie, { append: true });
|
|
278
|
+
return c.json({ data: result.data });
|
|
279
|
+
},
|
|
280
|
+
getEmpresas: async (c) => {
|
|
281
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
282
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
283
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
284
|
+
const result = await client.getUserEmpresas({ accessToken });
|
|
285
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
286
|
+
return c.json({ data: result.data });
|
|
287
|
+
},
|
|
288
|
+
setActiveEmpresa: async (c) => {
|
|
289
|
+
c.header("Cache-Control", "no-store");
|
|
290
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
291
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
292
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
293
|
+
let raw;
|
|
294
|
+
try {
|
|
295
|
+
raw = await c.req.json();
|
|
296
|
+
} catch {
|
|
297
|
+
return errorResponse(c, sdkError("malformed", messages().invalidJsonBody, 400), 400);
|
|
298
|
+
}
|
|
299
|
+
const parsed = ActiveEmpresaSchema.safeParse(raw);
|
|
300
|
+
if (!parsed.success) return errorResponse(c, sdkError("malformed", "empresaId inválido: debe ser el id de una empresa o null", 400), 400);
|
|
301
|
+
const result = await client.setActiveEmpresa({
|
|
302
|
+
accessToken,
|
|
303
|
+
empresaId: parsed.data.empresaId
|
|
304
|
+
});
|
|
305
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
306
|
+
if (!result.data.accessToken) return errorResponse(c, sdkError("malformed", "Respuesta de Auth sin access token reemitido", 502), 502);
|
|
307
|
+
c.header("Set-Cookie", require_cookies.setAccessTokenCookie(result.data.accessToken), { append: true });
|
|
308
|
+
return c.json({ data: { empresaId: result.data.empresaId } });
|
|
309
|
+
},
|
|
310
|
+
getSessions: async (c) => {
|
|
311
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
312
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
313
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
314
|
+
const result = await client.getSessions({ accessToken });
|
|
315
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
316
|
+
return c.json({ data: result.data });
|
|
317
|
+
},
|
|
318
|
+
deleteSession: async (c) => {
|
|
319
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
320
|
+
const { accessToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
321
|
+
if (!accessToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
322
|
+
const sessionId = c.req.param("id");
|
|
323
|
+
if (!sessionId || !/^[\w-]+$/.test(sessionId)) return errorResponse(c, sdkError("malformed", messages().sessionInvalid, 400), 400);
|
|
324
|
+
const result = await client.deleteSession({
|
|
325
|
+
accessToken,
|
|
326
|
+
sessionId
|
|
327
|
+
});
|
|
328
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
329
|
+
return c.json({ data: result.data });
|
|
330
|
+
},
|
|
331
|
+
deleteAllSessions: async (c) => {
|
|
332
|
+
const cookieHeader = c.req.header("cookie") || null;
|
|
333
|
+
const { refreshToken } = require_cookies.readTokensFromCookies(cookieHeader);
|
|
334
|
+
if (!refreshToken) return errorResponse(c, sdkError("auth_required", messages().tokenNotFound, 401), 401);
|
|
335
|
+
const result = await client.deleteAllSessions({ refreshToken });
|
|
336
|
+
if (!result.ok) return errorResponse(c, result.error, result.error.status);
|
|
337
|
+
const clearHeaders = require_cookies.clearTokenCookies();
|
|
338
|
+
for (const cookie of clearHeaders) c.header("Set-Cookie", cookie, { append: true });
|
|
339
|
+
return c.json({ data: result.data });
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
Object.defineProperty(exports, "ActiveEmpresaSchema", {
|
|
344
|
+
enumerable: true,
|
|
345
|
+
get: function() {
|
|
346
|
+
return ActiveEmpresaSchema;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
Object.defineProperty(exports, "ErrorResponseSchema", {
|
|
350
|
+
enumerable: true,
|
|
351
|
+
get: function() {
|
|
352
|
+
return ErrorResponseSchema;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
Object.defineProperty(exports, "GetCodeResponseSchema", {
|
|
356
|
+
enumerable: true,
|
|
357
|
+
get: function() {
|
|
358
|
+
return GetCodeResponseSchema;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
Object.defineProperty(exports, "GetCodeSchema", {
|
|
362
|
+
enumerable: true,
|
|
363
|
+
get: function() {
|
|
364
|
+
return GetCodeSchema;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
Object.defineProperty(exports, "LoginResponseSchema", {
|
|
368
|
+
enumerable: true,
|
|
369
|
+
get: function() {
|
|
370
|
+
return LoginResponseSchema;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
Object.defineProperty(exports, "LoginSchema", {
|
|
374
|
+
enumerable: true,
|
|
375
|
+
get: function() {
|
|
376
|
+
return LoginSchema;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
Object.defineProperty(exports, "RefreshResponseSchema", {
|
|
380
|
+
enumerable: true,
|
|
381
|
+
get: function() {
|
|
382
|
+
return RefreshResponseSchema;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
Object.defineProperty(exports, "UpdateUserSchema", {
|
|
386
|
+
enumerable: true,
|
|
387
|
+
get: function() {
|
|
388
|
+
return UpdateUserSchema;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
Object.defineProperty(exports, "buildAuthHandlers", {
|
|
392
|
+
enumerable: true,
|
|
393
|
+
get: function() {
|
|
394
|
+
return buildAuthHandlers;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
Object.defineProperty(exports, "parseDeviceInfo", {
|
|
398
|
+
enumerable: true,
|
|
399
|
+
get: function() {
|
|
400
|
+
return parseDeviceInfo;
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
//# sourceMappingURL=auth-handlers-CDzGFDTu.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-handlers-CDzGFDTu.cjs","names":["Bowser","z","errorResponseSchema","getCodeResponseSchema","loginResponseSchema","getErrorWire","createHttpClient","resolveErrorMessages","getErrorMessages","setTokenCookies","readTokensFromCookies","deduplicateRefresh","clearTokenCookies","setAccessTokenCookie"],"sources":["../src/hono/device-info.ts","../src/schemas.ts","../src/auth-handlers.ts"],"sourcesContent":["import Bowser from 'bowser'\nimport type { DeviceInfo } from '../types'\n\nexport function parseDeviceInfo(request: Request): DeviceInfo {\n const userAgent = request.headers.get('user-agent') || ''\n const parsed = Bowser.parse(userAgent)\n\n return {\n deviceType: parsed.platform?.type || 'desktop',\n os: parsed.os?.name || 'Unknown',\n browser: parsed.browser?.name || 'Unknown',\n userAgent: userAgent.slice(0, 500),\n }\n}\n","/**\n * Schemas Zod 4 compartidos — fuente canónica (B1 confirmado por T-00 probe).\n * Usados por auth-handlers.ts (validación runtime) y hono-openapi/index.ts (OpenAPI doc).\n * Importar desde aquí evita duplicación y garantiza consistencia entre variantes.\n *\n * `parseErrorResponse` vive en `parse-error-response.ts` (módulo puro, D-35): este archivo no es\n * alcanzable desde `src/react/index.ts`.\n */\nimport { z } from 'zod'\nimport {\n errorResponseSchema,\n getCodeResponseSchema,\n loginResponseSchema,\n} from '@eva_solutions/auth-contracts'\n\n// === Request schemas ===\n\nexport const GetCodeSchema = z.object({\n phone: z.string().min(1),\n})\n\n/**\n * Cuerpo de POST /login. `challengeId` es el identificador opaco que devolvió\n * POST /get-code para este código: el navegador lo conserva en memoria y lo\n * reenvía junto con el código. Sin él, /login responde 400 (`malformed`).\n */\nexport const LoginSchema = z.object({\n phone: z.string().min(1),\n code: z.string().min(1),\n challengeId: z.string().min(1),\n // Empresa que queda activa (opcional). El `producto` NO viene del navegador: lo pone el SDK.\n empresaId: z.string().min(1).optional(),\n})\n\n/**\n * Cuerpo de POST /empresa-activa: el id de la empresa que queda activa o `null` para ninguna.\n * El campo es obligatorio (un body `{}` es inválido): `null` es una decisión, no un faltante.\n */\nexport const ActiveEmpresaSchema = z.object({\n empresaId: z.string().min(1).nullable(),\n})\n\n/**\n * Schema para PATCH /me — record no vacío.\n * Validación extra con .refine() para rechazar body vacío.\n */\nexport const UpdateUserSchema = z\n .record(z.string(), z.unknown())\n .refine((obj) => Object.keys(obj).length > 0, 'Cuerpo de actualización vacío')\n\n// === Response schemas ===\n\n/*\n * Los schemas de respuesta son alias del contrato compartido (D-28: el tipo es idéntico al que\n * este archivo definía antes). Se usan solo para documentar OpenAPI: `http-client` no los parsea en\n * runtime. Este módulo registra metadatos de zod al cargarse, así que NO debe ser alcanzable desde\n * `src/react` (regla D-35: ahí solo se importan valores de módulos puros o `import type`).\n */\n\n/** Wire de error `{ error: { code, message } }` (componente `ErrorBody`). */\nexport const ErrorResponseSchema = errorResponseSchema\n\n/** Wire de POST /login/get-code (200). `challengeId` es opaco; cada get-code nuevo invalida el anterior. */\nexport const GetCodeResponseSchema = getCodeResponseSchema\n\n/** Wire de POST /login (200). */\nexport const LoginResponseSchema = loginResponseSchema\n\n/** Wire de POST /login/refresh (200): el contrato reutiliza la respuesta de login. */\nexport const RefreshResponseSchema = loginResponseSchema\n\n// === Inferred types ===\n\nexport type GetCodeInput = z.infer<typeof GetCodeSchema>\nexport type LoginInput = z.infer<typeof LoginSchema>\nexport type ActiveEmpresaInput = z.infer<typeof ActiveEmpresaSchema>\nexport type UpdateUserInput = z.infer<typeof UpdateUserSchema>\n","/**\n * Factory de handlers de auth — fuente única de verdad para los 12 endpoints.\n * Compartido entre evaAuthRoutes() (Hono plano) y evaAuthOpenAPIRoutes() (OpenAPIHono).\n * Decisión M2: resolución de messages() por-request (closure evalúa global cada vez).\n */\nimport type { Context, MiddlewareHandler } from 'hono'\nimport { createHttpClient } from './http-client'\nimport {\n readTokensFromCookies,\n setTokenCookies,\n setAccessTokenCookie,\n clearTokenCookies,\n} from './cookies'\nimport { deduplicateRefresh } from './refresh-dedup'\nimport { parseDeviceInfo } from './hono/device-info'\nimport { resolveErrorMessages, type EvaErrorMessages } from './error-messages'\nimport {\n getErrorMessages,\n getErrorWire,\n validateErrorMessagesInput,\n} from './config'\nimport {\n ActiveEmpresaSchema,\n GetCodeSchema,\n LoginSchema,\n UpdateUserSchema,\n} from './schemas'\nimport type { EvaError, EvaSdkError } from './types'\nimport type { SdkErrorReason } from './error-codes'\n\nexport interface AuthHandlerOptions {\n errorMessages?: Partial<EvaErrorMessages>\n /**\n * Orígenes extra (`https://app.example.com`, sin path) desde los que se aceptan las mutaciones\n * con cookies, además del propio host de la request. Un `Origin` fuera de esa lista responde 403.\n * Acepta cualquier origen serializado `esquema://host[:puerto]` (también `tauri://localhost`,\n * `capacitor://localhost`) por coincidencia exacta. Lanza al construir si una entrada no lo es\n * (p. ej. `'*'` o `null`).\n */\n allowedOrigins?: readonly string[]\n}\n\n/**\n * Guardas para la variante OpenAPI de get-code/login: el validador de\n * @hono/zod-openapi responde el 400 antes que el handler, así que\n * no-store y el wire de error se replican aquí. middleware corre antes del validador\n * (JSON malformado); onInvalid es el hook del validador (body que no cumple el schema).\n */\nexport interface OpenAPIBodyGuard {\n middleware: MiddlewareHandler\n onInvalid: (result: { success: boolean }, c: Context) => Response | undefined\n}\n\nexport interface AuthHandlers {\n /** Middleware CSRF: rechaza con 403 las mutaciones cuyo `Origin` no está permitido. */\n originGuard: MiddlewareHandler\n openApiGuards: { getCode: OpenAPIBodyGuard; login: OpenAPIBodyGuard }\n getCode: (c: Context) => Promise<Response>\n login: (c: Context) => Promise<Response>\n refresh: (c: Context) => Promise<Response>\n logout: (c: Context) => Promise<Response>\n getMe: (c: Context) => Promise<Response>\n updateMe: (c: Context) => Promise<Response>\n deleteMe: (c: Context) => Promise<Response>\n getEmpresas: (c: Context) => Promise<Response>\n setActiveEmpresa: (c: Context) => Promise<Response>\n getSessions: (c: Context) => Promise<Response>\n deleteSession: (c: Context) => Promise<Response>\n deleteAllSessions: (c: Context) => Promise<Response>\n}\n\ntype ErrorStatus = 400 | 401 | 403 | 404 | 409 | 429 | 500 | 502 | 503\n\nconst KNOWN_ERROR_STATUSES = new Set<number>([\n 400, 401, 403, 404, 409, 429, 500, 502, 503,\n])\n\nconst REASON_TO_CODE: Record<SdkErrorReason, string> = {\n auth_required: 'unauthorized',\n token_invalid: 'unauthorized',\n refresh_no_tokens: 'unauthorized',\n verify_failed: 'unauthorized',\n network: 'service_unavailable',\n malformed: 'bad_request',\n}\n\nfunction resolveCode(evaError: EvaError): string {\n if (evaError.kind === 'api') return evaError.code\n return REASON_TO_CODE[evaError.reason]\n}\n\nfunction errorResponse(\n c: Context,\n evaError: EvaError,\n status: number,\n): Response {\n const safeStatus = KNOWN_ERROR_STATUSES.has(status)\n ? (status as ErrorStatus)\n : 500\n const wire = getErrorWire()\n if (wire === 'api') {\n return c.json(\n { error: { code: resolveCode(evaError), message: evaError.message } },\n safeStatus,\n )\n }\n return c.json({ error: evaError.message }, safeStatus)\n}\n\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])\n\n/**\n * Origen serializado de un esquema que no es http(s) (`tauri://localhost`, `capacitor://localhost`):\n * `esquema://host[:puerto]` sin userinfo, path, query ni fragmento (una `/` final se tolera).\n */\nconst CUSTOM_SCHEME_ORIGIN = /^([a-z][a-z0-9+.-]*):\\/\\/([^\\s/?#@\\\\]+)\\/?$/i\n\n/**\n * `new URL(...).origin` de un esquema no especial es `\"null\"`, así que http(s) se normaliza con el\n * parser y el resto se compara por su forma serializada en minúsculas (la que manda el navegador).\n */\nfunction normalizeAllowedOrigins(origins: readonly string[]): Set<string> {\n const normalized = new Set<string>()\n for (const entry of origins) {\n let url: URL | undefined\n try {\n url = new URL(entry)\n } catch {\n // cae al throw de abajo\n }\n const custom =\n url !== undefined && !/^https?:$/.test(url.protocol)\n ? CUSTOM_SCHEME_ORIGIN.exec(entry)\n : null\n if (\n url === undefined ||\n (custom === null && !/^https?:$/.test(url.protocol))\n ) {\n throw new Error(\n `[eva-auth-sdk] allowedOrigins inválido: ${JSON.stringify(entry)} (se espera un origen serializado esquema://host[:puerto], p. ej. https://app.example.com o tauri://localhost)`,\n )\n }\n normalized.add(\n custom === null\n ? url.origin\n : `${(custom[1] as string).toLowerCase()}://${(custom[2] as string).toLowerCase()}`,\n )\n }\n return normalized\n}\n\n/**\n * Mismo origen = mismo host:puerto que la request; el esquema no cuenta porque tras un proxy que\n * termina TLS el servidor ve `http://` mientras el navegador manda `https://`.\n */\nfunction isOriginAllowed(\n origin: string,\n requestUrl: string,\n allowed: ReadonlySet<string>,\n): boolean {\n let parsed: URL\n try {\n parsed = new URL(origin)\n } catch {\n return false // `Origin: null` (iframes sandbox, redirects entre orígenes) y basura\n }\n return (\n allowed.has(parsed.origin) ||\n allowed.has(origin.toLowerCase()) ||\n parsed.host === new URL(requestUrl).host\n )\n}\n\nfunction sdkError(\n reason: SdkErrorReason,\n message: string,\n status: number,\n): EvaSdkError {\n return { kind: 'sdk', reason, message, status }\n}\n\n/**\n * Construye los 12 handlers de auth con las opciones provistas.\n * Validación temprana de errorMessages si se proveen (lanza si key inválida o valor no-string).\n *\n * Decisión M2 (ADR-012): messages() se resuelve por-request (closure evalúa\n * getErrorMessages() en cada llamada). Permite que configureEvaAuth() post-factory\n * tome efecto en el siguiente request. Tradeoff: ~3 spreads + 2 fn calls per request.\n */\nexport function buildAuthHandlers(opts: AuthHandlerOptions = {}): AuthHandlers {\n if (opts.errorMessages !== undefined) {\n validateErrorMessagesInput(opts.errorMessages)\n }\n\n const allowedOrigins = normalizeAllowedOrigins(opts.allowedOrigins ?? [])\n\n const client = createHttpClient()\n\n // Resolución diferida por-request (M2)\n const messages = () =>\n resolveErrorMessages(opts.errorMessages, getErrorMessages())\n\n const bodyGuard = (invalidMessage: () => string): OpenAPIBodyGuard => ({\n middleware: async (c, next) => {\n c.header('Cache-Control', 'no-store')\n try {\n await c.req.json()\n } catch {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidJsonBody, 400),\n 400,\n )\n }\n await next()\n },\n onInvalid: (result, c) => {\n if (result.success) return undefined\n c.header('Cache-Control', 'no-store')\n return errorResponse(c, sdkError('malformed', invalidMessage(), 400), 400)\n },\n })\n\n // Sin `Origin` (curl, servidores) se deja pasar: todo navegador lo manda en las mutaciones.\n const originGuard: MiddlewareHandler = async (c, next) => {\n const origin = c.req.header('origin')\n if (\n SAFE_METHODS.has(c.req.method) ||\n origin === undefined ||\n isOriginAllowed(origin, c.req.url, allowedOrigins)\n ) {\n return next()\n }\n return errorResponse(\n c,\n {\n kind: 'api',\n code: 'forbidden',\n message: messages().originNotAllowed,\n status: 403,\n },\n 403,\n )\n }\n\n return {\n originGuard,\n openApiGuards: {\n getCode: bodyGuard(() => messages().invalidPhone),\n login: bodyGuard(() => messages().loginFailed),\n },\n // POST /get-code\n getCode: async (c: Context): Promise<Response> => {\n // Respuestas con challengeId/cookies: nunca cacheables (paridad con el API).\n c.header('Cache-Control', 'no-store')\n let raw: unknown\n try {\n raw = await c.req.json()\n } catch {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidJsonBody, 400),\n 400,\n )\n }\n const parsed = GetCodeSchema.safeParse(raw)\n if (!parsed.success) {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidPhone, 400),\n 400,\n )\n }\n const result = await client.getCode(parsed.data)\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // POST /login\n login: async (c: Context): Promise<Response> => {\n // Respuestas con challengeId/cookies: nunca cacheables (paridad con el API).\n c.header('Cache-Control', 'no-store')\n let raw: unknown\n try {\n raw = await c.req.json()\n } catch {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidJsonBody, 400),\n 400,\n )\n }\n const parsed = LoginSchema.safeParse(raw)\n if (!parsed.success) {\n return errorResponse(\n c,\n sdkError('malformed', messages().loginFailed, 400),\n 400,\n )\n }\n const deviceInfo = parseDeviceInfo(c.req.raw)\n const result = await client.login({ ...parsed.data, ...deviceInfo })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n if (result.data.tokens) {\n const cookieHeaders = setTokenCookies(result.data.tokens)\n for (const cookie of cookieHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n }\n return c.json({ data: { user: { id: result.data.user.id } } })\n },\n\n // POST /refresh\n refresh: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { refreshToken } = readTokensFromCookies(cookieHeader)\n if (!refreshToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await deduplicateRefresh(refreshToken, () =>\n client.refresh({ refreshToken }),\n )\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n if (result.data.tokens) {\n const cookieHeaders = setTokenCookies(result.data.tokens)\n for (const cookie of cookieHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n }\n return c.json({ data: { user: { id: result.data.user.id } } })\n },\n\n // POST /logout\n logout: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { refreshToken } = readTokensFromCookies(cookieHeader)\n if (!refreshToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.logout({ refreshToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n const clearHeaders = clearTokenCookies()\n for (const cookie of clearHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n return c.json({ data: result.data })\n },\n\n // GET /me\n getMe: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.getUser({ accessToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // PATCH /me\n updateMe: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n let raw: unknown\n try {\n raw = await c.req.json()\n } catch {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidJsonBody, 400),\n 400,\n )\n }\n const parsed = UpdateUserSchema.safeParse(raw)\n if (!parsed.success) {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidUpdateBody, 400),\n 400,\n )\n }\n const result = await client.updateUser({ accessToken, data: parsed.data })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // DELETE /me\n deleteMe: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.deleteUser({ accessToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n const clearHeaders = clearTokenCookies()\n for (const cookie of clearHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n return c.json({ data: result.data })\n },\n\n // GET /empresas\n getEmpresas: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.getUserEmpresas({ accessToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // POST /empresa-activa\n setActiveEmpresa: async (c: Context): Promise<Response> => {\n // Lleva un access token nuevo en una cookie: nunca cacheable.\n c.header('Cache-Control', 'no-store')\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n let raw: unknown\n try {\n raw = await c.req.json()\n } catch {\n return errorResponse(\n c,\n sdkError('malformed', messages().invalidJsonBody, 400),\n 400,\n )\n }\n const parsed = ActiveEmpresaSchema.safeParse(raw)\n if (!parsed.success) {\n return errorResponse(\n c,\n sdkError(\n 'malformed',\n 'empresaId inválido: debe ser el id de una empresa o null',\n 400,\n ),\n 400,\n )\n }\n const result = await client.setActiveEmpresa({\n accessToken,\n empresaId: parsed.data.empresaId,\n })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n // Auth reemite SOLO el access token; sin él la sesión seguiría con la empresa vieja y no hay\n // nada que reescribir: es una respuesta inválida de Auth, no un éxito.\n if (!result.data.accessToken) {\n return errorResponse(\n c,\n sdkError(\n 'malformed',\n 'Respuesta de Auth sin access token reemitido',\n 502,\n ),\n 502,\n )\n }\n c.header('Set-Cookie', setAccessTokenCookie(result.data.accessToken), {\n append: true,\n })\n return c.json({ data: { empresaId: result.data.empresaId } })\n },\n\n // GET /sessions\n getSessions: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.getSessions({ accessToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // DELETE /sessions/:id\n deleteSession: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { accessToken } = readTokensFromCookies(cookieHeader)\n if (!accessToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const sessionId = c.req.param('id')\n if (!sessionId || !/^[\\w-]+$/.test(sessionId)) {\n return errorResponse(\n c,\n sdkError('malformed', messages().sessionInvalid, 400),\n 400,\n )\n }\n const result = await client.deleteSession({ accessToken, sessionId })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n return c.json({ data: result.data })\n },\n\n // DELETE /sessions\n deleteAllSessions: async (c: Context): Promise<Response> => {\n const cookieHeader = c.req.header('cookie') || null\n const { refreshToken } = readTokensFromCookies(cookieHeader)\n if (!refreshToken)\n return errorResponse(\n c,\n sdkError('auth_required', messages().tokenNotFound, 401),\n 401,\n )\n const result = await client.deleteAllSessions({ refreshToken })\n if (!result.ok) return errorResponse(c, result.error, result.error.status)\n const clearHeaders = clearTokenCookies()\n for (const cookie of clearHeaders) {\n c.header('Set-Cookie', cookie, { append: true })\n }\n return c.json({ data: result.data })\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { n as EvaErrorMessages } from "./error-messages-CGpW1fsg.cjs";
|
|
2
|
+
import { Context } from "hono";
|
|
3
|
+
interface AuthHandlerOptions {
|
|
4
|
+
errorMessages?: Partial<EvaErrorMessages>;
|
|
5
|
+
/**
|
|
6
|
+
* Orígenes extra (`https://app.example.com`, sin path) desde los que se aceptan las mutaciones
|
|
7
|
+
* con cookies, además del propio host de la request. Un `Origin` fuera de esa lista responde 403.
|
|
8
|
+
* Acepta cualquier origen serializado `esquema://host[:puerto]` (también `tauri://localhost`,
|
|
9
|
+
* `capacitor://localhost`) por coincidencia exacta. Lanza al construir si una entrada no lo es
|
|
10
|
+
* (p. ej. `'*'` o `null`).
|
|
11
|
+
*/
|
|
12
|
+
allowedOrigins?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export { AuthHandlerOptions as t };
|
|
15
|
+
//# sourceMappingURL=auth-handlers-DRUUTEtW.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-handlers-DRUUTEtW.d.cts","names":[],"sources":["../src/auth-handlers.ts"],"mappings":";;UA8BiB;EACf,gBAAgB,QAAQ;;;;;;;;EAQxB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// ../auth-contracts/dist/catalog.js
|
|
2
|
+
/**
|
|
3
|
+
* PURE module: it must never reference `zod` or any schema module of this package (see
|
|
4
|
+
* `constants.ts`). The closed catalog of service audiences and, for each, its permissions.
|
|
5
|
+
*
|
|
6
|
+
* Apart from `tokens.ts` and `constants.ts` on purpose: the SDK `react` entry is size-budgeted and
|
|
7
|
+
* reaches `constants.ts` (header names), so nothing the browser does not need goes there. The SDK
|
|
8
|
+
* `react` closure imports neither this catalog nor the token vocabulary; Auth uses
|
|
9
|
+
* `isServiceAudience` to keep product slugs and service audiences apart.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Closed catalog of service audiences and, for each one, the permissions a service client can be
|
|
13
|
+
* granted on it. The service token `aud` is one of these keys and its `scope` a subset of the
|
|
14
|
+
* values. Add a permission here only together with the route that requires it.
|
|
15
|
+
*
|
|
16
|
+
* `admin` is NOT a permission of `auth-api`: the Auth admin surface authenticates with the signed
|
|
17
|
+
* request of a service client flagged `esAdmin`, never with a token. It IS a permission of
|
|
18
|
+
* `whatsapp-api`.
|
|
19
|
+
*/
|
|
20
|
+
const SERVICE_AUDIENCE_SCOPES = {
|
|
21
|
+
"auth-api": [
|
|
22
|
+
"users:read",
|
|
23
|
+
"webhooks:read",
|
|
24
|
+
"webhooks:write",
|
|
25
|
+
"empresas:leer",
|
|
26
|
+
"empresas:escribir",
|
|
27
|
+
"tokens:exchange",
|
|
28
|
+
"contrataciones:pedir",
|
|
29
|
+
"contrataciones:escribir",
|
|
30
|
+
"contrataciones:leer",
|
|
31
|
+
"empresas:baja",
|
|
32
|
+
"autorizaciones:escribir",
|
|
33
|
+
"autorizaciones:leer",
|
|
34
|
+
"directorio:leer"
|
|
35
|
+
],
|
|
36
|
+
"whatsapp-api": [
|
|
37
|
+
"messages:send:text",
|
|
38
|
+
"messages:send:media",
|
|
39
|
+
"admin"
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
/** Service audiences as a tuple, so schemas can build an enum straight from it. */
|
|
43
|
+
const SERVICE_AUDIENCES = ["auth-api", "whatsapp-api"];
|
|
44
|
+
/** True when `value` is an audience of the catalog. */
|
|
45
|
+
function isServiceAudience(value) {
|
|
46
|
+
return Object.hasOwn(SERVICE_AUDIENCE_SCOPES, value);
|
|
47
|
+
}
|
|
48
|
+
/** True when `scope` is a permission of `audience` in the catalog (an unknown audience is false). */
|
|
49
|
+
function isScopeOfAudience(audience, scope) {
|
|
50
|
+
return isServiceAudience(audience) && SERVICE_AUDIENCE_SCOPES[audience].includes(scope);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Permissions a service client can DELEGATE on behalf of a user (token exchange), by destination
|
|
54
|
+
* audience. A delegation edge (`service_client_delegations`) can only carry these.
|
|
55
|
+
*
|
|
56
|
+
* Narrower than {@link SERVICE_AUDIENCE_SCOPES} on purpose: `auth-api` is never a destination (Auth
|
|
57
|
+
* is the issuer, so no delegated token talks to it) and `admin` is never delegable. A test pins both
|
|
58
|
+
* and that every value is in the audience catalog.
|
|
59
|
+
*/
|
|
60
|
+
const DELEGABLE_AUDIENCE_SCOPES = { "whatsapp-api": ["messages:send:text", "messages:send:media"] };
|
|
61
|
+
/** Delegable audiences as a tuple, so schemas can build an enum straight from it. */
|
|
62
|
+
const DELEGABLE_AUDIENCES = ["whatsapp-api"];
|
|
63
|
+
/** Every delegable permission of every audience, flat (a scope string names its audience's service). */
|
|
64
|
+
const DELEGABLE_SCOPES = Object.values(DELEGABLE_AUDIENCE_SCOPES).flat();
|
|
65
|
+
/** True when `audience` can be the destination of a delegated token. */
|
|
66
|
+
function isDelegableAudience(value) {
|
|
67
|
+
return Object.hasOwn(DELEGABLE_AUDIENCE_SCOPES, value);
|
|
68
|
+
}
|
|
69
|
+
/** True when `scope` can be delegated towards `audience` (an unknown or non-delegable audience is false). */
|
|
70
|
+
function isDelegableScope(audience, scope) {
|
|
71
|
+
return isDelegableAudience(audience) && DELEGABLE_AUDIENCE_SCOPES[audience].includes(scope);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Closed catalog of permissions BETWEEN companies ("company B may do X on the data of company A"),
|
|
75
|
+
* by the service audience that owns the data. Kept apart from {@link SERVICE_AUDIENCE_SCOPES} on
|
|
76
|
+
* purpose: those say what a service CLIENT can do, these say what a COMPANY authorizes another
|
|
77
|
+
* company to do. They are only for private data; public or shared data needs none.
|
|
78
|
+
*
|
|
79
|
+
* Starts minimal and each owning service adds its own (together with the route that checks it).
|
|
80
|
+
* `auth-api` owns none: it only stores and answers the grants.
|
|
81
|
+
*/
|
|
82
|
+
const INTER_EMPRESA_PERMISSIONS = { "whatsapp-api": ["whatsapp:mensajes:leer"] };
|
|
83
|
+
/** Every inter-company permission, flat, so schemas can build an enum straight from it. */
|
|
84
|
+
const INTER_EMPRESA_PERMISSION_LIST = Object.values(INTER_EMPRESA_PERMISSIONS).flat();
|
|
85
|
+
/** True when `value` is a permission of the inter-company catalog. */
|
|
86
|
+
function isInterEmpresaPermission(value) {
|
|
87
|
+
return INTER_EMPRESA_PERMISSION_LIST.includes(value);
|
|
88
|
+
}
|
|
89
|
+
/** The audience that owns `permission` (the only one that may verify it), or `undefined`. */
|
|
90
|
+
function interEmpresaPermissionOwner(permission) {
|
|
91
|
+
return Object.keys(INTER_EMPRESA_PERMISSIONS).find((owner) => INTER_EMPRESA_PERMISSIONS[owner].includes(permission));
|
|
92
|
+
}
|
|
93
|
+
Object.defineProperty(exports, "DELEGABLE_AUDIENCES", {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
get: function() {
|
|
96
|
+
return DELEGABLE_AUDIENCES;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
Object.defineProperty(exports, "DELEGABLE_AUDIENCE_SCOPES", {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
get: function() {
|
|
102
|
+
return DELEGABLE_AUDIENCE_SCOPES;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
Object.defineProperty(exports, "DELEGABLE_SCOPES", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
get: function() {
|
|
108
|
+
return DELEGABLE_SCOPES;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
Object.defineProperty(exports, "INTER_EMPRESA_PERMISSIONS", {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
get: function() {
|
|
114
|
+
return INTER_EMPRESA_PERMISSIONS;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(exports, "INTER_EMPRESA_PERMISSION_LIST", {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
get: function() {
|
|
120
|
+
return INTER_EMPRESA_PERMISSION_LIST;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
Object.defineProperty(exports, "SERVICE_AUDIENCES", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
get: function() {
|
|
126
|
+
return SERVICE_AUDIENCES;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
Object.defineProperty(exports, "SERVICE_AUDIENCE_SCOPES", {
|
|
130
|
+
enumerable: true,
|
|
131
|
+
get: function() {
|
|
132
|
+
return SERVICE_AUDIENCE_SCOPES;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
Object.defineProperty(exports, "interEmpresaPermissionOwner", {
|
|
136
|
+
enumerable: true,
|
|
137
|
+
get: function() {
|
|
138
|
+
return interEmpresaPermissionOwner;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(exports, "isDelegableAudience", {
|
|
142
|
+
enumerable: true,
|
|
143
|
+
get: function() {
|
|
144
|
+
return isDelegableAudience;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
Object.defineProperty(exports, "isDelegableScope", {
|
|
148
|
+
enumerable: true,
|
|
149
|
+
get: function() {
|
|
150
|
+
return isDelegableScope;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
Object.defineProperty(exports, "isInterEmpresaPermission", {
|
|
154
|
+
enumerable: true,
|
|
155
|
+
get: function() {
|
|
156
|
+
return isInterEmpresaPermission;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
Object.defineProperty(exports, "isScopeOfAudience", {
|
|
160
|
+
enumerable: true,
|
|
161
|
+
get: function() {
|
|
162
|
+
return isScopeOfAudience;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
Object.defineProperty(exports, "isServiceAudience", {
|
|
166
|
+
enumerable: true,
|
|
167
|
+
get: function() {
|
|
168
|
+
return isServiceAudience;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=catalog-CHPqldcj.cjs.map
|