@mybuildex/pkg 0.6.1 → 0.8.0
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/README.md +35 -0
- package/dist/acl/allows.d.ts +3 -0
- package/dist/acl/allows.js +53 -0
- package/dist/acl/allows.js.map +1 -0
- package/dist/acl/check.d.ts +32 -0
- package/dist/acl/check.js +114 -0
- package/dist/acl/check.js.map +1 -0
- package/dist/acl/map.generated.d.ts +1 -0
- package/dist/acl/map.generated.js +2367 -0
- package/dist/acl/map.generated.js.map +1 -0
- package/dist/acl/plugin.d.ts +55 -0
- package/dist/acl/plugin.js +261 -0
- package/dist/acl/plugin.js.map +1 -0
- package/dist/acl/roles.d.ts +23 -0
- package/dist/acl/roles.js +71 -0
- package/dist/acl/roles.js.map +1 -0
- package/dist/audit/audit.d.ts +165 -0
- package/dist/audit/audit.js +595 -0
- package/dist/audit/audit.js.map +1 -0
- package/dist/audit/serialize.d.ts +20 -0
- package/dist/audit/serialize.js +94 -0
- package/dist/audit/serialize.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +68 -1
- package/dist/index.js.map +1 -1
- package/dist/prisma/multitenant.d.ts +6 -0
- package/dist/prisma/multitenant.js +6 -2
- package/dist/prisma/multitenant.js.map +1 -1
- package/dist/redis/client.d.ts +18 -0
- package/dist/redis/client.js +73 -0
- package/dist/redis/client.js.map +1 -0
- package/dist/tenant/auth.d.ts +4 -2
- package/dist/tenant/auth.js +29 -2
- package/dist/tenant/auth.js.map +1 -1
- package/dist/tenant/permissions.d.ts +57 -0
- package/dist/tenant/permissions.js +187 -0
- package/dist/tenant/permissions.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Serialização do antes/depois da auditoria: JSON seguro (BigInt, Date,
|
|
3
|
+
// Decimal, Buffer), campos sensíveis mascarados e tamanho limitado.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.MASK = exports.DEFAULT_MASK_KEYS = void 0;
|
|
6
|
+
exports.sanitizeForAudit = sanitizeForAudit;
|
|
7
|
+
exports.auditJson = auditJson;
|
|
8
|
+
exports.changedFields = changedFields;
|
|
9
|
+
exports.onlyChanged = onlyChanged;
|
|
10
|
+
/** Chaves mascaradas em qualquer nível (senha, token, segredo, chave privada...). */
|
|
11
|
+
exports.DEFAULT_MASK_KEYS = /pass(word)?|senha|token|secret|private_?key|api_?key|authorization|cookie|credential/i;
|
|
12
|
+
exports.MASK = "***";
|
|
13
|
+
const DEFAULT_MAX_STRING = 16 * 1024;
|
|
14
|
+
const DEFAULT_MAX_JSON = 512 * 1024;
|
|
15
|
+
function truncateString(s, max) {
|
|
16
|
+
const bytes = Buffer.byteLength(s, "utf8");
|
|
17
|
+
if (bytes <= max)
|
|
18
|
+
return s;
|
|
19
|
+
// corta pelo número de caracteres proporcional (aprox.) e marca
|
|
20
|
+
const keep = Math.max(0, Math.floor(s.length * (max / bytes)));
|
|
21
|
+
return `${s.slice(0, keep)}…[truncado ${bytes} bytes]`;
|
|
22
|
+
}
|
|
23
|
+
/** Valor pronto para JSON.stringify, com máscara e truncamento. */
|
|
24
|
+
function sanitizeForAudit(value, options = {}, depth = 0) {
|
|
25
|
+
const maskKeys = options.maskKeys ?? exports.DEFAULT_MASK_KEYS;
|
|
26
|
+
const maxString = options.maxStringBytes ?? DEFAULT_MAX_STRING;
|
|
27
|
+
if (value === null || value === undefined)
|
|
28
|
+
return null;
|
|
29
|
+
if (depth > 20)
|
|
30
|
+
return "[profundidade máxima]";
|
|
31
|
+
if (typeof value === "bigint")
|
|
32
|
+
return value.toString();
|
|
33
|
+
if (typeof value === "string")
|
|
34
|
+
return truncateString(value, maxString);
|
|
35
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
36
|
+
return value;
|
|
37
|
+
if (value instanceof Date)
|
|
38
|
+
return isNaN(value.getTime()) ? null : value.toISOString();
|
|
39
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array)
|
|
40
|
+
return `[binário ${value.byteLength} bytes]`;
|
|
41
|
+
if (typeof value === "function" || typeof value === "symbol")
|
|
42
|
+
return null;
|
|
43
|
+
// Decimal do Prisma (e similares) sabem se serializar
|
|
44
|
+
if (typeof value.toJSON === "function" && !Array.isArray(value)) {
|
|
45
|
+
return sanitizeForAudit(value.toJSON(), options, depth + 1);
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(value))
|
|
48
|
+
return value.map(v => sanitizeForAudit(v, options, depth + 1));
|
|
49
|
+
const out = {};
|
|
50
|
+
for (const [k, v] of Object.entries(value)) {
|
|
51
|
+
out[k] = maskKeys.test(k) && v !== null && v !== undefined ? exports.MASK : sanitizeForAudit(v, options, depth + 1);
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** JSON da coluna (ou null). Acima do limite, grava só um marcador com o tamanho. */
|
|
56
|
+
function auditJson(value, options = {}) {
|
|
57
|
+
if (value === null || value === undefined)
|
|
58
|
+
return null;
|
|
59
|
+
const json = JSON.stringify(sanitizeForAudit(value, options));
|
|
60
|
+
if (json === undefined)
|
|
61
|
+
return null;
|
|
62
|
+
const max = options.maxJsonBytes ?? DEFAULT_MAX_JSON;
|
|
63
|
+
const bytes = Buffer.byteLength(json, "utf8");
|
|
64
|
+
if (bytes > max)
|
|
65
|
+
return JSON.stringify({ _truncado: true, bytes });
|
|
66
|
+
return json;
|
|
67
|
+
}
|
|
68
|
+
/** Campos que mudaram entre antes e depois (comparação por valor serializado). */
|
|
69
|
+
function changedFields(before, after) {
|
|
70
|
+
const b = before && typeof before === "object" && !Array.isArray(before) ? before : {};
|
|
71
|
+
const a = after && typeof after === "object" && !Array.isArray(after) ? after : {};
|
|
72
|
+
const keys = new Set([...Object.keys(b), ...Object.keys(a)]);
|
|
73
|
+
const out = [];
|
|
74
|
+
for (const k of keys) {
|
|
75
|
+
if (JSON.stringify(sanitizeForAudit(b[k] ?? null)) !== JSON.stringify(sanitizeForAudit(a[k] ?? null)))
|
|
76
|
+
out.push(k);
|
|
77
|
+
}
|
|
78
|
+
return out.sort();
|
|
79
|
+
}
|
|
80
|
+
/** Só os campos alterados (mais o id) — o update grava o diff, não a linha
|
|
81
|
+
* inteira: corta a maior parte do tamanho do audit_logs. */
|
|
82
|
+
function onlyChanged(row, changed) {
|
|
83
|
+
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
84
|
+
return row ?? null;
|
|
85
|
+
const src = row;
|
|
86
|
+
const out = {};
|
|
87
|
+
if ("id" in src)
|
|
88
|
+
out.id = src.id;
|
|
89
|
+
for (const k of changed)
|
|
90
|
+
if (k in src)
|
|
91
|
+
out[k] = src[k];
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/audit/serialize.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -33,3 +33,17 @@ export type { ErrorHandlerOptions } from "./http/error-handler";
|
|
|
33
33
|
export { createGcfHandler } from "./http/gcf-handler";
|
|
34
34
|
export type { GcfHandlerOptions } from "./http/gcf-handler";
|
|
35
35
|
export { GeminiHelp, EMBED_DIM, GEMINI_MODEL, EMBED_MODEL } from "./ai/gemini";
|
|
36
|
+
export { createPermissionsResolver, defaultPermissionsQuery, invalidatePermissionsCache, permissionsCacheKey, permissionsVersionKey, } from "./tenant/permissions";
|
|
37
|
+
export type { PermissionsResolverOptions, PermissionsRedisLike, PermissionsInvalidationRedisLike, InvalidatePermissionsOptions, InvalidatePermissionsResult, } from "./tenant/permissions";
|
|
38
|
+
export { createRedisClient, resolveRedisOptions, DEFAULT_REDIS_CONNECT_TIMEOUT_MS } from "./redis/client";
|
|
39
|
+
export type { RedisClient, RedisClientOptions } from "./redis/client";
|
|
40
|
+
export { ACL_MAP } from "./acl/map.generated";
|
|
41
|
+
export { checkAcl, aclEntryIds, resolveAclRule, evaluateAclRule, AclConfigError } from "./acl/check";
|
|
42
|
+
export { TEACHER_ACLS, STUDENT_ACLS, RESPONSIBLE_ACLS, ROLE_ALIASES, isRoleName, isSingleRoleList, hasAclName, hasAnyOf, FUNCTION_ROLE_PAIRS, FUNCTION_ROLES, FUNCTION_ROLE_ALIASES, isFunctionRoleName } from "./acl/roles";
|
|
43
|
+
export type { AclMap, AclRule, ResolvedAclRule } from "./acl/check";
|
|
44
|
+
export { createAclPlugin, useModuleAcl, getAclRouteReport, DEFAULT_ACL_ACTIONS, ACL_ACTION_FALLBACK, defaultAclAction } from "./acl/plugin";
|
|
45
|
+
export { aclAllows } from "./acl/allows";
|
|
46
|
+
export type { AclMode, AclPluginOptions, AclRouteInfo, UseModuleAclOptions } from "./acl/plugin";
|
|
47
|
+
export { createAuditPlugin, createAuditExtension, createAuditQueryHandler, withAudit, auditEnabled, auditRaw, runInAuditContext, getAuditContext, writeEntries, auditRow, auditDate, resolveAuditActor, clearAuditActorCache, createForbiddenThrottle, AUDIT_COLUMNS, AUDIT_WRITE_OPERATIONS, } from "./audit/audit";
|
|
48
|
+
export type { AuditOptions, AuditPluginOptions, AuditOrigin, AuditEntry, AuditBaseClient, AuditActor } from "./audit/audit";
|
|
49
|
+
export { sanitizeForAudit, auditJson, changedFields, onlyChanged, DEFAULT_MASK_KEYS } from "./audit/serialize";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EMBED_MODEL = exports.GEMINI_MODEL = exports.EMBED_DIM = exports.GeminiHelp = exports.createGcfHandler = exports.isInternalError = exports.createErrorHandler = exports.getBucket = exports.getDefaultAuth = exports.getTenantAuth = exports.initFirebaseAdmin = exports.getFirebaseStorage = exports.getFirebaseClientApp = exports.createFirebaseClientPlugin = exports.createSwaggerPlugin = exports.DEFAULT_CORS = exports.createCorsPlugin = exports.withTenantSchema = exports.createMultitenantPrismaMariaDb = exports.resolveStatementTimeout = exports.createMultitenantPrisma = exports.createAsyncSendGuard = exports.createCompressPlugin = exports.createSharedSecretGuard = exports.safeEqual = exports.isPublicRoute = exports.publicPath = exports.publicRoute = exports.RequestScopeError = exports.runInRequestScope = exports.getRequestScope = exports.requestScoped = exports.createRequestScopePlugin = exports.createTenantMembershipAssert = exports.canonicalRequestPath = exports.createAuthMiddleware = exports.InvalidTenantError = exports.createTenantMiddleware = exports.readRawTenantId = exports.resolveTenantId = void 0;
|
|
3
|
+
exports.checkAcl = exports.ACL_MAP = exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS = exports.resolveRedisOptions = exports.createRedisClient = exports.permissionsVersionKey = exports.permissionsCacheKey = exports.invalidatePermissionsCache = exports.defaultPermissionsQuery = exports.createPermissionsResolver = exports.EMBED_MODEL = exports.GEMINI_MODEL = exports.EMBED_DIM = exports.GeminiHelp = exports.createGcfHandler = exports.isInternalError = exports.createErrorHandler = exports.getBucket = exports.getDefaultAuth = exports.getTenantAuth = exports.initFirebaseAdmin = exports.getFirebaseStorage = exports.getFirebaseClientApp = exports.createFirebaseClientPlugin = exports.createSwaggerPlugin = exports.DEFAULT_CORS = exports.createCorsPlugin = exports.withTenantSchema = exports.createMultitenantPrismaMariaDb = exports.resolveStatementTimeout = exports.createMultitenantPrisma = exports.createAsyncSendGuard = exports.createCompressPlugin = exports.createSharedSecretGuard = exports.safeEqual = exports.isPublicRoute = exports.publicPath = exports.publicRoute = exports.RequestScopeError = exports.runInRequestScope = exports.getRequestScope = exports.requestScoped = exports.createRequestScopePlugin = exports.createTenantMembershipAssert = exports.canonicalRequestPath = exports.createAuthMiddleware = exports.InvalidTenantError = exports.createTenantMiddleware = exports.readRawTenantId = exports.resolveTenantId = void 0;
|
|
4
|
+
exports.DEFAULT_MASK_KEYS = exports.onlyChanged = exports.changedFields = exports.auditJson = exports.sanitizeForAudit = exports.AUDIT_WRITE_OPERATIONS = exports.AUDIT_COLUMNS = exports.createForbiddenThrottle = exports.clearAuditActorCache = exports.resolveAuditActor = exports.auditDate = exports.auditRow = exports.writeEntries = exports.getAuditContext = exports.runInAuditContext = exports.auditRaw = exports.auditEnabled = exports.withAudit = exports.createAuditQueryHandler = exports.createAuditExtension = exports.createAuditPlugin = exports.aclAllows = exports.defaultAclAction = exports.ACL_ACTION_FALLBACK = exports.DEFAULT_ACL_ACTIONS = exports.getAclRouteReport = exports.useModuleAcl = exports.createAclPlugin = exports.isFunctionRoleName = exports.FUNCTION_ROLE_ALIASES = exports.FUNCTION_ROLES = exports.FUNCTION_ROLE_PAIRS = exports.hasAnyOf = exports.hasAclName = exports.isSingleRoleList = exports.isRoleName = exports.ROLE_ALIASES = exports.RESPONSIBLE_ACLS = exports.STUDENT_ACLS = exports.TEACHER_ACLS = exports.AclConfigError = exports.evaluateAclRule = exports.resolveAclRule = exports.aclEntryIds = void 0;
|
|
4
5
|
var resolve_1 = require("./tenant/resolve");
|
|
5
6
|
Object.defineProperty(exports, "resolveTenantId", { enumerable: true, get: function () { return resolve_1.resolveTenantId; } });
|
|
6
7
|
Object.defineProperty(exports, "readRawTenantId", { enumerable: true, get: function () { return resolve_1.readRawTenantId; } });
|
|
@@ -59,4 +60,70 @@ Object.defineProperty(exports, "GeminiHelp", { enumerable: true, get: function (
|
|
|
59
60
|
Object.defineProperty(exports, "EMBED_DIM", { enumerable: true, get: function () { return gemini_1.EMBED_DIM; } });
|
|
60
61
|
Object.defineProperty(exports, "GEMINI_MODEL", { enumerable: true, get: function () { return gemini_1.GEMINI_MODEL; } });
|
|
61
62
|
Object.defineProperty(exports, "EMBED_MODEL", { enumerable: true, get: function () { return gemini_1.EMBED_MODEL; } });
|
|
63
|
+
// ---- permissões por usuário (cadeia users -> perfis -> políticas -> regras -> permissões) ----
|
|
64
|
+
var permissions_1 = require("./tenant/permissions");
|
|
65
|
+
Object.defineProperty(exports, "createPermissionsResolver", { enumerable: true, get: function () { return permissions_1.createPermissionsResolver; } });
|
|
66
|
+
Object.defineProperty(exports, "defaultPermissionsQuery", { enumerable: true, get: function () { return permissions_1.defaultPermissionsQuery; } });
|
|
67
|
+
Object.defineProperty(exports, "invalidatePermissionsCache", { enumerable: true, get: function () { return permissions_1.invalidatePermissionsCache; } });
|
|
68
|
+
Object.defineProperty(exports, "permissionsCacheKey", { enumerable: true, get: function () { return permissions_1.permissionsCacheKey; } });
|
|
69
|
+
Object.defineProperty(exports, "permissionsVersionKey", { enumerable: true, get: function () { return permissions_1.permissionsVersionKey; } });
|
|
70
|
+
// ---- cliente Redis padrão (best-effort, com timeout de conexão) ----
|
|
71
|
+
var client_1 = require("./redis/client");
|
|
72
|
+
Object.defineProperty(exports, "createRedisClient", { enumerable: true, get: function () { return client_1.createRedisClient; } });
|
|
73
|
+
Object.defineProperty(exports, "resolveRedisOptions", { enumerable: true, get: function () { return client_1.resolveRedisOptions; } });
|
|
74
|
+
Object.defineProperty(exports, "DEFAULT_REDIS_CONNECT_TIMEOUT_MS", { enumerable: true, get: function () { return client_1.DEFAULT_REDIS_CONNECT_TIMEOUT_MS; } });
|
|
75
|
+
// ---- ACL por endpoint (mapa do front) e auditoria de escrita ----
|
|
76
|
+
var map_generated_1 = require("./acl/map.generated");
|
|
77
|
+
Object.defineProperty(exports, "ACL_MAP", { enumerable: true, get: function () { return map_generated_1.ACL_MAP; } });
|
|
78
|
+
var check_1 = require("./acl/check");
|
|
79
|
+
Object.defineProperty(exports, "checkAcl", { enumerable: true, get: function () { return check_1.checkAcl; } });
|
|
80
|
+
Object.defineProperty(exports, "aclEntryIds", { enumerable: true, get: function () { return check_1.aclEntryIds; } });
|
|
81
|
+
Object.defineProperty(exports, "resolveAclRule", { enumerable: true, get: function () { return check_1.resolveAclRule; } });
|
|
82
|
+
Object.defineProperty(exports, "evaluateAclRule", { enumerable: true, get: function () { return check_1.evaluateAclRule; } });
|
|
83
|
+
Object.defineProperty(exports, "AclConfigError", { enumerable: true, get: function () { return check_1.AclConfigError; } });
|
|
84
|
+
var roles_1 = require("./acl/roles");
|
|
85
|
+
Object.defineProperty(exports, "TEACHER_ACLS", { enumerable: true, get: function () { return roles_1.TEACHER_ACLS; } });
|
|
86
|
+
Object.defineProperty(exports, "STUDENT_ACLS", { enumerable: true, get: function () { return roles_1.STUDENT_ACLS; } });
|
|
87
|
+
Object.defineProperty(exports, "RESPONSIBLE_ACLS", { enumerable: true, get: function () { return roles_1.RESPONSIBLE_ACLS; } });
|
|
88
|
+
Object.defineProperty(exports, "ROLE_ALIASES", { enumerable: true, get: function () { return roles_1.ROLE_ALIASES; } });
|
|
89
|
+
Object.defineProperty(exports, "isRoleName", { enumerable: true, get: function () { return roles_1.isRoleName; } });
|
|
90
|
+
Object.defineProperty(exports, "isSingleRoleList", { enumerable: true, get: function () { return roles_1.isSingleRoleList; } });
|
|
91
|
+
Object.defineProperty(exports, "hasAclName", { enumerable: true, get: function () { return roles_1.hasAclName; } });
|
|
92
|
+
Object.defineProperty(exports, "hasAnyOf", { enumerable: true, get: function () { return roles_1.hasAnyOf; } });
|
|
93
|
+
Object.defineProperty(exports, "FUNCTION_ROLE_PAIRS", { enumerable: true, get: function () { return roles_1.FUNCTION_ROLE_PAIRS; } });
|
|
94
|
+
Object.defineProperty(exports, "FUNCTION_ROLES", { enumerable: true, get: function () { return roles_1.FUNCTION_ROLES; } });
|
|
95
|
+
Object.defineProperty(exports, "FUNCTION_ROLE_ALIASES", { enumerable: true, get: function () { return roles_1.FUNCTION_ROLE_ALIASES; } });
|
|
96
|
+
Object.defineProperty(exports, "isFunctionRoleName", { enumerable: true, get: function () { return roles_1.isFunctionRoleName; } });
|
|
97
|
+
var plugin_3 = require("./acl/plugin");
|
|
98
|
+
Object.defineProperty(exports, "createAclPlugin", { enumerable: true, get: function () { return plugin_3.createAclPlugin; } });
|
|
99
|
+
Object.defineProperty(exports, "useModuleAcl", { enumerable: true, get: function () { return plugin_3.useModuleAcl; } });
|
|
100
|
+
Object.defineProperty(exports, "getAclRouteReport", { enumerable: true, get: function () { return plugin_3.getAclRouteReport; } });
|
|
101
|
+
Object.defineProperty(exports, "DEFAULT_ACL_ACTIONS", { enumerable: true, get: function () { return plugin_3.DEFAULT_ACL_ACTIONS; } });
|
|
102
|
+
Object.defineProperty(exports, "ACL_ACTION_FALLBACK", { enumerable: true, get: function () { return plugin_3.ACL_ACTION_FALLBACK; } });
|
|
103
|
+
Object.defineProperty(exports, "defaultAclAction", { enumerable: true, get: function () { return plugin_3.defaultAclAction; } });
|
|
104
|
+
var allows_1 = require("./acl/allows");
|
|
105
|
+
Object.defineProperty(exports, "aclAllows", { enumerable: true, get: function () { return allows_1.aclAllows; } });
|
|
106
|
+
var audit_1 = require("./audit/audit");
|
|
107
|
+
Object.defineProperty(exports, "createAuditPlugin", { enumerable: true, get: function () { return audit_1.createAuditPlugin; } });
|
|
108
|
+
Object.defineProperty(exports, "createAuditExtension", { enumerable: true, get: function () { return audit_1.createAuditExtension; } });
|
|
109
|
+
Object.defineProperty(exports, "createAuditQueryHandler", { enumerable: true, get: function () { return audit_1.createAuditQueryHandler; } });
|
|
110
|
+
Object.defineProperty(exports, "withAudit", { enumerable: true, get: function () { return audit_1.withAudit; } });
|
|
111
|
+
Object.defineProperty(exports, "auditEnabled", { enumerable: true, get: function () { return audit_1.auditEnabled; } });
|
|
112
|
+
Object.defineProperty(exports, "auditRaw", { enumerable: true, get: function () { return audit_1.auditRaw; } });
|
|
113
|
+
Object.defineProperty(exports, "runInAuditContext", { enumerable: true, get: function () { return audit_1.runInAuditContext; } });
|
|
114
|
+
Object.defineProperty(exports, "getAuditContext", { enumerable: true, get: function () { return audit_1.getAuditContext; } });
|
|
115
|
+
Object.defineProperty(exports, "writeEntries", { enumerable: true, get: function () { return audit_1.writeEntries; } });
|
|
116
|
+
Object.defineProperty(exports, "auditRow", { enumerable: true, get: function () { return audit_1.auditRow; } });
|
|
117
|
+
Object.defineProperty(exports, "auditDate", { enumerable: true, get: function () { return audit_1.auditDate; } });
|
|
118
|
+
Object.defineProperty(exports, "resolveAuditActor", { enumerable: true, get: function () { return audit_1.resolveAuditActor; } });
|
|
119
|
+
Object.defineProperty(exports, "clearAuditActorCache", { enumerable: true, get: function () { return audit_1.clearAuditActorCache; } });
|
|
120
|
+
Object.defineProperty(exports, "createForbiddenThrottle", { enumerable: true, get: function () { return audit_1.createForbiddenThrottle; } });
|
|
121
|
+
Object.defineProperty(exports, "AUDIT_COLUMNS", { enumerable: true, get: function () { return audit_1.AUDIT_COLUMNS; } });
|
|
122
|
+
Object.defineProperty(exports, "AUDIT_WRITE_OPERATIONS", { enumerable: true, get: function () { return audit_1.AUDIT_WRITE_OPERATIONS; } });
|
|
123
|
+
var serialize_1 = require("./audit/serialize");
|
|
124
|
+
Object.defineProperty(exports, "sanitizeForAudit", { enumerable: true, get: function () { return serialize_1.sanitizeForAudit; } });
|
|
125
|
+
Object.defineProperty(exports, "auditJson", { enumerable: true, get: function () { return serialize_1.auditJson; } });
|
|
126
|
+
Object.defineProperty(exports, "changedFields", { enumerable: true, get: function () { return serialize_1.changedFields; } });
|
|
127
|
+
Object.defineProperty(exports, "onlyChanged", { enumerable: true, get: function () { return serialize_1.onlyChanged; } });
|
|
128
|
+
Object.defineProperty(exports, "DEFAULT_MASK_KEYS", { enumerable: true, get: function () { return serialize_1.DEFAULT_MASK_KEYS; } });
|
|
62
129
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuditOptions } from "../audit/audit";
|
|
1
2
|
export type TenantClient<T> = T & {
|
|
2
3
|
$schema: string;
|
|
3
4
|
};
|
|
@@ -58,6 +59,11 @@ export interface MultitenantOptions<TClient, TPool extends PoolLike> {
|
|
|
58
59
|
statementTimeoutMs?: number;
|
|
59
60
|
log?: unknown;
|
|
60
61
|
errorFormat?: string;
|
|
62
|
+
/** Auditoria de escrita: tabelas listadas (ou "*") ganham log de quem/onde/
|
|
63
|
+
* antes/depois em `audit_logs`. Ausente ou `tables` vazio = client
|
|
64
|
+
* original, sem extensão. Precisa do createAuditPlugin registrado para
|
|
65
|
+
* saber quem fez. */
|
|
66
|
+
audit?: AuditOptions;
|
|
61
67
|
}
|
|
62
68
|
export interface Multitenant<TClient> {
|
|
63
69
|
pool: PoolLike;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.resolveStatementTimeout = resolveStatementTimeout;
|
|
12
12
|
exports.createMultitenantPrisma = createMultitenantPrisma;
|
|
13
|
+
const audit_1 = require("../audit/audit");
|
|
13
14
|
/** Teto de execução: opção > env DB_STATEMENT_TIMEOUT_MS > 60000; inválido ou negativo cai no default; 0 desliga. */
|
|
14
15
|
function resolveStatementTimeout(value) {
|
|
15
16
|
const raw = value ?? process.env.DB_STATEMENT_TIMEOUT_MS ?? 60000;
|
|
@@ -66,12 +67,15 @@ function createMultitenantPrisma(options) {
|
|
|
66
67
|
let client = clients.get(dbName);
|
|
67
68
|
if (!client) {
|
|
68
69
|
const adapter = new options.PrismaMariaDb(pool, { database: dbName });
|
|
69
|
-
|
|
70
|
+
const base = new options.PrismaClient({
|
|
70
71
|
adapter,
|
|
71
72
|
log: options.log,
|
|
72
73
|
errorFormat: options.errorFormat,
|
|
73
74
|
});
|
|
74
|
-
|
|
75
|
+
base.$schema = dbName;
|
|
76
|
+
client = (0, audit_1.auditEnabled)(options.audit)
|
|
77
|
+
? (0, audit_1.withAudit)(base, options.audit)
|
|
78
|
+
: base;
|
|
75
79
|
clients.set(dbName, client);
|
|
76
80
|
}
|
|
77
81
|
return client;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multitenant.js","sourceRoot":"","sources":["../../src/prisma/multitenant.ts"],"names":[],"mappings":";AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;;
|
|
1
|
+
{"version":3,"file":"multitenant.js","sourceRoot":"","sources":["../../src/prisma/multitenant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createClient } from "redis";
|
|
2
|
+
export type RedisClient = ReturnType<typeof createClient>;
|
|
3
|
+
export declare const DEFAULT_REDIS_CONNECT_TIMEOUT_MS = 3000;
|
|
4
|
+
export interface RedisClientOptions {
|
|
5
|
+
/** Opções do createClient. Default: JSON.parse(env.REDIS). */
|
|
6
|
+
options?: Record<string, any>;
|
|
7
|
+
/** Ambiente lido quando `options` não vem (default process.env). */
|
|
8
|
+
env?: Record<string, string | undefined>;
|
|
9
|
+
/** Tempo máximo para conectar, ms (default 3000). */
|
|
10
|
+
connectTimeoutMs?: number;
|
|
11
|
+
/** Fábrica do cliente (injeção para teste). Default: createClient do `redis`. */
|
|
12
|
+
createClient?: (options: any) => any;
|
|
13
|
+
/** Log de erro (default console.error). */
|
|
14
|
+
log?: (message: string, error?: unknown) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Opções finais do createClient (exportado para teste). */
|
|
17
|
+
export declare function resolveRedisOptions(options?: RedisClientOptions): Record<string, any> | undefined;
|
|
18
|
+
export declare function createRedisClient(options?: RedisClientOptions): Promise<RedisClient | undefined>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.resolveRedisOptions = resolveRedisOptions;
|
|
5
|
+
exports.createRedisClient = createRedisClient;
|
|
6
|
+
// Cliente Redis padrão das APIs. Antes cada API criava o
|
|
7
|
+
// seu (v1_pedagogico: infra.ts; v3_peoples: config/redis.ts) — a conexão
|
|
8
|
+
// agora mora aqui, UMA vez.
|
|
9
|
+
//
|
|
10
|
+
// Contrato: a env `REDIS` traz o JSON das opções do `createClient` do
|
|
11
|
+
// node-redis (vem do Secret Manager pelo workflow deploy-firebase-api-with-redis).
|
|
12
|
+
//
|
|
13
|
+
// Best-effort — nunca derruba o boot:
|
|
14
|
+
// - sem `REDIS`, JSON inválido ou falha na conexão → `undefined` (a API
|
|
15
|
+
// segue sem cache; quem usa testa o cliente antes);
|
|
16
|
+
// - timeout na conexão (default 3 s): o reconnect padrão do node-redis tenta
|
|
17
|
+
// para sempre e deixaria o boot da function preso esperando;
|
|
18
|
+
// - `disableOfflineQueue: true` por padrão: com a conexão caída, o comando
|
|
19
|
+
// falha na hora em vez de ficar na fila segurando a request (quem usa já
|
|
20
|
+
// trata erro como "sem cache"). As opções da env podem sobrescrever.
|
|
21
|
+
//
|
|
22
|
+
// O cliente devolvido serve direto como `redis` do createTenantMembershipAssert
|
|
23
|
+
// e do createPermissionsResolver (get/setEx).
|
|
24
|
+
const redis_1 = require("redis");
|
|
25
|
+
exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS = 3000;
|
|
26
|
+
/** Opções finais do createClient (exportado para teste). */
|
|
27
|
+
function resolveRedisOptions(options) {
|
|
28
|
+
let base = options?.options;
|
|
29
|
+
if (!base) {
|
|
30
|
+
const raw = (options?.env ?? process.env).REDIS;
|
|
31
|
+
if (!raw)
|
|
32
|
+
return undefined;
|
|
33
|
+
base = JSON.parse(String(raw));
|
|
34
|
+
}
|
|
35
|
+
if (!base || typeof base !== "object" || Array.isArray(base))
|
|
36
|
+
throw new Error("REDIS precisa ser um objeto JSON com as opções do createClient");
|
|
37
|
+
return { disableOfflineQueue: true, ...base };
|
|
38
|
+
}
|
|
39
|
+
async function createRedisClient(options = {}) {
|
|
40
|
+
const log = options.log ?? ((message, error) => console.error(message, error));
|
|
41
|
+
const factory = options.createClient ?? redis_1.createClient;
|
|
42
|
+
const timeoutMs = options.connectTimeoutMs ?? exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS;
|
|
43
|
+
let client;
|
|
44
|
+
try {
|
|
45
|
+
const clientOptions = resolveRedisOptions(options);
|
|
46
|
+
if (!clientOptions)
|
|
47
|
+
return undefined;
|
|
48
|
+
client = factory(clientOptions);
|
|
49
|
+
client.on?.("error", (err) => log("Redis Client Error", err));
|
|
50
|
+
let timer;
|
|
51
|
+
const timeout = new Promise((_, reject) => {
|
|
52
|
+
timer = setTimeout(() => reject(new Error(`timeout de ${timeoutMs}ms na conexão`)), timeoutMs);
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
await Promise.race([client.connect(), timeout]);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
return client;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
log("Redis não iniciado", err);
|
|
64
|
+
try {
|
|
65
|
+
client?.destroy?.();
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// cliente já descartado
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/redis/client.ts"],"names":[],"mappings":";;;AAsCA,kDASC;AAED,8CA8BC;AA/ED,yDAAyD;AACzD,yEAAyE;AACzE,4BAA4B;AAC5B,EAAE;AACF,sEAAsE;AACtE,mFAAmF;AACnF,EAAE;AACF,sCAAsC;AACtC,yEAAyE;AACzE,uDAAuD;AACvD,8EAA8E;AAC9E,gEAAgE;AAChE,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,EAAE;AACF,gFAAgF;AAChF,8CAA8C;AAC9C,iCAAmC;AAItB,QAAA,gCAAgC,GAAG,IAAI,CAAC;AAerD,4DAA4D;AAC5D,SAAgB,mBAAmB,CAAC,OAA4B;IAC5D,IAAI,IAAI,GAAG,OAAO,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAChD,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAChJ,OAAO,EAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,IAAI,EAAC,CAAC;AAChD,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,KAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACjG,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,IAAI,oBAAY,CAAC;IACrD,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,IAAI,wCAAgC,CAAC;IAE/E,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACD,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,aAAa;YAAE,OAAO,SAAS,CAAC;QACrC,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAC;QACvE,IAAI,KAAgD,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YACtC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,SAAS,eAAe,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACnG,CAAC,CAAC,CAAC;QACH,IAAI,CAAC;YACD,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QACpD,CAAC;gBAAS,CAAC;YACP,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,MAAqB,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACL,wBAAwB;QAC5B,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC"}
|
package/dist/tenant/auth.d.ts
CHANGED
|
@@ -9,8 +9,10 @@ export interface AuthMiddlewareOptions {
|
|
|
9
9
|
publicRoutes: PublicRouteLike[];
|
|
10
10
|
/** Resolve o Auth do tenant Firebase (ex: getTenantAuth do pkg) */
|
|
11
11
|
getTenantAuth: (tenantId: string | undefined) => TenantAuthLike;
|
|
12
|
-
/** false = API single-tenant (ex: core):
|
|
13
|
-
*
|
|
12
|
+
/** false = API single-tenant (ex: core): só vale token do tenant DEFAULT
|
|
13
|
+
* do Firebase. Chama getTenantAuth(undefined) — passe () => getDefaultAuth()
|
|
14
|
+
* — e token que carrega o claim firebase.tenant (usuário de escola) é
|
|
15
|
+
* recusado com 403, sem chamar o verifyIdToken. Default: true */
|
|
14
16
|
tenantAware?: boolean;
|
|
15
17
|
/** Aceitar token via ?token= (default: false — vaza em logs) */
|
|
16
18
|
allowQueryToken?: boolean;
|
package/dist/tenant/auth.js
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
// vazam em logs/histórico; só habilitar para fluxos que precisam (mídia).
|
|
10
10
|
// 3. Gancho `assertTenant` para amarrar o tenant do token ao id_school da
|
|
11
11
|
// URL (falha => 403) — o isolamento de dados exige esse vínculo.
|
|
12
|
+
// 4. `tenantAware: false` (core) aceita SÓ token do tenant default: token com
|
|
13
|
+
// o claim `firebase.tenant` (usuário de escola) responde 403.
|
|
12
14
|
//
|
|
13
15
|
// O tenant Firebase vem do claim `firebase.tenant` do próprio token; a
|
|
14
16
|
// VALIDAÇÃO criptográfica é do verifyIdToken do tenant correspondente —
|
|
@@ -51,7 +53,14 @@ function encodeParam(value) {
|
|
|
51
53
|
return "";
|
|
52
54
|
return encodeURIComponent(String(value));
|
|
53
55
|
}
|
|
56
|
+
const SCHOOL_TOKEN_MESSAGE = "Token de escola não é aceito nesta API";
|
|
57
|
+
/** O token (payload ou decodificado) carrega o claim firebase.tenant? */
|
|
58
|
+
function hasTenantClaim(token) {
|
|
59
|
+
const tenant = token?.firebase?.tenant;
|
|
60
|
+
return tenant !== undefined && tenant !== null && tenant !== "";
|
|
61
|
+
}
|
|
54
62
|
function createAuthMiddleware(options) {
|
|
63
|
+
const singleTenant = options.tenantAware === false;
|
|
55
64
|
const TOKEN_CACHE = new Map();
|
|
56
65
|
const MAX_CACHE_SIZE = options.cacheMaxSize ?? 2000;
|
|
57
66
|
const MAX_TTL_MS = options.cacheTtlMs ?? 120 * 1000;
|
|
@@ -127,6 +136,9 @@ function createAuthMiddleware(options) {
|
|
|
127
136
|
}
|
|
128
137
|
const cached = getCached(authHeader);
|
|
129
138
|
if (cached) {
|
|
139
|
+
if (singleTenant && hasTenantClaim(cached)) {
|
|
140
|
+
return reply.status(403).send({ message: SCHOOL_TOKEN_MESSAGE });
|
|
141
|
+
}
|
|
130
142
|
if (options.assertTenant) {
|
|
131
143
|
try {
|
|
132
144
|
await options.assertTenant(cached, request);
|
|
@@ -141,13 +153,28 @@ function createAuthMiddleware(options) {
|
|
|
141
153
|
return;
|
|
142
154
|
}
|
|
143
155
|
// o claim de tenant orienta QUAL Auth valida; a prova é criptográfica
|
|
156
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
|
|
144
157
|
let tenantId;
|
|
145
|
-
if (
|
|
146
|
-
|
|
158
|
+
if (singleTenant) {
|
|
159
|
+
// API single-tenant: token de escola não entra. O Auth default
|
|
160
|
+
// do firebase-admin valida a assinatura de token de QUALQUER
|
|
161
|
+
// tenant do projeto (só o TenantAwareAuth confere o claim);
|
|
162
|
+
// quem barrava era, por acaso, a busca do usuário na checagem
|
|
163
|
+
// de revogação. Recusar pelo payload é seguro: tirar o claim
|
|
164
|
+
// quebra a assinatura.
|
|
165
|
+
if (hasTenantClaim(payload)) {
|
|
166
|
+
return reply.status(403).send({ message: SCHOOL_TOKEN_MESSAGE });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
147
170
|
tenantId = payload?.firebase?.tenant;
|
|
148
171
|
}
|
|
149
172
|
const auth = options.getTenantAuth(tenantId);
|
|
150
173
|
const decodedToken = await auth.verifyIdToken(authHeader, true);
|
|
174
|
+
// a regra vale sobre o token VERIFICADO (o payload acima é só atalho)
|
|
175
|
+
if (singleTenant && hasTenantClaim(decodedToken)) {
|
|
176
|
+
return reply.status(403).send({ message: SCHOOL_TOKEN_MESSAGE });
|
|
177
|
+
}
|
|
151
178
|
setCached(authHeader, decodedToken, decodedToken.exp);
|
|
152
179
|
if (options.assertTenant) {
|
|
153
180
|
try {
|
package/dist/tenant/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/tenant/auth.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,EAAE;AACF,qEAAqE;AACrE,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,0EAA0E;AAC1E,6EAA6E;AAC7E,0EAA0E;AAC1E,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,mDAAmD;;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/tenant/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface PermissionsRedisLike {
|
|
2
|
+
get(key: string): Promise<string | null>;
|
|
3
|
+
setEx(key: string, ttlSeconds: number, value: string): Promise<unknown>;
|
|
4
|
+
}
|
|
5
|
+
export interface PermissionsResolverOptions {
|
|
6
|
+
/** Client Redis opcional (get/setEx). Sem ele, consulta o banco a cada request. */
|
|
7
|
+
redis?: PermissionsRedisLike;
|
|
8
|
+
/** TTL do cache, segundos (default 3600). */
|
|
9
|
+
cacheTtlSeconds?: number;
|
|
10
|
+
/** Identificadores de cada papel (default en + pt: teacher/professor,
|
|
11
|
+
* student/aluno, responsible/responsavel). */
|
|
12
|
+
roles?: {
|
|
13
|
+
teacher?: string | string[];
|
|
14
|
+
student?: string | string[];
|
|
15
|
+
responsible?: string | string[];
|
|
16
|
+
};
|
|
17
|
+
/** Consulta customizada: recebe o prisma da escola e o uid, devolve os identifiers. */
|
|
18
|
+
query?: (prisma: any, uid: string) => Promise<string[]>;
|
|
19
|
+
/** Log de erro (default console.error). */
|
|
20
|
+
logger?: (message: string, error?: unknown) => void;
|
|
21
|
+
}
|
|
22
|
+
/** A mesma consulta que as APIs usavam, com o uid como parâmetro. */
|
|
23
|
+
export declare function defaultPermissionsQuery(prisma: any, uid: string): Promise<string[]>;
|
|
24
|
+
export declare function createPermissionsResolver(options?: PermissionsResolverOptions): (req: any, idSchool: string | null) => Promise<void>;
|
|
25
|
+
/** Chave da versão do cache de permissões de uma escola. */
|
|
26
|
+
export declare function permissionsVersionKey(idSchool: string | number): string;
|
|
27
|
+
/** Chave do cache de permissões de um usuário numa versão. */
|
|
28
|
+
export declare function permissionsCacheKey(idSchool: string | number, version: string, uid: string): string;
|
|
29
|
+
export interface PermissionsInvalidationRedisLike {
|
|
30
|
+
incr(key: string): Promise<number>;
|
|
31
|
+
/** node-redis v4 devolve uma chave por iteração; v5, um lote (string[]). */
|
|
32
|
+
scanIterator?(options: {
|
|
33
|
+
MATCH: string;
|
|
34
|
+
COUNT?: number;
|
|
35
|
+
}): AsyncIterable<string | string[]>;
|
|
36
|
+
del?(keys: string | string[]): Promise<unknown>;
|
|
37
|
+
}
|
|
38
|
+
export interface InvalidatePermissionsOptions {
|
|
39
|
+
/** Também apaga as chaves do formato antigo `perms:<id>:<uid>` (cache sem
|
|
40
|
+
* versão), via SCAN — nunca KEYS. Ligar enquanto houver API no formato
|
|
41
|
+
* antigo lendo o cache. Default false. */
|
|
42
|
+
legacy?: boolean;
|
|
43
|
+
/** Log de erro (default console.error). */
|
|
44
|
+
logger?: (message: string, error?: unknown) => void;
|
|
45
|
+
}
|
|
46
|
+
export interface InvalidatePermissionsResult {
|
|
47
|
+
/** Nova versão da escola (null quando falhou). */
|
|
48
|
+
version: number | null;
|
|
49
|
+
/** Chaves antigas apagadas no modo legacy. */
|
|
50
|
+
legacyDeleted: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Invalida o cache de permissões de UMA escola: INCR em `perms_ver:<id>`.
|
|
54
|
+
* Chamar depois de qualquer escrita em permissões, regras, políticas,
|
|
55
|
+
* perfis ou vínculo usuário↔perfil (v1_acls). Nunca lança.
|
|
56
|
+
*/
|
|
57
|
+
export declare function invalidatePermissionsCache(redis: PermissionsInvalidationRedisLike | undefined | null, idSchool: string | number | null | undefined, options?: InvalidatePermissionsOptions): Promise<InvalidatePermissionsResult>;
|