emilsoftware-utilities 2.0.0-dev.82 → 2.0.0-dev.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/accessi/server/index.d.ts +4 -0
  2. package/dist/accessi/server/index.js +7 -1
  3. package/dist/accessi/server/index.js.map +1 -1
  4. package/dist/accessi/server/tenantRouter.d.ts +35 -0
  5. package/dist/accessi/server/tenantRouter.js +71 -0
  6. package/dist/accessi/server/tenantRouter.js.map +1 -0
  7. package/dist/accessi/server/tenantSupervisor.d.ts +60 -0
  8. package/dist/accessi/server/tenantSupervisor.js +296 -0
  9. package/dist/accessi/server/tenantSupervisor.js.map +1 -0
  10. package/dist/accessi/server/tenants.js +8 -0
  11. package/dist/accessi/server/tenants.js.map +1 -1
  12. package/dist/accessi-module/AccessiModule.js.map +1 -1
  13. package/dist/accessi-module/Console/console.js +1 -1
  14. package/dist/accessi-module/index.d.ts +1 -1
  15. package/dist/accessi-module/index.js +4 -3
  16. package/dist/accessi-module/index.js.map +1 -1
  17. package/dist/accessi-module/observability/metrics.js +13 -4
  18. package/dist/accessi-module/observability/metrics.js.map +1 -1
  19. package/dist/accessi-module/security/audit.d.ts +14 -4
  20. package/dist/accessi-module/security/audit.js +73 -48
  21. package/dist/accessi-module/security/audit.js.map +1 -1
  22. package/dist/accessi-module/tenancy/tenantContext.d.ts +15 -0
  23. package/dist/accessi-module/tenancy/tenantContext.js +26 -0
  24. package/dist/accessi-module/tenancy/tenantContext.js.map +1 -0
  25. package/dist/emilsoftware-utilities-2.0.0-dev.84.tgz +0 -0
  26. package/docs/adr/0002-multi-tenancy.md +9 -7
  27. package/docs/multi-tenancy.md +69 -3
  28. package/package.json +3 -3
  29. package/dist/emilsoftware-utilities-2.0.0-dev.82.tgz +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tenants.js","sourceRoot":"","sources":["../../../src/accessi/server/tenants.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync } from 'fs';\nimport { basename, join, resolve } from 'path';\nimport { WIRE_CRYPT_DISABLE, WIRE_CRYPT_ENABLE } from 'node-firebird';\nimport type { Options } from 'node-firebird';\nimport type {\n AccessiOptions,\n AccessiHttpOptions,\n AdminBootstrapOptions,\n CatalogScriptsOptions,\n ConsoleEntryOptions,\n EmailOptions,\n ExtensionFieldsOptions,\n FederatedAuthenticationOptions,\n JwtOptions,\n PublicAuthRateLimitOptions,\n PublicRegistrationOptions,\n ServiceTokenOptions,\n SystemSeedsOptions,\n} from '../../accessi-module/AccessiModule';\nimport type { AccessiEdgeRateLimitOptions } from '../../accessi-module/security/edgeRateLimit';\nimport type { AccessiAuthCookieOptions } from '../../accessi-module/security/authCookies';\nimport type { AccessiMetricsOptions } from '../../accessi-module/observability/metrics';\nimport type { AccessiAuditOptions } from '../../accessi-module/security/audit';\nimport type { SessionRevocationOptions } from '../../accessi-module/security/sessionRevocation';\nimport type { AccessTokenRevocationOptions } from '../../accessi-module/security/accessTokenRevocation';\nimport type { RefreshTokenRotationOptions } from '../../accessi-module/security/refreshTokenRotation';\nimport type { OpenApiSetupOptions } from '../../openapi/OpenApiConfig';\nimport { validateAccessiOptions } from '../../accessi-module/security/validateOptions';\n\n/** Identita e routing del tenant. */\nexport interface AccessiTenantSettings {\n /** Minuscole, numeri, `-` e `_`; max 63 caratteri. */\n id: string;\n /** Host esatti o wildcard `*.example.com`. */\n hosts?: string[];\n /** Prefisso path, es. `/acme`. */\n path?: string;\n /** Porta del processo quando si usa il supervisore. */\n port?: number;\n /** Default `true`. */\n enabled?: boolean;\n description?: string;\n}\n\n/** Connessione Firebird del tenant, tipizzata senza callback. */\nexport interface AccessiTenantDatabaseOptions {\n host: string;\n port?: number;\n database: string;\n user?: string;\n password?: string;\n /** `disabled`/`optional`; `required` e il default del driver. */\n wireCrypt?: 'required' | 'optional' | 'disabled';\n pluginName?: string;\n}\n\n/**\n * Configurazione serializzabile di un tenant.\n *\n * I campi che contengono store, callback o logger (`store`, `sink`, `match`,\n * `onDocument`, `logger`, ...) sono esclusi: vanno collegati dal backend\n * ospitante, non da un file di configurazione.\n */\nexport interface AccessiTenantEnvironment {\n tenant: AccessiTenantSettings;\n database: AccessiTenantDatabaseOptions;\n jwt: JwtOptions;\n email: EmailOptions;\n encryptionKey: string;\n confirmationEmailUrl: string;\n confirmationEmailReturnUrl: string;\n confirmationEmailPrefix?: string;\n customResetPage?: string;\n publicBaseUrl?: string;\n consoleApiBaseUrl?: string;\n mockDemoUser?: boolean;\n passwordExpiration?: boolean;\n passwordExpirationDays?: number;\n legacyPasswordMigrationOnStartup?: boolean;\n autoUpdateDatabase?: boolean;\n http?: AccessiHttpOptions;\n authCookie?: AccessiAuthCookieOptions;\n publicAuthRateLimit?: Omit<PublicAuthRateLimitOptions, 'store'>;\n publicRegistration?: PublicRegistrationOptions;\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n serviceTokens?: Omit<ServiceTokenOptions, 'rateLimitStore'>;\n catalogScripts?: CatalogScriptsOptions;\n systemSeeds?: SystemSeedsOptions;\n adminBootstrap?: AdminBootstrapOptions;\n openapi?: Omit<OpenApiSetupOptions, 'onDocument'>;\n consoleEntry?: Omit<ConsoleEntryOptions, 'store'>;\n edgeRateLimit?: Omit<AccessiEdgeRateLimitOptions, 'store' | 'match'>;\n sessionRevocation?: Omit<SessionRevocationOptions, 'store'>;\n accessTokenRevocation?: Omit<AccessTokenRevocationOptions, 'store'>;\n refreshTokenRotation?: Omit<RefreshTokenRotationOptions, 'store'>;\n metrics?: Omit<AccessiMetricsOptions, 'sink'>;\n audit?: Omit<AccessiAuditOptions, 'sinks' | 'store' | 'tenantId'>;\n bufferLogs?: boolean;\n}\n\nexport interface AccessiTenant {\n id: string;\n hosts: string[];\n path?: string;\n enabled: boolean;\n description?: string;\n port?: number;\n /** Nome del file `*.environment.ts` di origine (mai il contenuto). */\n file: string;\n environmentFile: string;\n options: AccessiOptions;\n}\n\nexport interface AccessiTenantSummary {\n id: string;\n hosts: string[];\n path?: string;\n enabled: boolean;\n description?: string;\n port?: number;\n file: string;\n database: {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n issuer?: string;\n audience?: string;\n jwtAlgorithm: string;\n refreshEnabled: boolean;\n}\n\nexport interface AccessiTenantResolution {\n tenant: AccessiTenant;\n matchedBy: 'host' | 'path' | 'header';\n}\n\nexport interface AccessiTenantRegistry {\n directory: string;\n tenants: AccessiTenant[];\n warnings: string[];\n allowHeader: boolean;\n byId: ReadonlyMap<string, AccessiTenant>;\n resolve(input: { host?: string; path?: string; header?: string }, options?: { allowHeader?: boolean }): AccessiTenantResolution | undefined;\n summary(): AccessiTenantSummary[];\n}\n\nexport interface LoadAccessiTenantsOptions {\n /** Cartella con `<id>.environment.ts`. */\n directory: string;\n /** Abilita la risoluzione via header `x-accessi-tenant`. Default: false. */\n allowHeader?: boolean;\n /** Consente issuer/audience uguali tra tenant (sconsigliato). Default: false. */\n allowSharedIssuer?: boolean;\n}\n\n/** Errore aggregato di configurazione tenant. */\nexport class AccessiTenantConfigurationError extends Error {\n readonly issues: string[];\n\n constructor(issues: string[]) {\n super(`Configurazione tenant non valida:\\n${issues.map((issue) => `- ${issue}`).join('\\n')}`);\n this.name = 'AccessiTenantConfigurationError';\n this.issues = issues;\n }\n}\n\n/**\n * Helper di tipizzazione per i file tenant.\n *\n * ```ts\n * import type { AccessiTenantEnvironment } from 'emilsoftware-utilities/accessi/server';\n * import { defineAccessiTenantEnvironment } from 'emilsoftware-utilities/accessi/server';\n *\n * export default defineAccessiTenantEnvironment({\n * tenant: { id: 'acme', hosts: ['accessi.acme.example.com'] },\n * database: { host: 'db-acme', database: '/data/acme.fdb' },\n * jwt: { secret: process.env.ACME_JWT_SECRET!, expiresIn: '1h' },\n * email: { ... },\n * encryptionKey: process.env.ACME_ENCRYPTION_KEY!,\n * confirmationEmailUrl: 'https://accessi.acme.example.com',\n * confirmationEmailReturnUrl: 'https://accessi.acme.example.com',\n * });\n * ```\n */\nexport function defineAccessiTenantEnvironment<const T extends AccessiTenantEnvironment>(\n environment: T,\n): T {\n return environment;\n}\n\nfunction normalizeHost(host: string): string {\n return host.trim().toLowerCase().replace(/\\.$/, '');\n}\n\nfunction normalizeTenantPath(path: string | undefined): string | undefined {\n if (path === undefined || path.trim() === '') return undefined;\n const normalized = `/${path.trim().replace(/^\\/+|\\/+$/g, '')}`;\n return normalized === '/' ? '/' : normalized;\n}\n\nfunction matchesHost(tenant: AccessiTenant, host: string): boolean {\n return tenant.hosts.some((candidate) => {\n if (candidate === host) return true;\n if (candidate.startsWith('*.')) {\n const suffix = candidate.slice(1);\n return host.endsWith(suffix) && host.length > suffix.length;\n }\n return false;\n });\n}\n\nfunction matchesPath(tenant: AccessiTenant, path: string): boolean {\n if (!tenant.path) return false;\n if (tenant.path === '/') return true;\n return path === tenant.path || path.startsWith(`${tenant.path}/`);\n}\n\n/** Prefisso Redis consigliato per isolare gli store del tenant. */\nexport function getAccessiTenantRedisPrefix(tenantId: string): string {\n return `accessi:${tenantId}:`;\n}\n\n/**\n * Converte la configurazione tipizzata in `AccessiOptions`.\n *\n * Applica i default di Firebird e collega `tenantId`; non crea store o sink,\n * che restano responsabilita del backend ospitante.\n */\nexport function accessiOptionsFromTenantEnvironment(\n environment: AccessiTenantEnvironment,\n): AccessiOptions {\n const database = environment.database;\n const databaseOptions: Options = {\n host: database.host,\n port: database.port ?? 3050,\n database: database.database,\n user: database.user ?? 'SYSDBA',\n password: database.password ?? 'masterkey',\n ...(database.pluginName ? { pluginName: database.pluginName } : {}),\n ...(database.wireCrypt === 'disabled'\n ? { wireCrypt: WIRE_CRYPT_DISABLE }\n : database.wireCrypt === 'optional'\n ? { wireCrypt: WIRE_CRYPT_ENABLE }\n : {}),\n };\n\n return {\n databaseOptions,\n confirmationEmailUrl: environment.confirmationEmailUrl,\n confirmationEmailReturnUrl: environment.confirmationEmailReturnUrl,\n ...(environment.confirmationEmailPrefix ? { confirmationEmailPrefix: environment.confirmationEmailPrefix } : {}),\n ...(environment.customResetPage ? { customResetPage: environment.customResetPage } : {}),\n ...(environment.publicBaseUrl ? { publicBaseUrl: environment.publicBaseUrl } : {}),\n ...(environment.consoleApiBaseUrl ? { consoleApiBaseUrl: environment.consoleApiBaseUrl } : {}),\n encryptionKey: environment.encryptionKey,\n mockDemoUser: environment.mockDemoUser ?? false,\n ...(environment.passwordExpiration !== undefined ? { passwordExpiration: environment.passwordExpiration } : {}),\n ...(environment.passwordExpirationDays !== undefined ? { passwordExpirationDays: environment.passwordExpirationDays } : {}),\n ...(environment.legacyPasswordMigrationOnStartup !== undefined\n ? { legacyPasswordMigrationOnStartup: environment.legacyPasswordMigrationOnStartup }\n : {}),\n ...(environment.autoUpdateDatabase !== undefined ? { autoUpdateDatabase: environment.autoUpdateDatabase } : {}),\n jwtOptions: environment.jwt,\n emailOptions: environment.email,\n ...(environment.http ? { http: environment.http } : {}),\n ...(environment.authCookie ? { authCookie: environment.authCookie } : {}),\n ...(environment.publicAuthRateLimit ? { publicAuthRateLimit: environment.publicAuthRateLimit } : {}),\n ...(environment.publicRegistration ? { publicRegistration: environment.publicRegistration } : {}),\n ...(environment.federatedAuthentication ? { federatedAuthentication: environment.federatedAuthentication } : {}),\n ...(environment.extensionFieldsOptions ? { extensionFieldsOptions: environment.extensionFieldsOptions } : {}),\n ...(environment.serviceTokens ? { serviceTokens: environment.serviceTokens } : {}),\n ...(environment.catalogScripts ? { catalogScripts: environment.catalogScripts } : {}),\n ...(environment.systemSeeds ? { systemSeeds: environment.systemSeeds } : {}),\n ...(environment.adminBootstrap ? { adminBootstrap: environment.adminBootstrap } : {}),\n ...(environment.openapi ? { openapi: environment.openapi } : {}),\n ...(environment.consoleEntry ? { consoleEntry: environment.consoleEntry } : {}),\n ...(environment.edgeRateLimit ? { edgeRateLimit: environment.edgeRateLimit } : {}),\n ...(environment.sessionRevocation ? { sessionRevocation: environment.sessionRevocation } : {}),\n ...(environment.accessTokenRevocation ? { accessTokenRevocation: environment.accessTokenRevocation } : {}),\n ...(environment.refreshTokenRotation ? { refreshTokenRotation: environment.refreshTokenRotation } : {}),\n ...(environment.metrics ? { metrics: environment.metrics } : {}),\n ...(environment.audit ? { audit: environment.audit } : {}),\n ...(environment.bufferLogs !== undefined ? { bufferLogs: environment.bufferLogs } : {}),\n tenantId: environment.tenant.id,\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction runtimeIssues(environment: unknown, file: string): string[] {\n const issues: string[] = [];\n if (!isRecord(environment)) {\n return [`${file}: il file deve esportare un oggetto (default export o export environment).`];\n }\n const tenant = environment.tenant;\n if (!isRecord(tenant)) {\n issues.push(`${file}: tenant mancante.`);\n } else {\n if (typeof tenant.id !== 'string' || !/^[a-z0-9][a-z0-9_-]{0,62}$/.test(tenant.id)) {\n issues.push(`${file}: tenant.id non valido (minuscole, numeri, - e _, max 63).`);\n }\n if (tenant.hosts !== undefined && (!Array.isArray(tenant.hosts) || tenant.hosts.some((host) => typeof host !== 'string'))) {\n issues.push(`${file}: tenant.hosts deve essere un array di stringhe.`);\n }\n if (tenant.path !== undefined && typeof tenant.path !== 'string') {\n issues.push(`${file}: tenant.path deve essere una stringa.`);\n }\n if (\n tenant.port !== undefined\n && (typeof tenant.port !== 'number' || !Number.isInteger(tenant.port) || tenant.port < 1 || tenant.port > 65535)\n ) {\n issues.push(`${file}: tenant.port non valida.`);\n }\n }\n\n const database = environment.database;\n if (!isRecord(database)) {\n issues.push(`${file}: database mancante.`);\n } else {\n if (typeof database.host !== 'string' || database.host.trim() === '') {\n issues.push(`${file}: database.host obbligatorio.`);\n }\n if (typeof database.database !== 'string' || database.database.trim() === '') {\n issues.push(`${file}: database.database obbligatorio.`);\n }\n if (\n database.port !== undefined\n && (typeof database.port !== 'number' || !Number.isInteger(database.port) || database.port < 1 || database.port > 65535)\n ) {\n issues.push(`${file}: database.port non valida.`);\n }\n }\n\n if (!isRecord(environment.jwt)) issues.push(`${file}: jwt mancante.`);\n else {\n if (typeof environment.jwt.secret !== 'string' || environment.jwt.secret === '') {\n issues.push(`${file}: jwt.secret obbligatorio.`);\n }\n if (typeof environment.jwt.expiresIn !== 'string' || environment.jwt.expiresIn === '') {\n issues.push(`${file}: jwt.expiresIn obbligatorio.`);\n }\n }\n\n if (!isRecord(environment.email)) issues.push(`${file}: email mancante.`);\n if (typeof environment.encryptionKey !== 'string' || environment.encryptionKey === '') {\n issues.push(`${file}: encryptionKey obbligatoria.`);\n }\n if (typeof environment.confirmationEmailUrl !== 'string') {\n issues.push(`${file}: confirmationEmailUrl obbligatoria.`);\n }\n if (typeof environment.confirmationEmailReturnUrl !== 'string') {\n issues.push(`${file}: confirmationEmailReturnUrl obbligatoria.`);\n }\n return issues;\n}\n\nfunction loadEnvironmentModule(file: string): unknown {\n if (/\\.(ts|mts|cts)$/i.test(file)) {\n // Caricamento lazy: jiti serve solo ai file tenant TypeScript.\n const { createJiti } = require('jiti') as {\n createJiti: (\n id: string,\n options?: { interopDefault?: boolean; moduleCache?: boolean; fsCache?: boolean },\n ) => (id: string) => unknown;\n };\n const jiti = createJiti(file, { interopDefault: true, moduleCache: false, fsCache: false });\n return jiti(file);\n }\n return require(file);\n}\n\n/**\n * Carica un singolo file `*.environment.ts`.\n *\n * Usa jiti per eseguire TypeScript anche nel pacchetto compilato, senza\n * richiedere un passo di build separato per i file tenant.\n */\nexport function loadAccessiTenantEnvironmentFile(file: string): { tenant: AccessiTenant; environment: AccessiTenantEnvironment } {\n const absolute = resolve(file);\n let loaded: unknown;\n try {\n loaded = loadEnvironmentModule(absolute);\n } catch (error) {\n throw new AccessiTenantConfigurationError([\n `${basename(file)}: impossibile caricare il file (${error instanceof Error ? error.message : String(error)}).`,\n ]);\n }\n\n const record = isRecord(loaded) ? loaded : {};\n const environment = (record.default ?? record.environment ?? loaded) as unknown;\n const issues = runtimeIssues(environment, basename(file));\n if (issues.length > 0) throw new AccessiTenantConfigurationError(issues);\n\n const typed = environment as AccessiTenantEnvironment;\n const settings = typed.tenant;\n const options = accessiOptionsFromTenantEnvironment(typed);\n const validation = validateAccessiOptions(options);\n const validationIssues = validation.errors.map((issue) => `${basename(file)}: ${issue.code}: ${issue.message}`);\n if (validationIssues.length > 0) throw new AccessiTenantConfigurationError(validationIssues);\n\n const hosts = (settings.hosts ?? []).map(normalizeHost).filter(Boolean);\n const path = normalizeTenantPath(settings.path);\n if (hosts.length === 0 && !path) {\n throw new AccessiTenantConfigurationError([\n `${basename(file)}: configurare tenant.hosts oppure tenant.path.`,\n ]);\n }\n\n const tenant: AccessiTenant = {\n id: settings.id,\n hosts,\n ...(path ? { path } : {}),\n enabled: settings.enabled !== false,\n ...(settings.description ? { description: settings.description } : {}),\n ...(settings.port ? { port: settings.port } : {}),\n file: basename(file),\n environmentFile: absolute,\n options,\n };\n return { tenant, environment: typed };\n}\n\n/**\n * Carica i tenant da una cartella di file `<id>.environment.ts`.\n *\n * La validazione e aggregata: un errore blocca l'intera cartella, cosi non si\n * avvia un tenant con configurazione parziale. Nessun segreto viene stampato.\n */\nexport function loadAccessiTenants(options: LoadAccessiTenantsOptions): AccessiTenantRegistry {\n if (!options?.directory) throw new Error('loadAccessiTenants: directory obbligatoria.');\n const directory = resolve(options.directory);\n const issues: string[] = [];\n const warnings: string[] = [];\n\n let files: string[];\n try {\n files = readdirSync(directory, { withFileTypes: true })\n .filter((entry) => entry.isFile() && /\\.environment\\.(ts|mts|cts|js|mjs|cjs)$/.test(entry.name))\n .map((entry) => entry.name)\n .sort();\n } catch (error) {\n throw new AccessiTenantConfigurationError([\n `Cartella tenant non leggibile (${directory}): ${error instanceof Error ? error.message : String(error)}`,\n ]);\n }\n if (files.length === 0) {\n throw new AccessiTenantConfigurationError([`Nessun file *.environment.ts nella cartella ${directory}.`]);\n }\n\n const tenants: AccessiTenant[] = [];\n for (const file of files) {\n try {\n tenants.push(loadAccessiTenantEnvironmentFile(join(directory, file)).tenant);\n } catch (error) {\n if (error instanceof AccessiTenantConfigurationError) issues.push(...error.issues);\n else issues.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n const byId = new Map<string, AccessiTenant>();\n const hostsSeen = new Map<string, string>();\n const pathsSeen = new Map<string, string>();\n const jwtSecrets = new Map<string, string>();\n const issuerAudience = new Map<string, string>();\n for (const tenant of tenants) {\n if (byId.has(tenant.id)) {\n issues.push(`Tenant duplicato \"${tenant.id}\" (${tenant.file} e ${byId.get(tenant.id)?.file}).`);\n } else {\n byId.set(tenant.id, tenant);\n }\n for (const host of tenant.hosts) {\n const existing = hostsSeen.get(host);\n if (existing) issues.push(`Host \"${host}\" assegnato a \"${existing}\" e \"${tenant.id}\".`);\n else hostsSeen.set(host, tenant.id);\n }\n if (tenant.path) {\n const existing = pathsSeen.get(tenant.path);\n if (existing) issues.push(`Path \"${tenant.path}\" assegnato a \"${existing}\" e \"${tenant.id}\".`);\n else pathsSeen.set(tenant.path, tenant.id);\n }\n\n // Un segreto JWT condiviso rende un token valido su piu tenant.\n const signingKey = tenant.options.jwtOptions.privateKey ?? tenant.options.jwtOptions.secret;\n const fingerprintKey = `${tenant.options.jwtOptions.algorithm ?? 'HS256'}|${signingKey}`;\n const existingKey = jwtSecrets.get(fingerprintKey);\n if (existingKey) {\n issues.push(`Chiave JWT condivisa tra \"${existingKey}\" e \"${tenant.id}\": usare segreti distinti.`);\n } else {\n jwtSecrets.set(fingerprintKey, tenant.id);\n }\n\n const issuer = tenant.options.jwtOptions.issuer ?? '(assente)';\n const audience = Array.isArray(tenant.options.jwtOptions.audience)\n ? tenant.options.jwtOptions.audience.join(',')\n : (tenant.options.jwtOptions.audience ?? '(assente)');\n const issuerKey = `${issuer}|${audience}`;\n const existingIssuer = issuerAudience.get(issuerKey);\n if (existingIssuer && options.allowSharedIssuer !== true) {\n warnings.push(`Issuer/audience \"${issuerKey}\" condivisi tra \"${existingIssuer}\" e \"${tenant.id}\".`);\n } else {\n issuerAudience.set(issuerKey, tenant.id);\n }\n }\n\n const enabled = tenants.filter((tenant) => tenant.enabled);\n if (enabled.length > 1) {\n const defaultTenant = enabled.find((tenant) => tenant.hosts.length === 0 && tenant.path === '/');\n if (defaultTenant) {\n issues.push(`Tenant \"${defaultTenant.id}\" intercetta tutte le richieste (path \"/\") insieme ad altri tenant.`);\n }\n }\n\n if (issues.length > 0) throw new AccessiTenantConfigurationError(issues);\n\n const registry: AccessiTenantRegistry = {\n directory,\n tenants,\n warnings,\n allowHeader: options.allowHeader === true,\n byId,\n resolve(input, resolveOptions) {\n const allowHeader = resolveOptions?.allowHeader ?? registry.allowHeader;\n const host = input.host ? normalizeHost(input.host.split(':')[0] ?? input.host) : undefined;\n if (host) {\n const byHost = enabled.find((tenant) => matchesHost(tenant, host));\n if (byHost) return { tenant: byHost, matchedBy: 'host' };\n }\n\n const requestPath = input.path ?? '/';\n const byPath = enabled\n .filter((tenant) => matchesPath(tenant, requestPath))\n .sort((left, right) => (right.path?.length ?? 0) - (left.path?.length ?? 0))[0];\n if (byPath && byPath.path !== '/') return { tenant: byPath, matchedBy: 'path' };\n\n if (allowHeader && input.header) {\n const headerId = input.header.trim().toLowerCase();\n const tenant = byId.get(headerId);\n if (tenant?.enabled) return { tenant, matchedBy: 'header' };\n }\n\n if (byPath) return { tenant: byPath, matchedBy: 'path' };\n return undefined;\n },\n summary() {\n return tenants.map((tenant) => {\n const database = tenant.options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n return {\n id: tenant.id,\n hosts: [...tenant.hosts],\n ...(tenant.path ? { path: tenant.path } : {}),\n enabled: tenant.enabled,\n ...(tenant.description ? { description: tenant.description } : {}),\n ...(tenant.port ? { port: tenant.port } : {}),\n file: tenant.file,\n database: {\n host: database.host,\n port: database.port,\n database: database.database,\n user: database.user,\n },\n issuer: tenant.options.jwtOptions.issuer,\n ...(tenant.options.jwtOptions.audience\n ? {\n audience: typeof tenant.options.jwtOptions.audience === 'string'\n ? tenant.options.jwtOptions.audience\n : tenant.options.jwtOptions.audience.join(','),\n }\n : {}),\n jwtAlgorithm: tenant.options.jwtOptions.algorithm ?? 'HS256',\n refreshEnabled: Boolean(tenant.options.jwtOptions.refreshExpiresIn),\n };\n });\n },\n };\n\n return registry;\n}\n"]}
1
+ {"version":3,"file":"tenants.js","sourceRoot":"","sources":["../../../src/accessi/server/tenants.ts"],"names":[],"mappings":";;;AA2LA,wEAIC;AA8BD,kEAEC;AAQD,kFAyDC;AA8FD,4EA2CC;AAQD,gDA+JC;AAhlBD,2BAAiC;AACjC,+BAA+C;AAC/C,iDAAsE;AAyBtE,mFAAuF;AAmIvF,iDAAiD;AACjD,MAAa,+BAAgC,SAAQ,KAAK;IAGxD,YAAY,MAAgB;QAC1B,KAAK,CAAC,sCAAsC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9F,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;QAC9C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AARD,0EAQC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,8BAA8B,CAC5C,WAAc;IAEd,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAwB;IACnD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC;IAC/D,OAAO,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC/C,CAAC;AAED,SAAS,WAAW,CAAC,MAAqB,EAAE,IAAY;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;QACrC,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACpC,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC9D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,MAAqB,EAAE,IAAY;IACtD,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAC/B,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;AACpE,CAAC;AAED,mEAAmE;AACnE,SAAgB,2BAA2B,CAAC,QAAgB;IAC1D,OAAO,WAAW,QAAQ,GAAG,CAAC;AAChC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mCAAmC,CACjD,WAAqC;;IAErC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;IACtC,MAAM,eAAe,iCACnB,IAAI,EAAE,QAAQ,CAAC,IAAI,EACnB,IAAI,EAAE,MAAA,QAAQ,CAAC,IAAI,mCAAI,IAAI,EAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAC3B,IAAI,EAAE,MAAA,QAAQ,CAAC,IAAI,mCAAI,QAAQ,EAC/B,QAAQ,EAAE,MAAA,QAAQ,CAAC,QAAQ,mCAAI,WAAW,IACvC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAChE,CAAC,QAAQ,CAAC,SAAS,KAAK,UAAU;QACnC,CAAC,CAAC,EAAE,SAAS,EAAE,kCAAkB,EAAE;QACnC,CAAC,CAAC,QAAQ,CAAC,SAAS,KAAK,UAAU;YACjC,CAAC,CAAC,EAAE,SAAS,EAAE,iCAAiB,EAAE;YAClC,CAAC,CAAC,EAAE,CAAC,CACV,CAAC;IAEF,6aACE,eAAe,EACf,oBAAoB,EAAE,WAAW,CAAC,oBAAoB,EACtD,0BAA0B,EAAE,WAAW,CAAC,0BAA0B,IAC/D,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,WAAW,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC7G,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACrF,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC/E,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,WAAW,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC9F,aAAa,EAAE,WAAW,CAAC,aAAa,EACxC,YAAY,EAAE,MAAA,WAAW,CAAC,YAAY,mCAAI,KAAK,KAC5C,CAAC,WAAW,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5G,CAAC,WAAW,CAAC,sBAAsB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,WAAW,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACxH,CAAC,WAAW,CAAC,gCAAgC,KAAK,SAAS;QAC5D,CAAC,CAAC,EAAE,gCAAgC,EAAE,WAAW,CAAC,gCAAgC,EAAE;QACpF,CAAC,CAAC,EAAE,CAAC,GACJ,CAAC,WAAW,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC/G,UAAU,EAAE,WAAW,CAAC,GAAG,EAC3B,YAAY,EAAE,WAAW,CAAC,KAAK,KAC5B,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACpD,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACtE,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,WAAW,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACjG,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC9F,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,WAAW,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC7G,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,WAAW,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC1G,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC/E,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAClF,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACzE,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAClF,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC7D,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5E,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC/E,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,WAAW,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC3F,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,WAAW,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACvG,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,WAAW,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACpG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC7D,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACvD,CAAC,WAAW,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACvF,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAC/B;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,aAAa,CAAC,WAAoB,EAAE,IAAY;IACvD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,IAAI,4EAA4E,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACnF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,4DAA4D,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1H,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,kDAAkD,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;QAC/D,CAAC;QACD,IACE,MAAM,CAAC,IAAI,KAAK,SAAS;eACtB,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,EAChH,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;IACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,sBAAsB,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC7E,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,mCAAmC,CAAC,CAAC;QAC1D,CAAC;QACD,IACE,QAAQ,CAAC,IAAI,KAAK,SAAS;eACxB,CAAC,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC,EACxH,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,6BAA6B,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC;SACjE,CAAC;QACJ,IAAI,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YAChF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,4BAA4B,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,OAAO,WAAW,CAAC,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,WAAW,CAAC,GAAG,CAAC,SAAS,KAAK,EAAE,EAAE,CAAC;YACtF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAC1E,IAAI,OAAO,WAAW,CAAC,aAAa,KAAK,QAAQ,IAAI,WAAW,CAAC,aAAa,KAAK,EAAE,EAAE,CAAC;QACtF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,+BAA+B,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,WAAW,CAAC,oBAAoB,KAAK,QAAQ,EAAE,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,sCAAsC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,WAAW,CAAC,0BAA0B,KAAK,QAAQ,EAAE,CAAC;QAC/D,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,4CAA4C,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,+DAA+D;QAC/D,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,MAAM,CAKpC,CAAC;QACF,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gCAAgC,CAAC,IAAY;;IAC3D,MAAM,QAAQ,GAAG,IAAA,cAAO,EAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,+BAA+B,CAAC;YACxC,GAAG,IAAA,eAAQ,EAAC,IAAI,CAAC,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;SAC/G,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,MAAM,WAAW,GAAG,CAAC,MAAA,MAAA,MAAM,CAAC,OAAO,mCAAI,MAAM,CAAC,WAAW,mCAAI,MAAM,CAAY,CAAC;IAChF,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,IAAA,eAAQ,EAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,+BAA+B,CAAC,MAAM,CAAC,CAAC;IAEzE,MAAM,KAAK,GAAG,WAAuC,CAAC;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC;IAC9B,MAAM,OAAO,GAAG,mCAAmC,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,IAAA,wCAAsB,EAAC,OAAO,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAA,eAAQ,EAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAChH,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IAE7F,MAAM,KAAK,GAAG,CAAC,MAAA,QAAQ,CAAC,KAAK,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,IAAI,+BAA+B,CAAC;YACxC,GAAG,IAAA,eAAQ,EAAC,IAAI,CAAC,gDAAgD;SAClE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,2EACV,EAAE,EAAE,QAAQ,CAAC,EAAE,EACf,KAAK,IACF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACzB,OAAO,EAAE,QAAQ,CAAC,OAAO,KAAK,KAAK,KAChC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACnE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACjD,IAAI,EAAE,IAAA,eAAQ,EAAC,IAAI,CAAC,EACpB,eAAe,EAAE,QAAQ,EACzB,OAAO,GACR,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,OAAkC;;IACnE,IAAI,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,CAAA;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACxF,MAAM,SAAS,GAAG,IAAA,cAAO,EAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,IAAA,gBAAW,EAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACpD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,yCAAyC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAC/F,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;aAC1B,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,+BAA+B,CAAC;YACxC,kCAAkC,SAAS,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAC1G,CAAC,CAAC;IACL,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,+BAA+B,CAAC,CAAC,+CAA+C,SAAS,GAAG,CAAC,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,gCAAgC,CAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,+BAA+B;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;;gBAC9E,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC,IAAI,MAAM,MAAA,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,0CAAE,IAAI,IAAI,CAAC,CAAC;QAClG,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,QAAQ;gBAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,kBAAkB,QAAQ,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;;gBACnF,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,QAAQ;gBAAE,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,kBAAkB,QAAQ,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;;gBAC1F,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,QAAQ;gBAAE,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,iBAAiB,QAAQ,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;;gBACzF,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,gEAAgE;QAChE,MAAM,UAAU,GAAG,MAAA,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,mCAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;QAC5F,MAAM,cAAc,GAAG,GAAG,MAAA,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,mCAAI,OAAO,IAAI,UAAU,EAAE,CAAC;QACzF,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACnD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,6BAA6B,WAAW,QAAQ,MAAM,CAAC,EAAE,4BAA4B,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,mCAAI,WAAW,CAAC;QAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAChE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YAC9C,CAAC,CAAC,CAAC,MAAA,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,mCAAI,WAAW,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC1C,MAAM,cAAc,GAAG,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,cAAc,IAAI,OAAO,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACzD,QAAQ,CAAC,IAAI,CAAC,oBAAoB,SAAS,oBAAoB,cAAc,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QACtG,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QACjG,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,WAAW,aAAa,CAAC,EAAE,qEAAqE,CAAC,CAAC;QAChH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,+BAA+B,CAAC,MAAM,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAA0B;QACtC,SAAS;QACT,OAAO;QACP,QAAQ;QACR,WAAW,EAAE,OAAO,CAAC,WAAW,KAAK,IAAI;QACzC,IAAI;QACJ,OAAO,CAAC,KAAK,EAAE,cAAc;;YAC3B,MAAM,WAAW,GAAG,MAAA,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,WAAW,mCAAI,QAAQ,CAAC,WAAW,CAAC;YACxE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,MAAA,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,mCAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5F,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;gBACnE,IAAI,MAAM;oBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;YAC3D,CAAC;YAED,MAAM,WAAW,GAAG,MAAA,KAAK,CAAC,IAAI,mCAAI,GAAG,CAAC;YACtC,MAAM,MAAM,GAAG,OAAO;iBACnB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;iBACpD,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,uBAAC,OAAA,CAAC,MAAA,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,mCAAI,CAAC,CAAC,GAAG,CAAC,MAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,MAAM,mCAAI,CAAC,CAAC,CAAA,EAAA,CAAC,CAAC,CAAC,CAAC,CAAC;YAClF,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;YAEhF,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAClC,IAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,OAAO;oBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;YAC9D,CAAC;YAED,IAAI,MAAM;gBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;YACzD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO;YACL,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;;gBAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,eAK/B,CAAC;gBACF,2GACE,EAAE,EAAE,MAAM,CAAC,EAAE,EACb,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IACrB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC7C,OAAO,EAAE,MAAM,CAAC,OAAO,KACpB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC/D,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC7C,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ,CAAC,IAAI;wBACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;wBACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;wBAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;qBACpB,EACD,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,KACrC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ;oBACpC,CAAC,CAAC;wBACE,QAAQ,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,KAAK,QAAQ;4BAC9D,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ;4BACpC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;qBACjD;oBACH,CAAC,CAAC,EAAE,CAAC,KACP,YAAY,EAAE,MAAA,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,mCAAI,OAAO,EAC5D,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,IACnE;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { readdirSync } from 'fs';\nimport { basename, join, resolve } from 'path';\nimport { WIRE_CRYPT_DISABLE, WIRE_CRYPT_ENABLE } from 'node-firebird';\nimport type { Options } from 'node-firebird';\nimport type {\n AccessiOptions,\n AccessiHttpOptions,\n AdminBootstrapOptions,\n CatalogScriptsOptions,\n ConsoleEntryOptions,\n EmailOptions,\n ExtensionFieldsOptions,\n FederatedAuthenticationOptions,\n JwtOptions,\n PublicAuthRateLimitOptions,\n PublicRegistrationOptions,\n ServiceTokenOptions,\n SystemSeedsOptions,\n} from '../../accessi-module/AccessiModule';\nimport type { AccessiEdgeRateLimitOptions } from '../../accessi-module/security/edgeRateLimit';\nimport type { AccessiAuthCookieOptions } from '../../accessi-module/security/authCookies';\nimport type { AccessiMetricsOptions } from '../../accessi-module/observability/metrics';\nimport type { AccessiAuditOptions } from '../../accessi-module/security/audit';\nimport type { SessionRevocationOptions } from '../../accessi-module/security/sessionRevocation';\nimport type { AccessTokenRevocationOptions } from '../../accessi-module/security/accessTokenRevocation';\nimport type { RefreshTokenRotationOptions } from '../../accessi-module/security/refreshTokenRotation';\nimport type { OpenApiSetupOptions } from '../../openapi/OpenApiConfig';\nimport { validateAccessiOptions } from '../../accessi-module/security/validateOptions';\n\n/** Identita e routing del tenant. */\nexport interface AccessiTenantSettings {\n /** Minuscole, numeri, `-` e `_`; max 63 caratteri. */\n id: string;\n /** Host esatti o wildcard `*.example.com`. */\n hosts?: string[];\n /** Prefisso path, es. `/acme`. */\n path?: string;\n /** Porta del processo quando si usa il supervisore. */\n port?: number;\n /** Default `true`. */\n enabled?: boolean;\n description?: string;\n}\n\n/** Connessione Firebird del tenant, tipizzata senza callback. */\nexport interface AccessiTenantDatabaseOptions {\n host: string;\n port?: number;\n database: string;\n user?: string;\n password?: string;\n /** `disabled`/`optional`; `required` e il default del driver. */\n wireCrypt?: 'required' | 'optional' | 'disabled';\n pluginName?: string;\n}\n\n/**\n * Configurazione serializzabile di un tenant.\n *\n * I campi che contengono store, callback o logger (`store`, `sink`, `match`,\n * `onDocument`, `logger`, ...) sono esclusi: vanno collegati dal backend\n * ospitante, non da un file di configurazione.\n */\nexport interface AccessiTenantEnvironment {\n tenant: AccessiTenantSettings;\n database: AccessiTenantDatabaseOptions;\n jwt: JwtOptions;\n email: EmailOptions;\n encryptionKey: string;\n confirmationEmailUrl: string;\n confirmationEmailReturnUrl: string;\n confirmationEmailPrefix?: string;\n customResetPage?: string;\n publicBaseUrl?: string;\n consoleApiBaseUrl?: string;\n mockDemoUser?: boolean;\n passwordExpiration?: boolean;\n passwordExpirationDays?: number;\n legacyPasswordMigrationOnStartup?: boolean;\n autoUpdateDatabase?: boolean;\n http?: AccessiHttpOptions;\n authCookie?: AccessiAuthCookieOptions;\n publicAuthRateLimit?: Omit<PublicAuthRateLimitOptions, 'store'>;\n publicRegistration?: PublicRegistrationOptions;\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n serviceTokens?: Omit<ServiceTokenOptions, 'rateLimitStore'>;\n catalogScripts?: CatalogScriptsOptions;\n systemSeeds?: SystemSeedsOptions;\n adminBootstrap?: AdminBootstrapOptions;\n openapi?: Omit<OpenApiSetupOptions, 'onDocument'>;\n consoleEntry?: Omit<ConsoleEntryOptions, 'store'>;\n edgeRateLimit?: Omit<AccessiEdgeRateLimitOptions, 'store' | 'match'>;\n sessionRevocation?: Omit<SessionRevocationOptions, 'store'>;\n accessTokenRevocation?: Omit<AccessTokenRevocationOptions, 'store'>;\n refreshTokenRotation?: Omit<RefreshTokenRotationOptions, 'store'>;\n metrics?: Omit<AccessiMetricsOptions, 'sink'>;\n audit?: Omit<AccessiAuditOptions, 'sinks' | 'store' | 'tenantId'>;\n bufferLogs?: boolean;\n}\n\nexport interface AccessiTenant {\n id: string;\n hosts: string[];\n path?: string;\n enabled: boolean;\n description?: string;\n port?: number;\n /** Nome del file `*.environment.ts` di origine (mai il contenuto). */\n file: string;\n environmentFile: string;\n options: AccessiOptions;\n}\n\nexport interface AccessiTenantSummary {\n id: string;\n hosts: string[];\n path?: string;\n enabled: boolean;\n description?: string;\n port?: number;\n file: string;\n database: {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n issuer?: string;\n audience?: string;\n jwtAlgorithm: string;\n refreshEnabled: boolean;\n}\n\nexport interface AccessiTenantResolution {\n tenant: AccessiTenant;\n matchedBy: 'host' | 'path' | 'header';\n}\n\nexport interface AccessiTenantRegistry {\n directory: string;\n tenants: AccessiTenant[];\n warnings: string[];\n allowHeader: boolean;\n byId: ReadonlyMap<string, AccessiTenant>;\n resolve(input: { host?: string; path?: string; header?: string }, options?: { allowHeader?: boolean }): AccessiTenantResolution | undefined;\n summary(): AccessiTenantSummary[];\n}\n\nexport interface LoadAccessiTenantsOptions {\n /** Cartella con `<id>.environment.ts`. */\n directory: string;\n /** Abilita la risoluzione via header `x-accessi-tenant`. Default: false. */\n allowHeader?: boolean;\n /** Consente issuer/audience uguali tra tenant (sconsigliato). Default: false. */\n allowSharedIssuer?: boolean;\n}\n\n/** Errore aggregato di configurazione tenant. */\nexport class AccessiTenantConfigurationError extends Error {\n readonly issues: string[];\n\n constructor(issues: string[]) {\n super(`Configurazione tenant non valida:\\n${issues.map((issue) => `- ${issue}`).join('\\n')}`);\n this.name = 'AccessiTenantConfigurationError';\n this.issues = issues;\n }\n}\n\n/**\n * Helper di tipizzazione per i file tenant.\n *\n * ```ts\n * import type { AccessiTenantEnvironment } from 'emilsoftware-utilities/accessi/server';\n * import { defineAccessiTenantEnvironment } from 'emilsoftware-utilities/accessi/server';\n *\n * export default defineAccessiTenantEnvironment({\n * tenant: { id: 'acme', hosts: ['accessi.acme.example.com'] },\n * database: { host: 'db-acme', database: '/data/acme.fdb' },\n * jwt: { secret: process.env.ACME_JWT_SECRET!, expiresIn: '1h' },\n * email: { ... },\n * encryptionKey: process.env.ACME_ENCRYPTION_KEY!,\n * confirmationEmailUrl: 'https://accessi.acme.example.com',\n * confirmationEmailReturnUrl: 'https://accessi.acme.example.com',\n * });\n * ```\n */\nexport function defineAccessiTenantEnvironment<const T extends AccessiTenantEnvironment>(\n environment: T,\n): T {\n return environment;\n}\n\nfunction normalizeHost(host: string): string {\n return host.trim().toLowerCase().replace(/\\.$/, '');\n}\n\nfunction normalizeTenantPath(path: string | undefined): string | undefined {\n if (path === undefined || path.trim() === '') return undefined;\n const normalized = `/${path.trim().replace(/^\\/+|\\/+$/g, '')}`;\n return normalized === '/' ? '/' : normalized;\n}\n\nfunction matchesHost(tenant: AccessiTenant, host: string): boolean {\n return tenant.hosts.some((candidate) => {\n if (candidate === host) return true;\n if (candidate.startsWith('*.')) {\n const suffix = candidate.slice(1);\n return host.endsWith(suffix) && host.length > suffix.length;\n }\n return false;\n });\n}\n\nfunction matchesPath(tenant: AccessiTenant, path: string): boolean {\n if (!tenant.path) return false;\n if (tenant.path === '/') return true;\n return path === tenant.path || path.startsWith(`${tenant.path}/`);\n}\n\n/** Prefisso Redis consigliato per isolare gli store del tenant. */\nexport function getAccessiTenantRedisPrefix(tenantId: string): string {\n return `accessi:${tenantId}:`;\n}\n\n/**\n * Converte la configurazione tipizzata in `AccessiOptions`.\n *\n * Applica i default di Firebird e collega `tenantId`; non crea store o sink,\n * che restano responsabilita del backend ospitante.\n */\nexport function accessiOptionsFromTenantEnvironment(\n environment: AccessiTenantEnvironment,\n): AccessiOptions {\n const database = environment.database;\n const databaseOptions: Options = {\n host: database.host,\n port: database.port ?? 3050,\n database: database.database,\n user: database.user ?? 'SYSDBA',\n password: database.password ?? 'masterkey',\n ...(database.pluginName ? { pluginName: database.pluginName } : {}),\n ...(database.wireCrypt === 'disabled'\n ? { wireCrypt: WIRE_CRYPT_DISABLE }\n : database.wireCrypt === 'optional'\n ? { wireCrypt: WIRE_CRYPT_ENABLE }\n : {}),\n };\n\n return {\n databaseOptions,\n confirmationEmailUrl: environment.confirmationEmailUrl,\n confirmationEmailReturnUrl: environment.confirmationEmailReturnUrl,\n ...(environment.confirmationEmailPrefix ? { confirmationEmailPrefix: environment.confirmationEmailPrefix } : {}),\n ...(environment.customResetPage ? { customResetPage: environment.customResetPage } : {}),\n ...(environment.publicBaseUrl ? { publicBaseUrl: environment.publicBaseUrl } : {}),\n ...(environment.consoleApiBaseUrl ? { consoleApiBaseUrl: environment.consoleApiBaseUrl } : {}),\n encryptionKey: environment.encryptionKey,\n mockDemoUser: environment.mockDemoUser ?? false,\n ...(environment.passwordExpiration !== undefined ? { passwordExpiration: environment.passwordExpiration } : {}),\n ...(environment.passwordExpirationDays !== undefined ? { passwordExpirationDays: environment.passwordExpirationDays } : {}),\n ...(environment.legacyPasswordMigrationOnStartup !== undefined\n ? { legacyPasswordMigrationOnStartup: environment.legacyPasswordMigrationOnStartup }\n : {}),\n ...(environment.autoUpdateDatabase !== undefined ? { autoUpdateDatabase: environment.autoUpdateDatabase } : {}),\n jwtOptions: environment.jwt,\n emailOptions: environment.email,\n ...(environment.http ? { http: environment.http } : {}),\n ...(environment.authCookie ? { authCookie: environment.authCookie } : {}),\n ...(environment.publicAuthRateLimit ? { publicAuthRateLimit: environment.publicAuthRateLimit } : {}),\n ...(environment.publicRegistration ? { publicRegistration: environment.publicRegistration } : {}),\n ...(environment.federatedAuthentication ? { federatedAuthentication: environment.federatedAuthentication } : {}),\n ...(environment.extensionFieldsOptions ? { extensionFieldsOptions: environment.extensionFieldsOptions } : {}),\n ...(environment.serviceTokens ? { serviceTokens: environment.serviceTokens } : {}),\n ...(environment.catalogScripts ? { catalogScripts: environment.catalogScripts } : {}),\n ...(environment.systemSeeds ? { systemSeeds: environment.systemSeeds } : {}),\n ...(environment.adminBootstrap ? { adminBootstrap: environment.adminBootstrap } : {}),\n ...(environment.openapi ? { openapi: environment.openapi } : {}),\n ...(environment.consoleEntry ? { consoleEntry: environment.consoleEntry } : {}),\n ...(environment.edgeRateLimit ? { edgeRateLimit: environment.edgeRateLimit } : {}),\n ...(environment.sessionRevocation ? { sessionRevocation: environment.sessionRevocation } : {}),\n ...(environment.accessTokenRevocation ? { accessTokenRevocation: environment.accessTokenRevocation } : {}),\n ...(environment.refreshTokenRotation ? { refreshTokenRotation: environment.refreshTokenRotation } : {}),\n ...(environment.metrics ? { metrics: environment.metrics } : {}),\n ...(environment.audit ? { audit: environment.audit } : {}),\n ...(environment.bufferLogs !== undefined ? { bufferLogs: environment.bufferLogs } : {}),\n tenantId: environment.tenant.id,\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction runtimeIssues(environment: unknown, file: string): string[] {\n const issues: string[] = [];\n if (!isRecord(environment)) {\n return [`${file}: il file deve esportare un oggetto (default export o export environment).`];\n }\n const tenant = environment.tenant;\n if (!isRecord(tenant)) {\n issues.push(`${file}: tenant mancante.`);\n } else {\n if (typeof tenant.id !== 'string' || !/^[a-z0-9][a-z0-9_-]{0,62}$/.test(tenant.id)) {\n issues.push(`${file}: tenant.id non valido (minuscole, numeri, - e _, max 63).`);\n }\n if (tenant.hosts !== undefined && (!Array.isArray(tenant.hosts) || tenant.hosts.some((host) => typeof host !== 'string'))) {\n issues.push(`${file}: tenant.hosts deve essere un array di stringhe.`);\n }\n if (tenant.path !== undefined && typeof tenant.path !== 'string') {\n issues.push(`${file}: tenant.path deve essere una stringa.`);\n }\n if (\n tenant.port !== undefined\n && (typeof tenant.port !== 'number' || !Number.isInteger(tenant.port) || tenant.port < 1 || tenant.port > 65535)\n ) {\n issues.push(`${file}: tenant.port non valida.`);\n }\n }\n\n const database = environment.database;\n if (!isRecord(database)) {\n issues.push(`${file}: database mancante.`);\n } else {\n if (typeof database.host !== 'string' || database.host.trim() === '') {\n issues.push(`${file}: database.host obbligatorio.`);\n }\n if (typeof database.database !== 'string' || database.database.trim() === '') {\n issues.push(`${file}: database.database obbligatorio.`);\n }\n if (\n database.port !== undefined\n && (typeof database.port !== 'number' || !Number.isInteger(database.port) || database.port < 1 || database.port > 65535)\n ) {\n issues.push(`${file}: database.port non valida.`);\n }\n }\n\n if (!isRecord(environment.jwt)) issues.push(`${file}: jwt mancante.`);\n else {\n if (typeof environment.jwt.secret !== 'string' || environment.jwt.secret === '') {\n issues.push(`${file}: jwt.secret obbligatorio.`);\n }\n if (typeof environment.jwt.expiresIn !== 'string' || environment.jwt.expiresIn === '') {\n issues.push(`${file}: jwt.expiresIn obbligatorio.`);\n }\n }\n\n if (!isRecord(environment.email)) issues.push(`${file}: email mancante.`);\n if (typeof environment.encryptionKey !== 'string' || environment.encryptionKey === '') {\n issues.push(`${file}: encryptionKey obbligatoria.`);\n }\n if (typeof environment.confirmationEmailUrl !== 'string') {\n issues.push(`${file}: confirmationEmailUrl obbligatoria.`);\n }\n if (typeof environment.confirmationEmailReturnUrl !== 'string') {\n issues.push(`${file}: confirmationEmailReturnUrl obbligatoria.`);\n }\n return issues;\n}\n\nfunction loadEnvironmentModule(file: string): unknown {\n if (/\\.(ts|mts|cts)$/i.test(file)) {\n // Caricamento lazy: jiti serve solo ai file tenant TypeScript.\n const { createJiti } = require('jiti') as {\n createJiti: (\n id: string,\n options?: { interopDefault?: boolean; moduleCache?: boolean; fsCache?: boolean },\n ) => (id: string) => unknown;\n };\n const jiti = createJiti(file, { interopDefault: true, moduleCache: false, fsCache: false });\n return jiti(file);\n }\n return require(file);\n}\n\n/**\n * Carica un singolo file `*.environment.ts`.\n *\n * Usa jiti per eseguire TypeScript anche nel pacchetto compilato, senza\n * richiedere un passo di build separato per i file tenant.\n */\nexport function loadAccessiTenantEnvironmentFile(file: string): { tenant: AccessiTenant; environment: AccessiTenantEnvironment } {\n const absolute = resolve(file);\n let loaded: unknown;\n try {\n loaded = loadEnvironmentModule(absolute);\n } catch (error) {\n throw new AccessiTenantConfigurationError([\n `${basename(file)}: impossibile caricare il file (${error instanceof Error ? error.message : String(error)}).`,\n ]);\n }\n\n const record = isRecord(loaded) ? loaded : {};\n const environment = (record.default ?? record.environment ?? loaded) as unknown;\n const issues = runtimeIssues(environment, basename(file));\n if (issues.length > 0) throw new AccessiTenantConfigurationError(issues);\n\n const typed = environment as AccessiTenantEnvironment;\n const settings = typed.tenant;\n const options = accessiOptionsFromTenantEnvironment(typed);\n const validation = validateAccessiOptions(options);\n const validationIssues = validation.errors.map((issue) => `${basename(file)}: ${issue.code}: ${issue.message}`);\n if (validationIssues.length > 0) throw new AccessiTenantConfigurationError(validationIssues);\n\n const hosts = (settings.hosts ?? []).map(normalizeHost).filter(Boolean);\n const path = normalizeTenantPath(settings.path);\n if (hosts.length === 0 && !path) {\n throw new AccessiTenantConfigurationError([\n `${basename(file)}: configurare tenant.hosts oppure tenant.path.`,\n ]);\n }\n\n const tenant: AccessiTenant = {\n id: settings.id,\n hosts,\n ...(path ? { path } : {}),\n enabled: settings.enabled !== false,\n ...(settings.description ? { description: settings.description } : {}),\n ...(settings.port ? { port: settings.port } : {}),\n file: basename(file),\n environmentFile: absolute,\n options,\n };\n return { tenant, environment: typed };\n}\n\n/**\n * Carica i tenant da una cartella di file `<id>.environment.ts`.\n *\n * La validazione e aggregata: un errore blocca l'intera cartella, cosi non si\n * avvia un tenant con configurazione parziale. Nessun segreto viene stampato.\n */\nexport function loadAccessiTenants(options: LoadAccessiTenantsOptions): AccessiTenantRegistry {\n if (!options?.directory) throw new Error('loadAccessiTenants: directory obbligatoria.');\n const directory = resolve(options.directory);\n const issues: string[] = [];\n const warnings: string[] = [];\n\n let files: string[];\n try {\n files = readdirSync(directory, { withFileTypes: true })\n .filter((entry) => entry.isFile() && /\\.environment\\.(ts|mts|cts|js|mjs|cjs)$/.test(entry.name))\n .map((entry) => entry.name)\n .sort();\n } catch (error) {\n throw new AccessiTenantConfigurationError([\n `Cartella tenant non leggibile (${directory}): ${error instanceof Error ? error.message : String(error)}`,\n ]);\n }\n if (files.length === 0) {\n throw new AccessiTenantConfigurationError([`Nessun file *.environment.ts nella cartella ${directory}.`]);\n }\n\n const tenants: AccessiTenant[] = [];\n for (const file of files) {\n try {\n tenants.push(loadAccessiTenantEnvironmentFile(join(directory, file)).tenant);\n } catch (error) {\n if (error instanceof AccessiTenantConfigurationError) issues.push(...error.issues);\n else issues.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n const byId = new Map<string, AccessiTenant>();\n const hostsSeen = new Map<string, string>();\n const pathsSeen = new Map<string, string>();\n const jwtSecrets = new Map<string, string>();\n const issuerAudience = new Map<string, string>();\n const portsSeen = new Map<number, string>();\n for (const tenant of tenants) {\n if (byId.has(tenant.id)) {\n issues.push(`Tenant duplicato \"${tenant.id}\" (${tenant.file} e ${byId.get(tenant.id)?.file}).`);\n } else {\n byId.set(tenant.id, tenant);\n }\n for (const host of tenant.hosts) {\n const existing = hostsSeen.get(host);\n if (existing) issues.push(`Host \"${host}\" assegnato a \"${existing}\" e \"${tenant.id}\".`);\n else hostsSeen.set(host, tenant.id);\n }\n if (tenant.path) {\n const existing = pathsSeen.get(tenant.path);\n if (existing) issues.push(`Path \"${tenant.path}\" assegnato a \"${existing}\" e \"${tenant.id}\".`);\n else pathsSeen.set(tenant.path, tenant.id);\n }\n if (tenant.port !== undefined) {\n const existing = portsSeen.get(tenant.port);\n if (existing) issues.push(`Porta ${tenant.port} assegnata a \"${existing}\" e \"${tenant.id}\".`);\n else portsSeen.set(tenant.port, tenant.id);\n }\n\n // Un segreto JWT condiviso rende un token valido su piu tenant.\n const signingKey = tenant.options.jwtOptions.privateKey ?? tenant.options.jwtOptions.secret;\n const fingerprintKey = `${tenant.options.jwtOptions.algorithm ?? 'HS256'}|${signingKey}`;\n const existingKey = jwtSecrets.get(fingerprintKey);\n if (existingKey) {\n issues.push(`Chiave JWT condivisa tra \"${existingKey}\" e \"${tenant.id}\": usare segreti distinti.`);\n } else {\n jwtSecrets.set(fingerprintKey, tenant.id);\n }\n\n const issuer = tenant.options.jwtOptions.issuer ?? '(assente)';\n const audience = Array.isArray(tenant.options.jwtOptions.audience)\n ? tenant.options.jwtOptions.audience.join(',')\n : (tenant.options.jwtOptions.audience ?? '(assente)');\n const issuerKey = `${issuer}|${audience}`;\n const existingIssuer = issuerAudience.get(issuerKey);\n if (existingIssuer && options.allowSharedIssuer !== true) {\n warnings.push(`Issuer/audience \"${issuerKey}\" condivisi tra \"${existingIssuer}\" e \"${tenant.id}\".`);\n } else {\n issuerAudience.set(issuerKey, tenant.id);\n }\n }\n\n const enabled = tenants.filter((tenant) => tenant.enabled);\n if (enabled.length > 1) {\n const defaultTenant = enabled.find((tenant) => tenant.hosts.length === 0 && tenant.path === '/');\n if (defaultTenant) {\n issues.push(`Tenant \"${defaultTenant.id}\" intercetta tutte le richieste (path \"/\") insieme ad altri tenant.`);\n }\n }\n\n if (issues.length > 0) throw new AccessiTenantConfigurationError(issues);\n\n const registry: AccessiTenantRegistry = {\n directory,\n tenants,\n warnings,\n allowHeader: options.allowHeader === true,\n byId,\n resolve(input, resolveOptions) {\n const allowHeader = resolveOptions?.allowHeader ?? registry.allowHeader;\n const host = input.host ? normalizeHost(input.host.split(':')[0] ?? input.host) : undefined;\n if (host) {\n const byHost = enabled.find((tenant) => matchesHost(tenant, host));\n if (byHost) return { tenant: byHost, matchedBy: 'host' };\n }\n\n const requestPath = input.path ?? '/';\n const byPath = enabled\n .filter((tenant) => matchesPath(tenant, requestPath))\n .sort((left, right) => (right.path?.length ?? 0) - (left.path?.length ?? 0))[0];\n if (byPath && byPath.path !== '/') return { tenant: byPath, matchedBy: 'path' };\n\n if (allowHeader && input.header) {\n const headerId = input.header.trim().toLowerCase();\n const tenant = byId.get(headerId);\n if (tenant?.enabled) return { tenant, matchedBy: 'header' };\n }\n\n if (byPath) return { tenant: byPath, matchedBy: 'path' };\n return undefined;\n },\n summary() {\n return tenants.map((tenant) => {\n const database = tenant.options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n return {\n id: tenant.id,\n hosts: [...tenant.hosts],\n ...(tenant.path ? { path: tenant.path } : {}),\n enabled: tenant.enabled,\n ...(tenant.description ? { description: tenant.description } : {}),\n ...(tenant.port ? { port: tenant.port } : {}),\n file: tenant.file,\n database: {\n host: database.host,\n port: database.port,\n database: database.database,\n user: database.user,\n },\n issuer: tenant.options.jwtOptions.issuer,\n ...(tenant.options.jwtOptions.audience\n ? {\n audience: typeof tenant.options.jwtOptions.audience === 'string'\n ? tenant.options.jwtOptions.audience\n : tenant.options.jwtOptions.audience.join(','),\n }\n : {}),\n jwtAlgorithm: tenant.options.jwtOptions.algorithm ?? 'HS256',\n refreshEnabled: Boolean(tenant.options.jwtOptions.refreshExpiresIn),\n };\n });\n },\n };\n\n return registry;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAU/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,sGAAmG;AACnG,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,4DAAuE;AACvE,sEAAsE;AACtE,4CAAyD;AACzD,iFAA8E;AAqTvE,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,IAAA,6BAAqB,EACnB,OAAO,CAAC,QAAQ;YACd,CAAC,iCAAM,CAAC,MAAA,OAAO,CAAC,KAAK,mCAAI,EAAE,CAAC,KAAE,QAAQ,EAAE,MAAA,MAAA,OAAO,CAAC,KAAK,0CAAE,QAAQ,mCAAI,OAAO,CAAC,QAAQ,IACnF,CAAC,CAAC,OAAO,CAAC,KAAK,CAClB,CAAC;QACF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B;aAAC;YAC7F,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AAnDY,sCAAa;wBAAb,aAAa;IArBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,iEAA+B;YAC/B,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;YAC9B,+CAAsB;SACvB;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B,CAAC;QACnU,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CAmDzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { INestApplication, LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm, AccessiUnknownKeyIdEvent } from './security/jwtTokenOptions';\nimport type { ConsoleEntryStore } from './security/consoleEntry';\nimport type { RateLimitStore } from './security/rateLimitStore';\nimport type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';\nimport type { SessionRevocationOptions } from './security/sessionRevocation';\nimport type { AccessTokenRevocationOptions } from './security/accessTokenRevocation';\nimport type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { FederatedAuthExchangeController } from './federated-auth/FederatedAuthExchangeController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { AccessiJwksBootstrapService } from './security/jwksBootstrap';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { configureAccessiAudit } from './security/audit';\nimport { AccessiAuditController } from './Controllers/AccessiAuditController';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */\n jwksPath?: string;\n /**\n * Chiavi pubbliche precedenti, esposte in JWKS e accettate in verifica\n * durante la rotazione. Se `keyId` e assente si usa il fingerprint della\n * chiave, lo stesso calcolato dalla JWKS.\n */\n previousPublicKeys?: Array<{\n publicKey: string;\n keyId?: string;\n algorithm?: AccessiAccessTokenAlgorithm;\n }>;\n /**\n * Alert quando un token presenta un `kid` assente da chiave corrente e\n * chiavi precedenti (tipico di una rotazione non completata).\n */\n onUnknownKeyId?: (event: AccessiUnknownKeyIdEvent) => void;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n /**\n * Durata del refresh token. Se assente il refresh token non viene emesso.\n * Consigliato: `30d`.\n */\n refreshExpiresIn?: string;\n}\n\n/** Configurazione dei ticket di ingresso alla console. */\nexport interface ConsoleEntryOptions {\n /** Durata del ticket in millisecondi. Default 60000. */\n ttlMs?: number;\n /** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */\n store?: ConsoleEntryStore;\n}\n\nimport type { AccessiSecurityHeadersSetting } from './security/securityHeaders';\nimport type { AccessiAuthCookieOptions } from './security/authCookies';\nimport type { AccessiMetricsOptions } from './observability/metrics';\nimport type { AccessiAuditOptions } from './security/audit';\n\n/** Impostazioni HTTP del servizio Accessi. */\nexport interface AccessiHttpOptions {\n /** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */\n cors?: Parameters<INestApplication['enableCors']>[0] | false;\n /** Trust proxy per IP reali dietro load balancer/reverse proxy. */\n trustProxy?: boolean | number | string;\n /** Header di sicurezza di base su console/OpenAPI. Default: true. */\n securityHeaders?: AccessiSecurityHeadersSetting;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n /** Store condiviso (es. Redis). Default: memoria del processo. */\n store?: RateLimitStore;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n refresh?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n /** Store condiviso per il rate limit dei service token. Default: memoria. */\n rateLimitStore?: RateLimitStore;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /**\n * Audit persistente: sink, retention ed endpoint amministrativi di query/export.\n */\n audit?: AccessiAuditOptions;\n /** Identificativo del tenant quando la configurazione arriva da una cartella multi-tenant. */\n tenantId?: string;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /** Base URL API per la console quando UI e API sono su domini diversi. */\n consoleApiBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n /** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */\n consoleEntry?: ConsoleEntryOptions;\n /** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */\n edgeRateLimit?: AccessiEdgeRateLimitOptions;\n /** CORS, trust proxy e header di sicurezza del servizio. */\n http?: AccessiHttpOptions;\n /**\n * Autenticazione opzionale via cookie httpOnly. Bearer resta il default:\n * la modalita si abilita passando questo oggetto (o `enabled: true`).\n */\n authCookie?: AccessiAuthCookieOptions;\n /** Metriche di dominio (login, 2FA, refresh, rate limit, store, ...). */\n metrics?: AccessiMetricsOptions;\n /** Revoca sessioni per utente tramite store memory/Redis. */\n sessionRevocation?: SessionRevocationOptions;\n /** Revoca dei singoli access token tramite `jti`, memory/Redis. */\n accessTokenRevocation?: AccessTokenRevocationOptions;\n /** Refresh token monouso tramite rotazione memory/Redis; rileva il riuso e revoca la famiglia. */\n refreshTokenRotation?: RefreshTokenRotationOptions;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n FederatedAuthExchangeController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n AccessiAuditController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n configureAccessiAudit(\n options.tenantId\n ? { ...(options.audit ?? {}), tenantId: options.audit?.tenantId ?? options.tenantId }\n : options.audit,\n );\n return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
1
+ {"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAU/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,sGAAmG;AACnG,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,4DAAuE;AACvE,sEAAsE;AACtE,4CAAyD;AACzD,iFAA8E;AAqTvE,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,IAAA,6BAAqB,EACnB,OAAO,CAAC,QAAQ;YACd,CAAC,iCAAM,CAAC,MAAA,OAAO,CAAC,KAAK,mCAAI,EAAE,CAAC,KAAE,QAAQ,EAAE,MAAA,MAAA,OAAO,CAAC,KAAK,0CAAE,QAAQ,mCAAI,OAAO,CAAC,QAAQ,IACnF,CAAC,CAAC,OAAO,CAAC,KAAK,CAClB,CAAC;QAAI,OAAO;YACX,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B;aAAC;YAC7F,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AAlDY,sCAAa;wBAAb,aAAa;IArBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,iEAA+B;YAC/B,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;YAC9B,+CAAsB;SACvB;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B,CAAC;QACnU,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CAkDzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { INestApplication, LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm, AccessiUnknownKeyIdEvent } from './security/jwtTokenOptions';\nimport type { ConsoleEntryStore } from './security/consoleEntry';\nimport type { RateLimitStore } from './security/rateLimitStore';\nimport type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';\nimport type { SessionRevocationOptions } from './security/sessionRevocation';\nimport type { AccessTokenRevocationOptions } from './security/accessTokenRevocation';\nimport type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { FederatedAuthExchangeController } from './federated-auth/FederatedAuthExchangeController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { AccessiJwksBootstrapService } from './security/jwksBootstrap';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { configureAccessiAudit } from './security/audit';\nimport { AccessiAuditController } from './Controllers/AccessiAuditController';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */\n jwksPath?: string;\n /**\n * Chiavi pubbliche precedenti, esposte in JWKS e accettate in verifica\n * durante la rotazione. Se `keyId` e assente si usa il fingerprint della\n * chiave, lo stesso calcolato dalla JWKS.\n */\n previousPublicKeys?: Array<{\n publicKey: string;\n keyId?: string;\n algorithm?: AccessiAccessTokenAlgorithm;\n }>;\n /**\n * Alert quando un token presenta un `kid` assente da chiave corrente e\n * chiavi precedenti (tipico di una rotazione non completata).\n */\n onUnknownKeyId?: (event: AccessiUnknownKeyIdEvent) => void;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n /**\n * Durata del refresh token. Se assente il refresh token non viene emesso.\n * Consigliato: `30d`.\n */\n refreshExpiresIn?: string;\n}\n\n/** Configurazione dei ticket di ingresso alla console. */\nexport interface ConsoleEntryOptions {\n /** Durata del ticket in millisecondi. Default 60000. */\n ttlMs?: number;\n /** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */\n store?: ConsoleEntryStore;\n}\n\nimport type { AccessiSecurityHeadersSetting } from './security/securityHeaders';\nimport type { AccessiAuthCookieOptions } from './security/authCookies';\nimport type { AccessiMetricsOptions } from './observability/metrics';\nimport type { AccessiAuditOptions } from './security/audit';\n\n/** Impostazioni HTTP del servizio Accessi. */\nexport interface AccessiHttpOptions {\n /** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */\n cors?: Parameters<INestApplication['enableCors']>[0] | false;\n /** Trust proxy per IP reali dietro load balancer/reverse proxy. */\n trustProxy?: boolean | number | string;\n /** Header di sicurezza di base su console/OpenAPI. Default: true. */\n securityHeaders?: AccessiSecurityHeadersSetting;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n /** Store condiviso (es. Redis). Default: memoria del processo. */\n store?: RateLimitStore;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n refresh?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n /** Store condiviso per il rate limit dei service token. Default: memoria. */\n rateLimitStore?: RateLimitStore;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /**\n * Audit persistente: sink, retention ed endpoint amministrativi di query/export.\n */\n audit?: AccessiAuditOptions;\n /** Identificativo del tenant quando la configurazione arriva da una cartella multi-tenant. */\n tenantId?: string;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /** Base URL API per la console quando UI e API sono su domini diversi. */\n consoleApiBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n /** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */\n consoleEntry?: ConsoleEntryOptions;\n /** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */\n edgeRateLimit?: AccessiEdgeRateLimitOptions;\n /** CORS, trust proxy e header di sicurezza del servizio. */\n http?: AccessiHttpOptions;\n /**\n * Autenticazione opzionale via cookie httpOnly. Bearer resta il default:\n * la modalita si abilita passando questo oggetto (o `enabled: true`).\n */\n authCookie?: AccessiAuthCookieOptions;\n /** Metriche di dominio (login, 2FA, refresh, rate limit, store, ...). */\n metrics?: AccessiMetricsOptions;\n /** Revoca sessioni per utente tramite store memory/Redis. */\n sessionRevocation?: SessionRevocationOptions;\n /** Revoca dei singoli access token tramite `jti`, memory/Redis. */\n accessTokenRevocation?: AccessTokenRevocationOptions;\n /** Refresh token monouso tramite rotazione memory/Redis; rileva il riuso e revoca la famiglia. */\n refreshTokenRotation?: RefreshTokenRotationOptions;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n FederatedAuthExchangeController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n AccessiAuditController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n configureAccessiAudit(\n options.tenantId\n ? { ...(options.audit ?? {}), tenantId: options.audit?.tenantId ?? options.tenantId }\n : options.audit,\n ); return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
@@ -1854,7 +1854,7 @@ function buildAiDigest() {
1854
1854
  }
1855
1855
 
1856
1856
  // src/accessi-module/Console/changelog.md
1857
- var changelog_default = "# Changelog Accessi\n\nNovit\xE0 e modifiche rilevanti della libreria `emilsoftware-utilities` (modulo Accessi).\n\n## Non rilasciato\n\n### Cambiamenti\n- Import: gli entry point (`accessi/server`, `accessi/resource-server`, `accessi/client*`, `accessi/contracts*`, `accessi/openapi`, `accessi/console`, `accessi/ui`) sono la via consigliata. Root barrel e deep import restano supportati fino alla prossima major; mappa di migrazione in `docs/import-migration.md`.\n- Sicurezza HTTP: CSP configurabile con nonce per la console, `'unsafe-inline'` documentato solo per Swagger UI, header frame/referrer/cache personalizzabili; guida in `docs/security-headers.md`.\n- Autenticazione: modalita opzionale a cookie `HttpOnly` con CSRF double-submit, refresh da cookie e supporto console; Bearer resta il default. Guida in `docs/auth-cookies.md`.\n- Observability: metriche Prometheus di dominio per login, 2FA, refresh, rate limit, introspection, JWKS, revoche, ticket console e store Redis, con alert suggeriti in `docs/metrics.md`.\n- Audit: sink memory/Redis/HTTP/callback, redazione ricorsiva, retention, query ed export NDJSON admin in `docs/audit.md`.\n- Multi-tenancy: un database per tenant senza modifiche allo schema, file `<id>.environment.ts` tipizzati (`AccessiTenantEnvironment`), validazione isolamento, risoluzione host/path/header fidato, supervisore processi, store Redis con prefisso automatico e template systemd/Docker/Nginx/Traefik in `deploy/`. Documentazione in `docs/multi-tenancy.md`.\n- Resource server: aggiunti `createAccessiAuthMiddleware`, `createAccessiAuthGuard`, `createAccessiTokenVerifier` e `createAccessiIntrospectionClient` per backend fratelli che non possiedono il database Accessi. Supporta HS256, RS/ES con chiave pubblica PEM e JWKS con cache.\n- Introspection: nuovo `POST /api/accessi/auth/introspect` protetto da service token con scope `accessi:introspect`. Restituisce `active`, profilo utente e grant correnti.\n- JWT: `jwtOptions` accetta `algorithm`, `issuer`, `audience`, `privateKey`, `publicKey`, `keyId`, `jwksPath` e `previousPublicKeys`. Default HS256 invariato; RS/ES sono consigliati per la topologia multi-servizio.\n- JWKS: con RS/ES Accessi pubblica `/accessi/.well-known/jwks.json` (path configurabile) con chiave corrente e chiavi precedenti per la rotazione. I resource server possono usare `jwks.url`.\n- Console ticket: introdotto `ConsoleEntryStore`. Default in memoria; `createRedisConsoleEntryStore` salva il JWT cifrato in Redis, usa TTL e consume atomico per il monouso multi-istanza. Configurazione in `consoleEntry.store` e `consoleEntry.ttlMs`.\n- Rate limit: introdotto `RateLimitStore`. `createRedisRateLimitStore` usa `INCR` + `PEXPIRE` atomici per contatori condivisi in cluster. Configurazione in `publicAuthRateLimit.store` e `serviceTokens.rateLimitStore`; default in memoria invariato.\n- Edge rate limit: aggiunto `createAccessiEdgeRateLimitMiddleware` e `AccessiOptions.edgeRateLimit` per una soglia grossolana per IP davanti alle rotte Accessi. Fail closed se lo store non risponde; supporta lo stesso store Redis.\n- Servizio standalone: aggiunti `createAccessiService`, `startAccessiService`, `/health/live`, `/health/ready`, `/health/metrics` e shutdown graceful. Aggiunti gli script `accessi:serve` e `accessi:serve:dist` per l'esecuzione come processo Node.\n- Configurazione: aggiunti `validateAccessiOptions` e `assertValidAccessiOptions`; il servizio standalone li applica al bootstrap.\n- HTTP: aggiunte opzioni `http.cors`, `http.trustProxy`, `http.securityHeaders`. La JWKS viene montata automaticamente anche con `AccessiModule.forRoot` tramite `HttpAdapterHost`.\n- SSO: aggiunto `POST /api/accessi/federated-auth/exchange` protetto da service token con scope `accessi:federated:exchange` per scambiare `{ provider, subject }` verificati da un backend fratello.\n- Audit: aggiunto `auditAccessi` per eventi di sicurezza strutturati; resource server ed edge rate limit registrano fallimenti di autenticazione, blocchi e rate limit non disponibile.\n- Contratto: aggiunto `npm run check:accessi-openapi`, eseguito nel build, che blocca path fuori prefisso, operationId duplicati/mancanti, $ref rotti, path legacy e rimozioni di operation/schema rispetto al fingerprint versionato.\n- Contratto: aggiunto `npm run accessi:update-openapi-fingerprint` per aggiornare intenzionalmente il fingerprint dopo una modifica breaking approvata.\n- Console: aggiunto `consoleApiBaseUrl` per servire UI e API su domini diversi; il valore viene iniettato in `window.__ACCESSI_API_BASE_URL__`.\n- Chiavi: aggiunto `npm run accessi:generate-jwt-keys` per generare coppia RS256/ES256, `keyId` e JWKS pubblica.\n- Sessioni: aggiunta la revoca per utente con `SessionRevocationStore` memory/Redis e `POST /api/accessi/auth/revoke-sessions`. Resource server e guard controllano il cutoff `iat`.\n- Refresh token: con `jwtOptions.refreshExpiresIn` login, 2FA e SSO emettono anche `refreshToken` (typ=refresh) e `POST /api/accessi/auth/refresh` restituisce una nuova coppia access+refresh. Gli access token hanno ora `jti`.\n- Refresh rotation: con `refreshTokenRotation.store` il refresh token e monouso e la rotazione e atomica tra istanze; due refresh concorrenti producono un solo successo.\n- Contratto: il fingerprint OpenAPI ora blocca anche la rimozione di operation/schema rispetto alla baseline versionata.\n- OpenAPI: aggiunto `mergeOpenApiDocuments` per unire il documento Accessi nel documento unico dell'host con conflitti espliciti.\n- Console: aggiunto `buildAccessiConsoleUrl` per linkare la console centrale senza mettere JWT nell'URL.\n- Rinomina: la configurazione e gli helper della documentazione usano `openapi`/`OpenApi` (`AccessiOptions.openapi`, `OpenApiSetupOptions`, `setupOpenApi`, `DEFAULT_ACCESSI_OPENAPI`); i vecchi nomi `swagger` non sono piu esportati.\n- Token Accessi: `TokenResult.expiresIn` riporta sempre la validita effettiva in secondi (es. `86400`), anche quando `jwtOptions.expiresIn` usa un formato leggibile come `24h`. I client possono quindi esporre `expires_in` anche per il token di login normale.\n- Console: nuova funzione **Login as** per superutenti e admin. Dalla lista utenti si genera un URL verso l'applicazione scelta con `?loginAsToken=<jwt>`; il token dura quanto la sessione Accessi standard (`jwtOptions.expiresIn`), registra l'attore nelle claim `act`/`loginAs` e resta soggetto alla gerarchia ADMIN > SUPER. Endpoint: `POST /api/accessi/user/login-as/:codiceUtente`.\n- Console: rimosse le sezioni **Filtri utente** e **Tipi filtro**. I filtri applicativi sono deprecati e non vengono pi\xF9 letti n\xE9 scritti dalla console; le tabelle restano invariate e la gestione torna manuale sul database.\n- Console: le conferme operative (es. \"Ruoli aggiornati\") ora compaiono come notifiche in alto a destra e scompaiono automaticamente.\n- Console: il salvataggio del profilo non invia pi\xF9 i campi della tabella `FILTRI`, evitando payload rifiutati dal backend. `UserService` tocca `FILTRI` solo se il chiamante invia esplicitamente almeno un campo legacy.\n- Console: scheda utente riorganizzata. \"Indietro\" resta nella barra superiore; stato registrazione, disattivazione ed eliminazione definitiva sono in un form coerente \"Stato e sicurezza\", con icone e tooltip allineati.\n- Console: pagina Changelog a larghezza piena, con intestazioni di versione evidenziate e sezioni orizzontali leggibili.\n- Seed `npm run accessi:seed-admin`: crea o aggiorna un admin completo (`FLGSUPER = 1` e `FLGADMIN = 1`) e corregge il nome colonna usato in precedenza (`FLGADMIN`).\n- Console: la pagina di default nella scheda utente \xE8 ora un autocomplete con ricerca. Propone tutte le rotte del catalogo menu, si filtra scrivendo ed \xE8 ancora possibile inserire un valore libero.\n- Autorizzazioni: i grant effettivi sommano ruoli e permessi diretti prendendo il livello massimo per menu. Un permesso diretto con livello inferiore (o 0) non annulla pi\xF9 il grant del ruolo.\n- Ruoli legacy: un menu senza descrizione non viene pi\xF9 scartato e un `TIPABI` mancante viene letto come livello 10, evitando utenti con ruolo ma senza accesso.\n- Grant dei ruoli arricchiti con i metadati di navigazione del catalogo menu (`pagina`, icona, gruppo, tipo): il frontend riceve gli stessi campi dei grant diretti e pu\xF2 costruire correttamente menu e rotte.\n- Sicurezza: `GET /api/accessi/permission/grants/:codiceUtente` accetta solo un JWT Accessi valido e consente la lettura solo al proprietario o a chi pu\xF2 gestire quel target (gerarchia ADMIN > SUPER). Un superutente non pu\xF2 leggere i grant di un admin.\n\n## 2.0.0-dev.50 (2026-10-15)\n\n### Cambiamenti\n- ORM: `Row` e `DbValue` sono i tipi predefiniti di `Orm.query` e `Orm.execute`; `transactionQuery` usa `Row[]`. Gli usi generici non devono pi\xF9 dichiarare `Record<string, unknown>`.\n- Build: il contratto OpenAPI generato (`src/accessi-module/openapi/`) \xE8 ignorato da Git e viene rigenerato da `npm run generate:accessi-openapi`.\n\n## 2.0.0-dev.49 (2026-10-15)\n\n### Cambiamenti\n- Documentazione HTTP rinominata da Swagger a **OpenAPI**: il modulo unificato espone `/accessi/openapi` e `/accessi/openapi.json`; `setupSwagger` usa `/openapi` come default.\n- Il path \xE8 configurabile tramite `EmilsoftwareOptions.swagger` (utile per far convivere pi\xF9 documentazioni).\n- Allineati log di avvio, Wiki e dispatch delle rotte del modulo.\n- L'alias storico `<path>-json` resta supportato.\n\n### Note\n- I consumer che aprivano `/swagger` o `/accessi/swagger` devono aggiornare l'URL alla nuova documentazione OpenAPI.\n\n## 2.0.0-dev.48 (2026-10-13)\n\n### Correzioni\n- `RestUtilities.sendErrorMessage` restituisce status HTTP specifici (400/401/403/4xx/5xx) e codici generici (`VALIDATION_ERROR`, `UNAUTHORIZED`, `FORBIDDEN`, `INTERNAL_ERROR`, `REQUEST_ERROR`), senza usare codici `ACCESSI_*` nel business helper.\n- Il messaggio restituito \xE8 quello reale dell'eccezione; gli errori testuali di validazione vengono riconosciuti come 400.\n\n## 2.0.0-dev.47 (2026-10-13)\n\n### Correzioni\n- Errore schema database reso generico: codice `DATABASE_SCHEMA_OUTDATED` e messaggio senza riferimenti specifici ad Accessi.\n\n## 2.0.0-dev.46 (2026-10-12)\n\n### Correzioni\n- `sendBaseResponse` resta retro-compatibile quando il terzo argomento \xE8 un tag stringa invece dello status HTTP.\n- Gestita la serializzazione dei `bigint`; gli errori di risposta vengono registrati con stack tramite `sendErrorMessage`.\n- `AccessiHttpExceptionFilter` registra gli errori con stack per facilitare la diagnosi.\n\n## 2.0.0-dev.45 (2026-10-12)\n\n### Correzioni\n- `set-gdpr` e l'aggiornamento di `flagGdpr` sono idempotenti: `UPDATE OR INSERT` su `UTENTI_GDPR` con `MATCHING (CODUTE, DATACC)`.\n- Evitate violazioni di chiave primaria e risposte 500 quando il consenso GDPR viene registrato pi\xF9 volte nello stesso giorno.\n\n## 2.0.0-dev.44\n\n### Aggiunte\n- Endpoint pubblico `GET /api/accessi/auth/bootstrap-admin/status` (`getAdminBootstrapStatus`): la console mostra la sezione \"Crea utente admin\" **solo** se `adminBootstrap.enabled` \xE8 `true`.\n\n### Correzioni\n- Rimossi i caratteri corrotti (mojibake UTF-8 \u2194 Windows-1252) da DTO, servizi, controller, console, OpenAPI e client generato (es. \"L'email \xE8 gi\xE0 associata a un utente Accessi.\").\n\n## 2.0.0-dev.43\n\n### Cambiamenti\n- Gerarchia dei ruoli formalizzata **ADMIN > SUPER > utente**: un superutente non puo' gestire un admin su `update-user`, `delete-user` (soft e hard), `set-password`, `force-password-reset`, `set-stato`, `assign-roles` e `assign-permissions` (`ensureCanManageTargetUser`, 403 se violato).\n- Guard **ultimo admin attivo**: non puo' essere disattivato, bloccato, eliminato o privato del flag Admin (400), per evitare il lockout della console.\n- Creazione utente (`create-managed-user` e registrazione pubblica) resa **atomica** rispetto all'invio email: fail-fast se SMTP non configurato e rollback dell'utente creato se l'invio fallisce (`ACCESSI_USER_INVITE_EMAIL_FAILED`).\n- Console: form password separato (Invio imposta la password invece di salvare il profilo), scheda utente in sola lettura per target di rango superiore.\n- SSO: anche il superutente puo' creare utenti SSO e gestirne identita/policy (`federated-auth/users/*`) sugli utenti non-admin; il catalogo dei provider SSO resta riservato agli admin.\n- Coerenza: i filtri utente (`saveFiltriUtente`) rispettano la gerarchia; il flag GDPR impostato dal profilo allinea anche `DATGDPR`; la scheda in sola lettura disabilita anche il collegamento SSO.\n- Eliminazione definitiva: se l'utente ha dati collegati (tabelle esterne/FK) risponde 400 con `code: ACCESSI_USER_DELETE_HAS_REFERENCES` e messaggio esplicito, suggerendo il soft delete (la hard delete resta invariata quando non ci sono vincoli).\n- Consenso GDPR completo: `update-user` con `flagGdpr` scrive anche la riga storica `UTENTI_GDPR`; in console il pulsante \"Registra consenso GDPR\" usa `set-gdpr`.\n- Console: aggiunto il pulsante \"Invia reset password legacy\" (super e admin).\n- Console: **auto-ingresso dal frontend** tramite ticket monouso (`POST /api/accessi/console/entry` + apertura di `#entry=<ticket>`), senza JWT nell'URL; il ticket e' legato all'utente, dura 60s, e' monouso e lo scambio e' protetto da rate limit (`publicAuthRateLimit.consoleEntry`).\n\n## 2.0.0-dev.42\n\n### Aggiunte\n- Gestione dei flag di privilegio dalla console Accessi:\n - un admin pu\xF2 assegnare o togliere sia `FLGADMIN` sia `FLGSUPER`;\n - un superutente senza `FLGADMIN` pu\xF2 gestire solo `FLGSUPER`;\n - i flag sono impostabili in creazione (utente locale o SSO) e in modifica profilo.\n- Eliminazione utenti con due modalit\xE0:\n - soft delete (`delete-user`, `STAREG=DELETE`) per admin e superutenti;\n - eliminazione definitiva (`delete-user-permanent`, solo admin) che rimuove in transazione utente e record collegati.\n- Gestione completa dell'utente dalla console (admin): anagrafica estesa (cellulare, lingua, avatar, metadata JSON), GDPR, scadenza password, tutti i filtri (`FILTRI`) e **impostazione diretta della password** (`POST /api/accessi/user/set-password/:codiceUtente`), senza accesso al database.\n- Scritture utente idempotenti: `UTENTI_CONFIG` in `UPDATE OR INSERT ... MATCHING (CODUTE)`; i campi non inviati restano invariati.\n- Policy password moderna quando si imposta una password (reset, set-password admin, bootstrap): minimo 8 caratteri con maiuscola, minuscola, cifra e carattere speciale, senza spazi e non comune. In caso di violazione risposta 400 con `code: ACCESSI_WEAK_PASSWORD` e `details`. La policy **non** si applica al login, cos\xEC le password preesistenti deboli continuano a funzionare.\n\n### Correzioni\n- Il backend verifica i flag in base al ruolo dell'utente connesso (`ensurePrivilegeFlagChanges`): inviare un flag non consentito restituisce 403.\n\n## 2.0.0-dev.33\n\n### Cambiamenti\n- Rimosse le logiche applicative residue dallo schema Accessi:\n - `MENU_GRP.NOMECAMPO`\n - `UTENTI.ENABLEIA`\n - `UTENTI_CONFIG.PAGDEF`\n - `UTENTI.CELLUTE`\n- Telefono canonico: `UTENTI_CONFIG.CELLULARE` (allargato a `VARCHAR(30)`).\n- Migrazione automatica: copia `UTENTI.CELLUTE` \u2192 `UTENTI_CONFIG.CELLULARE`, poi `DROP` delle colonne obsolete.\n- Ruoli chiariti:\n - `FLGSUPER`: superutente, riceve **tutte** le abilitazioni al livello massimo (30) dopo il login; in console vede **solo** la sezione **Utenti**.\n - `FLGADMIN`: accede a **tutta** la console (catalogo, token, SSO, utenti) ma **non** influisce sulle abilitazioni.\n- Aggiunta la sezione **Changelog** in console (sotto la Wiki).\n\n### Note\n- `FILTRI` e `FILTRI_TIPO` restano invariati (piano di migrazione futuro).\n- I backend che usavano i campi rimossi devono gestirli in tabelle proprie.\n\n## 2.0.0-dev.32\n\n### Cambiamenti\n- Rimosso il supporto ai flag applicativi in `UTENTI_CONFIG`: `FLGMOP`, `FLGPIANA`, `FLGADDETTI`, `FLGOSPITI`, `FLGPIANARFID`, `FLGCONTA`, `FLGCUBI`, `FLGCICLPASS`, `FLGDIPENDENTI`, `FLGINVENTARI`, `CAUMOV`, `NUMMAC`, `RAGSOCCLI`.\n- Rinominata la colonna `FLGADMINCONFIG` in `FLGADMIN` (con copia dei valori e `DROP`).\n\n## 2.0.0-dev.31\n\n### Aggiunte\n- Esposizione dei servizi Accessi all'host Express (`getAccessiModuleServices`) per delegare login, SSO e token senza reimplementarli.\n\n### Correzioni\n- `UserService.getUsers`: filtri estesi (`codiceUtente[]`, `numRep[]`, `codDipendente`, `cellulare`, `tipFil`, `flagSuper`).\n\n## 2.0.0-dev.24\n\n### Cambiamenti (breaking)\n- Chiavi JWT derivate per scopo (`access`, `reset`, `2fa`) e claim `typ` obbligatorio: gli access token precedenti non sono pi\xF9 validi.\n- Endpoint Allegati protetti di default.\n- Pool di connessioni attivo di default (`poolSize` 5).\n\n### Aggiunte\n- Service token macchina-a-macchina (gestione, guard, console).\n- CRUD completo dei cataloghi dalla console Accessi.\n- Supporto Firebird 2.5 nel migrator e nei test di integrazione.\n";
1857
+ var changelog_default = "# Changelog Accessi\n\nNovit\xE0 e modifiche rilevanti della libreria `emilsoftware-utilities` (modulo Accessi).\n\n## Non rilasciato\n\n### Cambiamenti\n- Import: gli entry point (`accessi/server`, `accessi/resource-server`, `accessi/client*`, `accessi/contracts*`, `accessi/openapi`, `accessi/console`, `accessi/ui`) sono la via consigliata. Root barrel e deep import restano supportati fino alla prossima major; mappa di migrazione in `docs/import-migration.md`.\n- Sicurezza HTTP: CSP configurabile con nonce per la console, `'unsafe-inline'` documentato solo per Swagger UI, header frame/referrer/cache personalizzabili; guida in `docs/security-headers.md`.\n- Autenticazione: modalita opzionale a cookie `HttpOnly` con CSRF double-submit, refresh da cookie e supporto console; Bearer resta il default. Guida in `docs/auth-cookies.md`.\n- Observability: metriche Prometheus di dominio per login, 2FA, refresh, rate limit, introspection, JWKS, revoche, ticket console e store Redis, con alert suggeriti in `docs/metrics.md`.\n- Audit: sink memory/Redis/HTTP/callback, redazione ricorsiva, retention, query ed export NDJSON admin in `docs/audit.md`.\n- Multi-tenancy: un database per tenant senza modifiche allo schema, file `<id>.environment.ts` tipizzati (`AccessiTenantEnvironment`), validazione isolamento, risoluzione host/path/header fidato, supervisore processi con `--watch`, store Redis con prefisso automatico, router in-process opt-in con contesto tenant e template systemd/Docker/Nginx/Traefik in `deploy/`. Documentazione in `docs/multi-tenancy.md`.\n- Resource server: aggiunti `createAccessiAuthMiddleware`, `createAccessiAuthGuard`, `createAccessiTokenVerifier` e `createAccessiIntrospectionClient` per backend fratelli che non possiedono il database Accessi. Supporta HS256, RS/ES con chiave pubblica PEM e JWKS con cache.\n- Introspection: nuovo `POST /api/accessi/auth/introspect` protetto da service token con scope `accessi:introspect`. Restituisce `active`, profilo utente e grant correnti.\n- JWT: `jwtOptions` accetta `algorithm`, `issuer`, `audience`, `privateKey`, `publicKey`, `keyId`, `jwksPath` e `previousPublicKeys`. Default HS256 invariato; RS/ES sono consigliati per la topologia multi-servizio.\n- JWKS: con RS/ES Accessi pubblica `/accessi/.well-known/jwks.json` (path configurabile) con chiave corrente e chiavi precedenti per la rotazione. I resource server possono usare `jwks.url`.\n- Console ticket: introdotto `ConsoleEntryStore`. Default in memoria; `createRedisConsoleEntryStore` salva il JWT cifrato in Redis, usa TTL e consume atomico per il monouso multi-istanza. Configurazione in `consoleEntry.store` e `consoleEntry.ttlMs`.\n- Rate limit: introdotto `RateLimitStore`. `createRedisRateLimitStore` usa `INCR` + `PEXPIRE` atomici per contatori condivisi in cluster. Configurazione in `publicAuthRateLimit.store` e `serviceTokens.rateLimitStore`; default in memoria invariato.\n- Edge rate limit: aggiunto `createAccessiEdgeRateLimitMiddleware` e `AccessiOptions.edgeRateLimit` per una soglia grossolana per IP davanti alle rotte Accessi. Fail closed se lo store non risponde; supporta lo stesso store Redis.\n- Servizio standalone: aggiunti `createAccessiService`, `startAccessiService`, `/health/live`, `/health/ready`, `/health/metrics` e shutdown graceful. Aggiunti gli script `accessi:serve` e `accessi:serve:dist` per l'esecuzione come processo Node.\n- Configurazione: aggiunti `validateAccessiOptions` e `assertValidAccessiOptions`; il servizio standalone li applica al bootstrap.\n- HTTP: aggiunte opzioni `http.cors`, `http.trustProxy`, `http.securityHeaders`. La JWKS viene montata automaticamente anche con `AccessiModule.forRoot` tramite `HttpAdapterHost`.\n- SSO: aggiunto `POST /api/accessi/federated-auth/exchange` protetto da service token con scope `accessi:federated:exchange` per scambiare `{ provider, subject }` verificati da un backend fratello.\n- Audit: aggiunto `auditAccessi` per eventi di sicurezza strutturati; resource server ed edge rate limit registrano fallimenti di autenticazione, blocchi e rate limit non disponibile.\n- Contratto: aggiunto `npm run check:accessi-openapi`, eseguito nel build, che blocca path fuori prefisso, operationId duplicati/mancanti, $ref rotti, path legacy e rimozioni di operation/schema rispetto al fingerprint versionato.\n- Contratto: aggiunto `npm run accessi:update-openapi-fingerprint` per aggiornare intenzionalmente il fingerprint dopo una modifica breaking approvata.\n- Console: aggiunto `consoleApiBaseUrl` per servire UI e API su domini diversi; il valore viene iniettato in `window.__ACCESSI_API_BASE_URL__`.\n- Chiavi: aggiunto `npm run accessi:generate-jwt-keys` per generare coppia RS256/ES256, `keyId` e JWKS pubblica.\n- Sessioni: aggiunta la revoca per utente con `SessionRevocationStore` memory/Redis e `POST /api/accessi/auth/revoke-sessions`. Resource server e guard controllano il cutoff `iat`.\n- Refresh token: con `jwtOptions.refreshExpiresIn` login, 2FA e SSO emettono anche `refreshToken` (typ=refresh) e `POST /api/accessi/auth/refresh` restituisce una nuova coppia access+refresh. Gli access token hanno ora `jti`.\n- Refresh rotation: con `refreshTokenRotation.store` il refresh token e monouso e la rotazione e atomica tra istanze; due refresh concorrenti producono un solo successo.\n- Contratto: il fingerprint OpenAPI ora blocca anche la rimozione di operation/schema rispetto alla baseline versionata.\n- OpenAPI: aggiunto `mergeOpenApiDocuments` per unire il documento Accessi nel documento unico dell'host con conflitti espliciti.\n- Console: aggiunto `buildAccessiConsoleUrl` per linkare la console centrale senza mettere JWT nell'URL.\n- Rinomina: la configurazione e gli helper della documentazione usano `openapi`/`OpenApi` (`AccessiOptions.openapi`, `OpenApiSetupOptions`, `setupOpenApi`, `DEFAULT_ACCESSI_OPENAPI`); i vecchi nomi `swagger` non sono piu esportati.\n- Token Accessi: `TokenResult.expiresIn` riporta sempre la validita effettiva in secondi (es. `86400`), anche quando `jwtOptions.expiresIn` usa un formato leggibile come `24h`. I client possono quindi esporre `expires_in` anche per il token di login normale.\n- Console: nuova funzione **Login as** per superutenti e admin. Dalla lista utenti si genera un URL verso l'applicazione scelta con `?loginAsToken=<jwt>`; il token dura quanto la sessione Accessi standard (`jwtOptions.expiresIn`), registra l'attore nelle claim `act`/`loginAs` e resta soggetto alla gerarchia ADMIN > SUPER. Endpoint: `POST /api/accessi/user/login-as/:codiceUtente`.\n- Console: rimosse le sezioni **Filtri utente** e **Tipi filtro**. I filtri applicativi sono deprecati e non vengono pi\xF9 letti n\xE9 scritti dalla console; le tabelle restano invariate e la gestione torna manuale sul database.\n- Console: le conferme operative (es. \"Ruoli aggiornati\") ora compaiono come notifiche in alto a destra e scompaiono automaticamente.\n- Console: il salvataggio del profilo non invia pi\xF9 i campi della tabella `FILTRI`, evitando payload rifiutati dal backend. `UserService` tocca `FILTRI` solo se il chiamante invia esplicitamente almeno un campo legacy.\n- Console: scheda utente riorganizzata. \"Indietro\" resta nella barra superiore; stato registrazione, disattivazione ed eliminazione definitiva sono in un form coerente \"Stato e sicurezza\", con icone e tooltip allineati.\n- Console: pagina Changelog a larghezza piena, con intestazioni di versione evidenziate e sezioni orizzontali leggibili.\n- Seed `npm run accessi:seed-admin`: crea o aggiorna un admin completo (`FLGSUPER = 1` e `FLGADMIN = 1`) e corregge il nome colonna usato in precedenza (`FLGADMIN`).\n- Console: la pagina di default nella scheda utente \xE8 ora un autocomplete con ricerca. Propone tutte le rotte del catalogo menu, si filtra scrivendo ed \xE8 ancora possibile inserire un valore libero.\n- Autorizzazioni: i grant effettivi sommano ruoli e permessi diretti prendendo il livello massimo per menu. Un permesso diretto con livello inferiore (o 0) non annulla pi\xF9 il grant del ruolo.\n- Ruoli legacy: un menu senza descrizione non viene pi\xF9 scartato e un `TIPABI` mancante viene letto come livello 10, evitando utenti con ruolo ma senza accesso.\n- Grant dei ruoli arricchiti con i metadati di navigazione del catalogo menu (`pagina`, icona, gruppo, tipo): il frontend riceve gli stessi campi dei grant diretti e pu\xF2 costruire correttamente menu e rotte.\n- Sicurezza: `GET /api/accessi/permission/grants/:codiceUtente` accetta solo un JWT Accessi valido e consente la lettura solo al proprietario o a chi pu\xF2 gestire quel target (gerarchia ADMIN > SUPER). Un superutente non pu\xF2 leggere i grant di un admin.\n\n## 2.0.0-dev.50 (2026-10-15)\n\n### Cambiamenti\n- ORM: `Row` e `DbValue` sono i tipi predefiniti di `Orm.query` e `Orm.execute`; `transactionQuery` usa `Row[]`. Gli usi generici non devono pi\xF9 dichiarare `Record<string, unknown>`.\n- Build: il contratto OpenAPI generato (`src/accessi-module/openapi/`) \xE8 ignorato da Git e viene rigenerato da `npm run generate:accessi-openapi`.\n\n## 2.0.0-dev.49 (2026-10-15)\n\n### Cambiamenti\n- Documentazione HTTP rinominata da Swagger a **OpenAPI**: il modulo unificato espone `/accessi/openapi` e `/accessi/openapi.json`; `setupSwagger` usa `/openapi` come default.\n- Il path \xE8 configurabile tramite `EmilsoftwareOptions.swagger` (utile per far convivere pi\xF9 documentazioni).\n- Allineati log di avvio, Wiki e dispatch delle rotte del modulo.\n- L'alias storico `<path>-json` resta supportato.\n\n### Note\n- I consumer che aprivano `/swagger` o `/accessi/swagger` devono aggiornare l'URL alla nuova documentazione OpenAPI.\n\n## 2.0.0-dev.48 (2026-10-13)\n\n### Correzioni\n- `RestUtilities.sendErrorMessage` restituisce status HTTP specifici (400/401/403/4xx/5xx) e codici generici (`VALIDATION_ERROR`, `UNAUTHORIZED`, `FORBIDDEN`, `INTERNAL_ERROR`, `REQUEST_ERROR`), senza usare codici `ACCESSI_*` nel business helper.\n- Il messaggio restituito \xE8 quello reale dell'eccezione; gli errori testuali di validazione vengono riconosciuti come 400.\n\n## 2.0.0-dev.47 (2026-10-13)\n\n### Correzioni\n- Errore schema database reso generico: codice `DATABASE_SCHEMA_OUTDATED` e messaggio senza riferimenti specifici ad Accessi.\n\n## 2.0.0-dev.46 (2026-10-12)\n\n### Correzioni\n- `sendBaseResponse` resta retro-compatibile quando il terzo argomento \xE8 un tag stringa invece dello status HTTP.\n- Gestita la serializzazione dei `bigint`; gli errori di risposta vengono registrati con stack tramite `sendErrorMessage`.\n- `AccessiHttpExceptionFilter` registra gli errori con stack per facilitare la diagnosi.\n\n## 2.0.0-dev.45 (2026-10-12)\n\n### Correzioni\n- `set-gdpr` e l'aggiornamento di `flagGdpr` sono idempotenti: `UPDATE OR INSERT` su `UTENTI_GDPR` con `MATCHING (CODUTE, DATACC)`.\n- Evitate violazioni di chiave primaria e risposte 500 quando il consenso GDPR viene registrato pi\xF9 volte nello stesso giorno.\n\n## 2.0.0-dev.44\n\n### Aggiunte\n- Endpoint pubblico `GET /api/accessi/auth/bootstrap-admin/status` (`getAdminBootstrapStatus`): la console mostra la sezione \"Crea utente admin\" **solo** se `adminBootstrap.enabled` \xE8 `true`.\n\n### Correzioni\n- Rimossi i caratteri corrotti (mojibake UTF-8 \u2194 Windows-1252) da DTO, servizi, controller, console, OpenAPI e client generato (es. \"L'email \xE8 gi\xE0 associata a un utente Accessi.\").\n\n## 2.0.0-dev.43\n\n### Cambiamenti\n- Gerarchia dei ruoli formalizzata **ADMIN > SUPER > utente**: un superutente non puo' gestire un admin su `update-user`, `delete-user` (soft e hard), `set-password`, `force-password-reset`, `set-stato`, `assign-roles` e `assign-permissions` (`ensureCanManageTargetUser`, 403 se violato).\n- Guard **ultimo admin attivo**: non puo' essere disattivato, bloccato, eliminato o privato del flag Admin (400), per evitare il lockout della console.\n- Creazione utente (`create-managed-user` e registrazione pubblica) resa **atomica** rispetto all'invio email: fail-fast se SMTP non configurato e rollback dell'utente creato se l'invio fallisce (`ACCESSI_USER_INVITE_EMAIL_FAILED`).\n- Console: form password separato (Invio imposta la password invece di salvare il profilo), scheda utente in sola lettura per target di rango superiore.\n- SSO: anche il superutente puo' creare utenti SSO e gestirne identita/policy (`federated-auth/users/*`) sugli utenti non-admin; il catalogo dei provider SSO resta riservato agli admin.\n- Coerenza: i filtri utente (`saveFiltriUtente`) rispettano la gerarchia; il flag GDPR impostato dal profilo allinea anche `DATGDPR`; la scheda in sola lettura disabilita anche il collegamento SSO.\n- Eliminazione definitiva: se l'utente ha dati collegati (tabelle esterne/FK) risponde 400 con `code: ACCESSI_USER_DELETE_HAS_REFERENCES` e messaggio esplicito, suggerendo il soft delete (la hard delete resta invariata quando non ci sono vincoli).\n- Consenso GDPR completo: `update-user` con `flagGdpr` scrive anche la riga storica `UTENTI_GDPR`; in console il pulsante \"Registra consenso GDPR\" usa `set-gdpr`.\n- Console: aggiunto il pulsante \"Invia reset password legacy\" (super e admin).\n- Console: **auto-ingresso dal frontend** tramite ticket monouso (`POST /api/accessi/console/entry` + apertura di `#entry=<ticket>`), senza JWT nell'URL; il ticket e' legato all'utente, dura 60s, e' monouso e lo scambio e' protetto da rate limit (`publicAuthRateLimit.consoleEntry`).\n\n## 2.0.0-dev.42\n\n### Aggiunte\n- Gestione dei flag di privilegio dalla console Accessi:\n - un admin pu\xF2 assegnare o togliere sia `FLGADMIN` sia `FLGSUPER`;\n - un superutente senza `FLGADMIN` pu\xF2 gestire solo `FLGSUPER`;\n - i flag sono impostabili in creazione (utente locale o SSO) e in modifica profilo.\n- Eliminazione utenti con due modalit\xE0:\n - soft delete (`delete-user`, `STAREG=DELETE`) per admin e superutenti;\n - eliminazione definitiva (`delete-user-permanent`, solo admin) che rimuove in transazione utente e record collegati.\n- Gestione completa dell'utente dalla console (admin): anagrafica estesa (cellulare, lingua, avatar, metadata JSON), GDPR, scadenza password, tutti i filtri (`FILTRI`) e **impostazione diretta della password** (`POST /api/accessi/user/set-password/:codiceUtente`), senza accesso al database.\n- Scritture utente idempotenti: `UTENTI_CONFIG` in `UPDATE OR INSERT ... MATCHING (CODUTE)`; i campi non inviati restano invariati.\n- Policy password moderna quando si imposta una password (reset, set-password admin, bootstrap): minimo 8 caratteri con maiuscola, minuscola, cifra e carattere speciale, senza spazi e non comune. In caso di violazione risposta 400 con `code: ACCESSI_WEAK_PASSWORD` e `details`. La policy **non** si applica al login, cos\xEC le password preesistenti deboli continuano a funzionare.\n\n### Correzioni\n- Il backend verifica i flag in base al ruolo dell'utente connesso (`ensurePrivilegeFlagChanges`): inviare un flag non consentito restituisce 403.\n\n## 2.0.0-dev.33\n\n### Cambiamenti\n- Rimosse le logiche applicative residue dallo schema Accessi:\n - `MENU_GRP.NOMECAMPO`\n - `UTENTI.ENABLEIA`\n - `UTENTI_CONFIG.PAGDEF`\n - `UTENTI.CELLUTE`\n- Telefono canonico: `UTENTI_CONFIG.CELLULARE` (allargato a `VARCHAR(30)`).\n- Migrazione automatica: copia `UTENTI.CELLUTE` \u2192 `UTENTI_CONFIG.CELLULARE`, poi `DROP` delle colonne obsolete.\n- Ruoli chiariti:\n - `FLGSUPER`: superutente, riceve **tutte** le abilitazioni al livello massimo (30) dopo il login; in console vede **solo** la sezione **Utenti**.\n - `FLGADMIN`: accede a **tutta** la console (catalogo, token, SSO, utenti) ma **non** influisce sulle abilitazioni.\n- Aggiunta la sezione **Changelog** in console (sotto la Wiki).\n\n### Note\n- `FILTRI` e `FILTRI_TIPO` restano invariati (piano di migrazione futuro).\n- I backend che usavano i campi rimossi devono gestirli in tabelle proprie.\n\n## 2.0.0-dev.32\n\n### Cambiamenti\n- Rimosso il supporto ai flag applicativi in `UTENTI_CONFIG`: `FLGMOP`, `FLGPIANA`, `FLGADDETTI`, `FLGOSPITI`, `FLGPIANARFID`, `FLGCONTA`, `FLGCUBI`, `FLGCICLPASS`, `FLGDIPENDENTI`, `FLGINVENTARI`, `CAUMOV`, `NUMMAC`, `RAGSOCCLI`.\n- Rinominata la colonna `FLGADMINCONFIG` in `FLGADMIN` (con copia dei valori e `DROP`).\n\n## 2.0.0-dev.31\n\n### Aggiunte\n- Esposizione dei servizi Accessi all'host Express (`getAccessiModuleServices`) per delegare login, SSO e token senza reimplementarli.\n\n### Correzioni\n- `UserService.getUsers`: filtri estesi (`codiceUtente[]`, `numRep[]`, `codDipendente`, `cellulare`, `tipFil`, `flagSuper`).\n\n## 2.0.0-dev.24\n\n### Cambiamenti (breaking)\n- Chiavi JWT derivate per scopo (`access`, `reset`, `2fa`) e claim `typ` obbligatorio: gli access token precedenti non sono pi\xF9 validi.\n- Endpoint Allegati protetti di default.\n- Pool di connessioni attivo di default (`poolSize` 5).\n\n### Aggiunte\n- Service token macchina-a-macchina (gestione, guard, console).\n- CRUD completo dei cataloghi dalla console Accessi.\n- Supporto Firebird 2.5 nel migrator e nei test di integrazione.\n";
1858
1858
 
1859
1859
  // src/accessi-module/Console/help.ts
1860
1860
  var p2 = (text) => ({ kind: "p", text });
@@ -39,7 +39,7 @@ export type { MemoryRateLimitStore, RateLimitDecision, RateLimitRedisClient, Rat
39
39
  export { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';
40
40
  export type { AccessiEdgeRateLimitMiddleware, AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';
41
41
  export { assertValidAccessiOptions, validateAccessiOptions } from './security/validateOptions';
42
- export { auditAccessi, configureAccessiAudit, getAccessiAuditStore, redactAccessiAuditValue, resetAccessiAudit } from './security/audit';
42
+ export { auditAccessi, configureAccessiAudit, configureAccessiTenantAudit, getAccessiAuditStore, redactAccessiAuditValue, resetAccessiAudit } from './security/audit';
43
43
  export type { AccessiAuditOptions, AccessiAuditPage, AccessiAuditQuery, AccessiAuditQueryableSink, AccessiAuditRecord, AccessiAuditSink } from './security/audit';
44
44
  export { createCallbackAccessiAuditSink, createHttpAccessiAuditSink, createMemoryAccessiAuditSink, createRedisAccessiAuditSink } from './security/auditSinks';
45
45
  export type { HttpAccessiAuditSinkOptions, MemoryAccessiAuditSink, MemoryAccessiAuditSinkOptions, RedisAccessiAuditSinkOptions } from './security/auditSinks';
@@ -26,9 +26,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.ServiceTokenService = exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.leadingStatementKeyword = exports.analyzeCatalogScript = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.revokeAccessiAccessTokenIfConfigured = exports.revokeAccessiAccessToken = exports.isAccessiAccessTokenRevoked = exports.getAccessTokenRevocationStore = exports.createRedisAccessTokenRevocationStore = exports.createMemoryAccessTokenRevocationStore = exports.revokeRefreshTokenFamily = exports.isRefreshTokenFamilyRevoked = exports.getRefreshTokenRotationStore = exports.consumeRefreshToken = exports.createRedisRefreshTokenRotationStore = exports.createMemoryRefreshTokenRotationStore = exports.getSessionRevocationStore = exports.isAccessiTokenRevoked = exports.revokeAccessiUserSessionsIfConfigured = exports.revokeAccessiUserSessions = exports.createRedisSessionRevocationStore = exports.createMemorySessionRevocationStore = exports.createRedisAccessiAuditSink = exports.createMemoryAccessiAuditSink = exports.createHttpAccessiAuditSink = exports.createCallbackAccessiAuditSink = exports.resetAccessiAudit = exports.redactAccessiAuditValue = exports.getAccessiAuditStore = exports.configureAccessiAudit = exports.auditAccessi = exports.validateAccessiOptions = exports.assertValidAccessiOptions = exports.createAccessiEdgeRateLimitMiddleware = exports.getDefaultRateLimitStore = exports.createRedisRateLimitStore = exports.createMemoryRateLimitStore = exports.getDefaultConsoleEntryStore = exports.createRedisConsoleEntryStore = exports.createMemoryConsoleEntryStore = exports.AccessiDatabaseUpdater = exports.FederatedAuthExchangeController = exports.AccessiAuditController = exports.AccessiIntrospectionController = exports.AccessiModule = void 0;
30
- exports.verifyAccessiJwt = exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.instrumentAccessiRedisClient = exports.resetAccessiMetrics = exports.renderAccessiMetrics = exports.recordAccessiMetric = exports.recordAccessiDuration = exports.observeAccessiMetric = exports.getAccessiMetricsSink = exports.getAccessiMetricsRegistry = exports.createAccessiMetricsRegistry = exports.countAccessiMetric = exports.accessiMetricName = exports.isAccessiCsrfExemptPath = exports.parseAccessiCookieHeader = exports.applyAccessiAuthCookies = exports.clearAccessiAuthCookies = exports.setAccessiAuthCookies = exports.getAccessiRefreshTokenFromCookie = exports.getAccessiAccessTokenFromCookie = exports.resolveAccessiAuthCookieOptions = exports.createAccessiAuthCookieMiddleware = exports.resolveAccessiSecurityHeaders = exports.createAccessiSecurityHeadersMiddleware = exports.buildAccessiContentSecurityPolicy = exports.applyAccessiContentSecurityPolicy = exports.applyAccessiBaseSecurityHeaders = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.isValidAdminBootstrapToken = exports.clearAdminBootstrapToken = exports.getAdminBootstrapToken = exports.getOrCreateAdminBootstrapToken = exports.AdminBootstrapService = exports.SchemaExportService = void 0;
31
- exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = void 0;
29
+ exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.leadingStatementKeyword = exports.analyzeCatalogScript = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.revokeAccessiAccessTokenIfConfigured = exports.revokeAccessiAccessToken = exports.isAccessiAccessTokenRevoked = exports.getAccessTokenRevocationStore = exports.createRedisAccessTokenRevocationStore = exports.createMemoryAccessTokenRevocationStore = exports.revokeRefreshTokenFamily = exports.isRefreshTokenFamilyRevoked = exports.getRefreshTokenRotationStore = exports.consumeRefreshToken = exports.createRedisRefreshTokenRotationStore = exports.createMemoryRefreshTokenRotationStore = exports.getSessionRevocationStore = exports.isAccessiTokenRevoked = exports.revokeAccessiUserSessionsIfConfigured = exports.revokeAccessiUserSessions = exports.createRedisSessionRevocationStore = exports.createMemorySessionRevocationStore = exports.createRedisAccessiAuditSink = exports.createMemoryAccessiAuditSink = exports.createHttpAccessiAuditSink = exports.createCallbackAccessiAuditSink = exports.resetAccessiAudit = exports.redactAccessiAuditValue = exports.getAccessiAuditStore = exports.configureAccessiTenantAudit = exports.configureAccessiAudit = exports.auditAccessi = exports.validateAccessiOptions = exports.assertValidAccessiOptions = exports.createAccessiEdgeRateLimitMiddleware = exports.getDefaultRateLimitStore = exports.createRedisRateLimitStore = exports.createMemoryRateLimitStore = exports.getDefaultConsoleEntryStore = exports.createRedisConsoleEntryStore = exports.createMemoryConsoleEntryStore = exports.AccessiDatabaseUpdater = exports.FederatedAuthExchangeController = exports.AccessiAuditController = exports.AccessiIntrospectionController = exports.AccessiModule = void 0;
30
+ exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.instrumentAccessiRedisClient = exports.resetAccessiMetrics = exports.renderAccessiMetrics = exports.recordAccessiMetric = exports.recordAccessiDuration = exports.observeAccessiMetric = exports.getAccessiMetricsSink = exports.getAccessiMetricsRegistry = exports.createAccessiMetricsRegistry = exports.countAccessiMetric = exports.accessiMetricName = exports.isAccessiCsrfExemptPath = exports.parseAccessiCookieHeader = exports.applyAccessiAuthCookies = exports.clearAccessiAuthCookies = exports.setAccessiAuthCookies = exports.getAccessiRefreshTokenFromCookie = exports.getAccessiAccessTokenFromCookie = exports.resolveAccessiAuthCookieOptions = exports.createAccessiAuthCookieMiddleware = exports.resolveAccessiSecurityHeaders = exports.createAccessiSecurityHeadersMiddleware = exports.buildAccessiContentSecurityPolicy = exports.applyAccessiContentSecurityPolicy = exports.applyAccessiBaseSecurityHeaders = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.isValidAdminBootstrapToken = exports.clearAdminBootstrapToken = exports.getAdminBootstrapToken = exports.getOrCreateAdminBootstrapToken = exports.AdminBootstrapService = exports.SchemaExportService = exports.ServiceTokenService = void 0;
31
+ exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.verifyAccessiJwt = void 0;
32
32
  exports.initializeAccessiModule = initializeAccessiModule;
33
33
  const express_1 = __importDefault(require("express"));
34
34
  const core_1 = require("@nestjs/core");
@@ -178,6 +178,7 @@ Object.defineProperty(exports, "validateAccessiOptions", { enumerable: true, get
178
178
  var audit_1 = require("./security/audit");
179
179
  Object.defineProperty(exports, "auditAccessi", { enumerable: true, get: function () { return audit_1.auditAccessi; } });
180
180
  Object.defineProperty(exports, "configureAccessiAudit", { enumerable: true, get: function () { return audit_1.configureAccessiAudit; } });
181
+ Object.defineProperty(exports, "configureAccessiTenantAudit", { enumerable: true, get: function () { return audit_1.configureAccessiTenantAudit; } });
181
182
  Object.defineProperty(exports, "getAccessiAuditStore", { enumerable: true, get: function () { return audit_1.getAccessiAuditStore; } });
182
183
  Object.defineProperty(exports, "redactAccessiAuditValue", { enumerable: true, get: function () { return audit_1.redactAccessiAuditValue; } });
183
184
  Object.defineProperty(exports, "resetAccessiAudit", { enumerable: true, get: function () { return audit_1.resetAccessiAudit; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nimport { createAccessiSecurityHeadersMiddleware } from './security/securityHeaders';\nimport { createAccessiAuthCookieMiddleware } from './security/authCookies';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n const authCookie = createAccessiAuthCookieMiddleware(options, isAccessiRoute);\n if (authCookie) {\n app.use(authCookie);\n }\n if (options.http?.securityHeaders !== false) {\n const securityHeaders = createAccessiSecurityHeadersMiddleware(\n options.http?.securityHeaders,\n isAccessiRoute,\n { isOpenApiUi: (path) => isOpenApiRequestPath(path, resolvedOpenApi) },\n );\n if (securityHeaders) {\n app.use(securityHeaders);\n }\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count', 'X-CSRF-Token'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { AccessiAuditController } from \"./Controllers/AccessiAuditController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport {\n auditAccessi,\n configureAccessiAudit,\n getAccessiAuditStore,\n redactAccessiAuditValue,\n resetAccessiAudit\n} from './security/audit';\nexport type {\n AccessiAuditOptions,\n AccessiAuditPage,\n AccessiAuditQuery,\n AccessiAuditQueryableSink,\n AccessiAuditRecord,\n AccessiAuditSink\n} from './security/audit';\nexport {\n createCallbackAccessiAuditSink,\n createHttpAccessiAuditSink,\n createMemoryAccessiAuditSink,\n createRedisAccessiAuditSink\n} from './security/auditSinks';\nexport type {\n HttpAccessiAuditSinkOptions,\n MemoryAccessiAuditSink,\n MemoryAccessiAuditSinkOptions,\n RedisAccessiAuditSinkOptions\n} from './security/auditSinks';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n applyAccessiBaseSecurityHeaders,\n applyAccessiContentSecurityPolicy,\n buildAccessiContentSecurityPolicy,\n createAccessiSecurityHeadersMiddleware,\n resolveAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport type {\n AccessiCspDirectives,\n AccessiCspOptions,\n AccessiCspSurface,\n AccessiSecurityHeadersOptions,\n AccessiSecurityHeadersSetting,\n ResolvedAccessiCsp,\n ResolvedAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport {\n createAccessiAuthCookieMiddleware,\n resolveAccessiAuthCookieOptions,\n getAccessiAccessTokenFromCookie,\n getAccessiRefreshTokenFromCookie,\n setAccessiAuthCookies,\n clearAccessiAuthCookies,\n applyAccessiAuthCookies,\n parseAccessiCookieHeader,\n isAccessiCsrfExemptPath\n} from './security/authCookies';\nexport type {\n AccessiAuthCookieOptions,\n AccessiAuthCookieSetting,\n AccessiAuthTokenPair,\n ResolvedAccessiAuthCookieOptions\n} from './security/authCookies';\nexport {\n accessiMetricName,\n countAccessiMetric,\n createAccessiMetricsRegistry,\n getAccessiMetricsRegistry,\n getAccessiMetricsSink,\n observeAccessiMetric,\n recordAccessiDuration,\n recordAccessiMetric,\n renderAccessiMetrics,\n resetAccessiMetrics\n} from './observability/metrics';\nexport type {\n AccessiMetricLabelValue,\n AccessiMetricLabels,\n AccessiMetricsOptions,\n AccessiMetricsRegistry,\n AccessiMetricsSink,\n AccessiMetricsSnapshot\n} from './observability/metrics';\nexport { instrumentAccessiRedisClient } from './observability/redisMetrics';\nexport type { AccessiRedisEvalClient } from './observability/redisMetrics';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nimport { createAccessiSecurityHeadersMiddleware } from './security/securityHeaders';\nimport { createAccessiAuthCookieMiddleware } from './security/authCookies';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n const authCookie = createAccessiAuthCookieMiddleware(options, isAccessiRoute);\n if (authCookie) {\n app.use(authCookie);\n }\n if (options.http?.securityHeaders !== false) {\n const securityHeaders = createAccessiSecurityHeadersMiddleware(\n options.http?.securityHeaders,\n isAccessiRoute,\n { isOpenApiUi: (path) => isOpenApiRequestPath(path, resolvedOpenApi) },\n );\n if (securityHeaders) {\n app.use(securityHeaders);\n }\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count', 'X-CSRF-Token'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { AccessiAuditController } from \"./Controllers/AccessiAuditController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport {\n auditAccessi,\n configureAccessiAudit,\n configureAccessiTenantAudit,\n getAccessiAuditStore,\n redactAccessiAuditValue,\n resetAccessiAudit\n} from './security/audit';\nexport type {\n AccessiAuditOptions,\n AccessiAuditPage,\n AccessiAuditQuery,\n AccessiAuditQueryableSink,\n AccessiAuditRecord,\n AccessiAuditSink\n} from './security/audit';\nexport {\n createCallbackAccessiAuditSink,\n createHttpAccessiAuditSink,\n createMemoryAccessiAuditSink,\n createRedisAccessiAuditSink\n} from './security/auditSinks';\nexport type {\n HttpAccessiAuditSinkOptions,\n MemoryAccessiAuditSink,\n MemoryAccessiAuditSinkOptions,\n RedisAccessiAuditSinkOptions\n} from './security/auditSinks';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n applyAccessiBaseSecurityHeaders,\n applyAccessiContentSecurityPolicy,\n buildAccessiContentSecurityPolicy,\n createAccessiSecurityHeadersMiddleware,\n resolveAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport type {\n AccessiCspDirectives,\n AccessiCspOptions,\n AccessiCspSurface,\n AccessiSecurityHeadersOptions,\n AccessiSecurityHeadersSetting,\n ResolvedAccessiCsp,\n ResolvedAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport {\n createAccessiAuthCookieMiddleware,\n resolveAccessiAuthCookieOptions,\n getAccessiAccessTokenFromCookie,\n getAccessiRefreshTokenFromCookie,\n setAccessiAuthCookies,\n clearAccessiAuthCookies,\n applyAccessiAuthCookies,\n parseAccessiCookieHeader,\n isAccessiCsrfExemptPath\n} from './security/authCookies';\nexport type {\n AccessiAuthCookieOptions,\n AccessiAuthCookieSetting,\n AccessiAuthTokenPair,\n ResolvedAccessiAuthCookieOptions\n} from './security/authCookies';\nexport {\n accessiMetricName,\n countAccessiMetric,\n createAccessiMetricsRegistry,\n getAccessiMetricsRegistry,\n getAccessiMetricsSink,\n observeAccessiMetric,\n recordAccessiDuration,\n recordAccessiMetric,\n renderAccessiMetrics,\n resetAccessiMetrics\n} from './observability/metrics';\nexport type {\n AccessiMetricLabelValue,\n AccessiMetricLabels,\n AccessiMetricsOptions,\n AccessiMetricsRegistry,\n AccessiMetricsSink,\n AccessiMetricsSnapshot\n} from './observability/metrics';\nexport { instrumentAccessiRedisClient } from './observability/redisMetrics';\nexport type { AccessiRedisEvalClient } from './observability/redisMetrics';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}