@adonis-agora/authkit-server 0.46.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/build/commands/clients_create.js +4 -4
  2. package/build/commands/configure.js +3 -2
  3. package/build/commands/doctor.js +8 -5
  4. package/build/commands/eject.js +1 -1
  5. package/build/commands/expire_scan.js +7 -5
  6. package/build/commands/import_users.js +1 -1
  7. package/build/commands/keys_rotate.js +7 -4
  8. package/build/host/views/account/apps.edge +5 -5
  9. package/build/host/views/account/login.edge +1 -1
  10. package/build/host/views/account/mfa.edge +7 -7
  11. package/build/host/views/account/orgs.edge +5 -5
  12. package/build/host/views/account/security.edge +10 -10
  13. package/build/host/views/account/tokens.edge +5 -5
  14. package/build/host/views/otp-unlock.edge +2 -2
  15. package/build/index.d.ts +7 -7
  16. package/build/index.js +5 -5
  17. package/build/providers/authkit_server_provider.d.ts +2 -2
  18. package/build/providers/authkit_server_provider.js +26 -10
  19. package/build/services/booted_app.d.ts +8 -0
  20. package/build/services/booted_app.js +27 -0
  21. package/build/services/main.d.ts +8 -1
  22. package/build/services/main.js +10 -2
  23. package/build/src/accounts/lucid_account_store.d.ts +3 -3
  24. package/build/src/accounts/lucid_account_store.js +6 -8
  25. package/build/src/accounts/lucid_store/core.js +1 -1
  26. package/build/src/accounts/lucid_store/mfa.js +1 -1
  27. package/build/src/accounts/lucid_store/organizations.js +2 -4
  28. package/build/src/accounts/lucid_store/password_hygiene.js +1 -4
  29. package/build/src/accounts/lucid_store/shared.d.ts +1 -1
  30. package/build/src/accounts/lucid_stores.d.ts +3 -3
  31. package/build/src/accounts/lucid_stores.js +2 -2
  32. package/build/src/adapters/database_adapter.js +3 -1
  33. package/build/src/adapters/factory.js +1 -1
  34. package/build/src/adapters/redis_adapter.js +2 -1
  35. package/build/src/commands/expire_scan_command.js +19 -5
  36. package/build/src/commands/settings_commands.js +22 -5
  37. package/build/src/define_config.d.ts +20 -20
  38. package/build/src/define_config.js +62 -67
  39. package/build/src/doctor/checks.js +45 -20
  40. package/build/src/events/dispatcher.d.ts +1 -1
  41. package/build/src/events/dispatcher.js +10 -10
  42. package/build/src/host/account_api/account_api_controller.js +95 -39
  43. package/build/src/host/account_deletion_ops.d.ts +4 -4
  44. package/build/src/host/account_deletion_ops.js +5 -5
  45. package/build/src/host/account_deletion_service.d.ts +2 -2
  46. package/build/src/host/account_deletion_service.js +2 -2
  47. package/build/src/host/account_export_service.d.ts +1 -1
  48. package/build/src/host/account_export_service.js +4 -6
  49. package/build/src/host/account_home.d.ts +0 -8
  50. package/build/src/host/account_home.js +6 -4
  51. package/build/src/host/account_login_url.d.ts +44 -0
  52. package/build/src/host/account_login_url.js +58 -0
  53. package/build/src/host/account_paths.d.ts +120 -0
  54. package/build/src/host/account_paths.js +161 -0
  55. package/build/src/host/admin_api/admin_orgs_service.d.ts +2 -2
  56. package/build/src/host/admin_api/admin_orgs_service.js +3 -2
  57. package/build/src/host/admin_api/admin_users_service.d.ts +12 -12
  58. package/build/src/host/admin_api/admin_users_service.js +20 -20
  59. package/build/src/host/admin_api/api_clients_controller.js +2 -2
  60. package/build/src/host/admin_api/api_misc_controller.js +2 -2
  61. package/build/src/host/admin_api/api_orgs_controller.js +3 -3
  62. package/build/src/host/admin_api/api_settings_controller.js +11 -5
  63. package/build/src/host/admin_api/api_users_controller.d.ts +2 -2
  64. package/build/src/host/admin_api/api_users_controller.js +37 -38
  65. package/build/src/host/admin_api/dto.d.ts +4 -4
  66. package/build/src/host/admin_clients_service.js +5 -4
  67. package/build/src/host/admin_console/admin_shell_controller.js +4 -2
  68. package/build/src/host/admin_console/console_audit_controller.js +1 -1
  69. package/build/src/host/admin_console/console_clients_controller.js +5 -3
  70. package/build/src/host/admin_console/console_impersonation_controller.js +1 -1
  71. package/build/src/host/admin_console/console_keys_controller.js +2 -4
  72. package/build/src/host/admin_console/console_orgs_controller.js +3 -3
  73. package/build/src/host/admin_console/console_roles_controller.js +30 -12
  74. package/build/src/host/admin_console/console_sessions_controller.js +3 -3
  75. package/build/src/host/admin_console/console_settings_controller.js +11 -5
  76. package/build/src/host/admin_console/console_users_controller.d.ts +2 -2
  77. package/build/src/host/admin_console/console_users_controller.js +46 -47
  78. package/build/src/host/admin_prefix.js +2 -2
  79. package/build/src/host/admin_sessions_service.d.ts +3 -1
  80. package/build/src/host/admin_sessions_service.js +36 -6
  81. package/build/src/host/adonis_auth_sync.d.ts +1 -1
  82. package/build/src/host/adonis_auth_user_provider.d.ts +1 -1
  83. package/build/src/host/app_key.js +1 -1
  84. package/build/src/host/avatar_storage.js +1 -3
  85. package/build/src/host/config_locks.js +1 -3
  86. package/build/src/host/console_session.d.ts +4 -0
  87. package/build/src/host/console_session.js +9 -2
  88. package/build/src/host/controllers/account_apps_controller.js +3 -2
  89. package/build/src/host/controllers/account_confirm_controller.js +2 -6
  90. package/build/src/host/controllers/account_mfa_controller.js +63 -12
  91. package/build/src/host/controllers/account_orgs_controller.js +53 -30
  92. package/build/src/host/controllers/account_security_controller.d.ts +2 -2
  93. package/build/src/host/controllers/account_security_controller.js +116 -116
  94. package/build/src/host/controllers/account_session_controller.js +7 -5
  95. package/build/src/host/controllers/account_tokens_controller.js +14 -2
  96. package/build/src/host/controllers/interaction_controller.js +59 -22
  97. package/build/src/host/controllers/pat_introspection_controller.js +10 -0
  98. package/build/src/host/controllers/registration_controller.js +28 -13
  99. package/build/src/host/default_mailer.js +11 -7
  100. package/build/src/host/durable/account_deletion_workflow.d.ts +2 -2
  101. package/build/src/host/durable/account_deletion_workflow.js +14 -14
  102. package/build/src/host/durable/account_export_workflow.d.ts +2 -2
  103. package/build/src/host/durable/account_export_workflow.js +12 -12
  104. package/build/src/host/durable/index.d.ts +5 -5
  105. package/build/src/host/durable/index.js +6 -6
  106. package/build/src/host/i18n.d.ts +1376 -1376
  107. package/build/src/host/i18n.js +1380 -1380
  108. package/build/src/host/impersonation.js +1 -7
  109. package/build/src/host/key_rotation_actions.d.ts +1 -1
  110. package/build/src/host/login_attempt.js +35 -6
  111. package/build/src/host/login_notify.js +1 -1
  112. package/build/src/host/middleware/account_auth.js +3 -1
  113. package/build/src/host/otp_lockout.js +1 -3
  114. package/build/src/host/rate_limit.js +1 -1
  115. package/build/src/host/register_auth_host.d.ts +96 -2
  116. package/build/src/host/register_auth_host.js +196 -91
  117. package/build/src/host/renderers/edge_renderer.js +19 -1
  118. package/build/src/host/renderers/inertia_renderer.d.ts +63 -0
  119. package/build/src/host/renderers/inertia_renderer.js +63 -0
  120. package/build/src/host/runtime_settings.js +1 -1
  121. package/build/src/host/runtime_toggles.d.ts +3 -3
  122. package/build/src/host/runtime_toggles.js +69 -24
  123. package/build/src/host/security_notice_service.d.ts +1 -1
  124. package/build/src/host/security_notice_service.js +1 -1
  125. package/build/src/host/session_context.js +1 -1
  126. package/build/src/host/sudo/index.d.ts +3 -3
  127. package/build/src/host/sudo/index.js +3 -3
  128. package/build/src/host/sudo/methods/magic_link.js +6 -5
  129. package/build/src/host/sudo/methods/passkey.js +7 -4
  130. package/build/src/host/sudo/methods/password.js +8 -3
  131. package/build/src/host/sudo/runtime.js +6 -13
  132. package/build/src/host/sudo_mode.js +3 -2
  133. package/build/src/host/ui-dist/assets/index-BQoTDiLV.js +137 -0
  134. package/build/src/host/ui-dist/index.html +1 -1
  135. package/build/src/keys/jwks_manager.js +1 -1
  136. package/build/src/keys/keystore.js +1 -1
  137. package/build/src/keys/keystore_manager.d.ts +2 -2
  138. package/build/src/keys/keystore_manager.js +2 -2
  139. package/build/src/keys/keystore_vault.js +8 -4
  140. package/build/src/mixins/with_audit_log.d.ts +1 -1
  141. package/build/src/mixins/with_auth_user.d.ts +1 -1
  142. package/build/src/mixins/with_auth_user.js +1 -1
  143. package/build/src/mixins/with_credentials.d.ts +1 -1
  144. package/build/src/mixins/with_mfa.d.ts +1 -1
  145. package/build/src/mixins/with_personal_access_token.d.ts +1 -1
  146. package/build/src/mixins/with_provider_identity.d.ts +1 -1
  147. package/build/src/mixins/with_webauthn_credential.d.ts +1 -1
  148. package/build/src/observability/diagnostics_bridge.js +2 -2
  149. package/build/src/observability/metrics_service.js +1 -1
  150. package/build/src/observability/telescope/data_providers.d.ts +1 -1
  151. package/build/src/observability/telescope/data_providers.js +29 -43
  152. package/build/src/observability/telescope/extension.d.ts +1 -1
  153. package/build/src/observability/telescope/extension.js +58 -58
  154. package/build/src/observability/telescope/index.d.ts +2 -2
  155. package/build/src/observability/telescope/index.js +2 -2
  156. package/build/src/observability/wire_provider_events.d.ts +1 -1
  157. package/build/src/observability/wire_provider_events.js +11 -11
  158. package/build/src/password/common_passwords.js +1 -1
  159. package/build/src/password/password_manager.d.ts +1 -1
  160. package/build/src/password/password_manager.js +4 -4
  161. package/build/src/pat/lucid_pat_store.js +2 -6
  162. package/build/src/pat/pat_tokens.js +1 -1
  163. package/build/src/provider/interaction_actions.js +1 -1
  164. package/build/src/provider/key_rotation_scheduler.js +3 -1
  165. package/build/src/provider/logout_sources.js +2 -8
  166. package/build/src/provider/oidc_service.d.ts +2 -2
  167. package/build/src/provider/oidc_service.js +22 -14
  168. package/build/src/provider/single_flight_lock.js +1 -3
  169. package/build/src/provider/token_exchange.d.ts +1 -1
  170. package/build/src/schema/ensure.js +3 -1
  171. package/build/stubs/ui/react/components/auth_shell.tsx +19 -19
  172. package/build/stubs/ui/react/pages/account/login.tsx +6 -7
  173. package/build/stubs/ui/react/pages/account/mfa.tsx +16 -15
  174. package/build/stubs/ui/react/pages/account/tokens.tsx +27 -17
  175. package/build/stubs/ui/react/pages/consent.tsx +12 -12
  176. package/build/stubs/ui/react/pages/forgot.tsx +7 -7
  177. package/build/stubs/ui/react/pages/login.tsx +22 -24
  178. package/build/stubs/ui/react/pages/mfa-challenge.tsx +9 -10
  179. package/build/stubs/ui/react/pages/reset.tsx +10 -10
  180. package/build/stubs/ui/react/pages/signup.tsx +30 -16
  181. package/build/stubs/ui/react/pages/verify-email.tsx +6 -6
  182. package/package.json +1 -1
  183. package/stubs/main.ts +2 -2
  184. package/stubs/ui/react/components/auth_shell.tsx +19 -19
  185. package/stubs/ui/react/pages/account/login.tsx +6 -7
  186. package/stubs/ui/react/pages/account/mfa.tsx +16 -15
  187. package/stubs/ui/react/pages/account/tokens.tsx +27 -17
  188. package/stubs/ui/react/pages/consent.tsx +12 -12
  189. package/stubs/ui/react/pages/forgot.tsx +7 -7
  190. package/stubs/ui/react/pages/login.tsx +22 -24
  191. package/stubs/ui/react/pages/mfa-challenge.tsx +9 -10
  192. package/stubs/ui/react/pages/reset.tsx +10 -10
  193. package/stubs/ui/react/pages/signup.tsx +30 -16
  194. package/stubs/ui/react/pages/verify-email.tsx +6 -6
  195. package/build/src/host/ui-dist/assets/index-BmI_J87g.js +0 -137
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Prefixo e segmentos de tela do console de conta (`/account/*`) — singleton de
3
+ * processo, configurável/localizável.
4
+ *
5
+ * Definidos em tempo de registro das rotas (`registerAuthHost`, via a opção
6
+ * `accountRoutes`) e lidos em runtime por TODOS os pontos que constroem uma URL
7
+ * do console de conta: o registro de rotas, os redirects dos controllers, as
8
+ * URLs absolutas dos e-mails transacionais, os guards de sudo e as views Edge
9
+ * (injetados como prop global `accountPaths` pelo renderer).
10
+ *
11
+ * Por que módulo singleton e não binding do container? Mesma razão do
12
+ * `admin_prefix` e do `account_login_url`: os guards e o registro de rotas são
13
+ * closures construídas em tempo de registro, ANTES da primeira request, quando
14
+ * o container do AdonisJS ainda não existe. Um módulo ESM é inicializado uma vez
15
+ * por processo — ideal para configuração imutável de boot.
16
+ *
17
+ * ── O que é configurável e o que NÃO é ──────────────────────────────────────
18
+ * Configuráveis: o PREFIXO (`/account` → `/conta`) e o SEGMENTO de cada TELA
19
+ * navegável (`security` → `seguranca`, `confirm` → `confirmar`, ...). São paths
20
+ * que o usuário vê na barra de endereço e que um host pode querer no idioma dele.
21
+ *
22
+ * NÃO configuráveis (de propósito): os action-subpaths dos POSTs de dentro de
23
+ * cada tela — `/password`, `/email`, `/enroll`, `/confirm`, `/disable`,
24
+ * `/passkeys/options`, `/passkeys/verify`, `/delete`, `/export`, o `/magic-link`
25
+ * e o `/passkey` das rotas de sudo, etc. São endpoints de formulário invisíveis
26
+ * ao usuário (ele nunca digita `/account/security/password`), servem apenas de
27
+ * alvo de `<form action>`/`fetch`, e mantê-los fixos evita multiplicar a
28
+ * superfície de configuração (e a de bugs) sem nenhum ganho de UX. Renomear a
29
+ * tela já cobre o caso real "quero /conta/seguranca". Idem para o segmento fixo
30
+ * `api` da JSON API (`{prefix}/api/*`): ele segue o prefixo mas nunca é
31
+ * traduzido — é contrato de máquina (authkit-react), não de humano.
32
+ */
33
+ /**
34
+ * Segmentos default de cada TELA navegável do console de conta. A chave é o
35
+ * identificador estável usado no código (`accountPath('security')`); o valor é
36
+ * o segmento de URL, sobrescrevível por `setAccountPaths`.
37
+ */
38
+ declare const DEFAULT_ACCOUNT_SEGMENTS: {
39
+ readonly login: "login";
40
+ readonly logout: "logout";
41
+ readonly security: "security";
42
+ readonly mfa: "mfa";
43
+ readonly confirm: "confirm";
44
+ readonly tokens: "tokens";
45
+ readonly apps: "apps";
46
+ readonly orgs: "orgs";
47
+ readonly emailConfirm: "email/confirm";
48
+ };
49
+ /** Chave de tela do console de conta (`login`, `security`, `confirm`, ...). */
50
+ export type AccountPathKey = keyof typeof DEFAULT_ACCOUNT_SEGMENTS;
51
+ /** Overrides aceitos por `setAccountPaths` / a opção `accountRoutes`. */
52
+ export interface AccountPathsOptions {
53
+ /** Prefixo base do console (ex.: `'/conta'`). Normalizado automaticamente. */
54
+ prefix?: string;
55
+ /** Segmentos de tela a sobrescrever (ex.: `{ security: 'seguranca' }`). */
56
+ paths?: Partial<Record<AccountPathKey, string>>;
57
+ }
58
+ /**
59
+ * Normaliza o prefixo: começa com '/', sem trailing slash. Mesma semântica de
60
+ * `normalizeAdminPrefix`. `'/'` → `'/'` (raiz) é improvável mas seguro.
61
+ */
62
+ export declare function normalizeAccountPrefix(raw: string): string;
63
+ /**
64
+ * Define o prefixo e/ou os segmentos de tela do console de conta para este
65
+ * processo. Chamado UMA VEZ por `registerAuthHost` no boot da aplicação.
66
+ *
67
+ * Só sobrescreve o que foi passado — chamada sem `prefix` mantém o prefixo
68
+ * atual, e segmentos ausentes de `paths` mantêm o default. Valores
69
+ * vazios/whitespace são ignorados (caem no default), nunca produzem um path
70
+ * quebrado.
71
+ *
72
+ * @example
73
+ * setAccountPaths({ prefix: '/conta', paths: { security: 'seguranca', confirm: 'confirmar' } })
74
+ * accountPath('security') // → '/conta/seguranca'
75
+ * accountPath('confirm') // → '/conta/confirmar'
76
+ */
77
+ export declare function setAccountPaths(opts: AccountPathsOptions | undefined): void;
78
+ /**
79
+ * Junta o prefixo do console de conta com um subpath arbitrário, tratando o
80
+ * prefixo raiz (`'/'`) como `''` na composição: sem isso o resultado seria
81
+ * `'//<sub>'`, que num `<form action>`/`fetch()` é URL protocol-relative (o
82
+ * browser lê `<sub>` como HOST, não como path).
83
+ *
84
+ * Base canônica de `accountPath()` e de QUALQUER outra composição
85
+ * prefixo+subpath fora das TELAS fixas (ex.: o `{prefix}/api` da JSON API em
86
+ * `register_auth_host`). Novas composições devem passar por aqui em vez de
87
+ * reimplementar `${accountPrefix()}/algo` — é exatamente essa duplicação que
88
+ * reproduz o bug do `//` quando o prefixo normaliza pra raiz.
89
+ *
90
+ * @example
91
+ * joinAccountPath('api') // default → '/account/api'
92
+ */
93
+ export declare function joinAccountPath(sub: string): string;
94
+ /**
95
+ * Retorna o path completo de uma TELA do console de conta (prefixo + segmento).
96
+ * Para os action-subpaths (POSTs de dentro da tela) concatene o subpath fixo:
97
+ * `accountPath('security') + '/password'`.
98
+ *
99
+ * @example
100
+ * accountPath('security') // default → '/account/security'
101
+ * accountPath('confirm') // default → '/account/confirm'
102
+ */
103
+ export declare function accountPath(key: AccountPathKey): string;
104
+ /**
105
+ * Retorna o prefixo BRUTO do console de conta (default `'/account'`; pode ser
106
+ * `'/'` na raiz). Para compor `{prefix}/algo` (ex.: a JSON API, cujo segmento
107
+ * `api` é fixo — contrato de máquina), use `joinAccountPath('algo')`: ela
108
+ * colapsa a raiz e evita o `//`. Este getter existe para os casos (ex.: os
109
+ * asserts de teste) que precisam do valor cru do prefixo.
110
+ */
111
+ export declare function accountPrefix(): string;
112
+ /**
113
+ * Mapa `{ chave → path completo }` de TODAS as telas. Injetado como prop global
114
+ * `accountPaths` nas views Edge, para que os `<form action>`/`fetch()` respeitem
115
+ * os overrides sem cada view conhecer o prefixo.
116
+ */
117
+ export declare function accountPathsMap(): Record<AccountPathKey, string>;
118
+ /** Restaura os defaults — uso em testes (isola o singleton entre casos). */
119
+ export declare function resetAccountPaths(): void;
120
+ export {};
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Prefixo e segmentos de tela do console de conta (`/account/*`) — singleton de
3
+ * processo, configurável/localizável.
4
+ *
5
+ * Definidos em tempo de registro das rotas (`registerAuthHost`, via a opção
6
+ * `accountRoutes`) e lidos em runtime por TODOS os pontos que constroem uma URL
7
+ * do console de conta: o registro de rotas, os redirects dos controllers, as
8
+ * URLs absolutas dos e-mails transacionais, os guards de sudo e as views Edge
9
+ * (injetados como prop global `accountPaths` pelo renderer).
10
+ *
11
+ * Por que módulo singleton e não binding do container? Mesma razão do
12
+ * `admin_prefix` e do `account_login_url`: os guards e o registro de rotas são
13
+ * closures construídas em tempo de registro, ANTES da primeira request, quando
14
+ * o container do AdonisJS ainda não existe. Um módulo ESM é inicializado uma vez
15
+ * por processo — ideal para configuração imutável de boot.
16
+ *
17
+ * ── O que é configurável e o que NÃO é ──────────────────────────────────────
18
+ * Configuráveis: o PREFIXO (`/account` → `/conta`) e o SEGMENTO de cada TELA
19
+ * navegável (`security` → `seguranca`, `confirm` → `confirmar`, ...). São paths
20
+ * que o usuário vê na barra de endereço e que um host pode querer no idioma dele.
21
+ *
22
+ * NÃO configuráveis (de propósito): os action-subpaths dos POSTs de dentro de
23
+ * cada tela — `/password`, `/email`, `/enroll`, `/confirm`, `/disable`,
24
+ * `/passkeys/options`, `/passkeys/verify`, `/delete`, `/export`, o `/magic-link`
25
+ * e o `/passkey` das rotas de sudo, etc. São endpoints de formulário invisíveis
26
+ * ao usuário (ele nunca digita `/account/security/password`), servem apenas de
27
+ * alvo de `<form action>`/`fetch`, e mantê-los fixos evita multiplicar a
28
+ * superfície de configuração (e a de bugs) sem nenhum ganho de UX. Renomear a
29
+ * tela já cobre o caso real "quero /conta/seguranca". Idem para o segmento fixo
30
+ * `api` da JSON API (`{prefix}/api/*`): ele segue o prefixo mas nunca é
31
+ * traduzido — é contrato de máquina (authkit-react), não de humano.
32
+ */
33
+ /** Prefixo default do console de conta. */
34
+ const DEFAULT_ACCOUNT_PREFIX = '/account';
35
+ /**
36
+ * Segmentos default de cada TELA navegável do console de conta. A chave é o
37
+ * identificador estável usado no código (`accountPath('security')`); o valor é
38
+ * o segmento de URL, sobrescrevível por `setAccountPaths`.
39
+ */
40
+ const DEFAULT_ACCOUNT_SEGMENTS = {
41
+ login: 'login',
42
+ logout: 'logout',
43
+ security: 'security',
44
+ mfa: 'mfa',
45
+ confirm: 'confirm',
46
+ tokens: 'tokens',
47
+ apps: 'apps',
48
+ orgs: 'orgs',
49
+ emailConfirm: 'email/confirm',
50
+ };
51
+ let _prefix = DEFAULT_ACCOUNT_PREFIX;
52
+ let _segments = { ...DEFAULT_ACCOUNT_SEGMENTS };
53
+ /**
54
+ * Normaliza o prefixo: começa com '/', sem trailing slash. Mesma semântica de
55
+ * `normalizeAdminPrefix`. `'/'` → `'/'` (raiz) é improvável mas seguro.
56
+ */
57
+ export function normalizeAccountPrefix(raw) {
58
+ let p = raw.trim();
59
+ if (!p.startsWith('/'))
60
+ p = `/${p}`;
61
+ p = p.replace(/\/+$/, '');
62
+ return p || '/';
63
+ }
64
+ /**
65
+ * Normaliza um segmento de tela: sem barras nas pontas (mas preserva barras
66
+ * internas, ex.: `'email/confirm'`). Valor vazio é ignorado pelo caller.
67
+ */
68
+ function normalizeSegment(raw) {
69
+ return raw.trim().replace(/^\/+/, '').replace(/\/+$/, '');
70
+ }
71
+ /**
72
+ * Define o prefixo e/ou os segmentos de tela do console de conta para este
73
+ * processo. Chamado UMA VEZ por `registerAuthHost` no boot da aplicação.
74
+ *
75
+ * Só sobrescreve o que foi passado — chamada sem `prefix` mantém o prefixo
76
+ * atual, e segmentos ausentes de `paths` mantêm o default. Valores
77
+ * vazios/whitespace são ignorados (caem no default), nunca produzem um path
78
+ * quebrado.
79
+ *
80
+ * @example
81
+ * setAccountPaths({ prefix: '/conta', paths: { security: 'seguranca', confirm: 'confirmar' } })
82
+ * accountPath('security') // → '/conta/seguranca'
83
+ * accountPath('confirm') // → '/conta/confirmar'
84
+ */
85
+ export function setAccountPaths(opts) {
86
+ if (!opts)
87
+ return;
88
+ if (opts.prefix !== undefined) {
89
+ const trimmed = opts.prefix.trim();
90
+ if (trimmed)
91
+ _prefix = normalizeAccountPrefix(trimmed);
92
+ }
93
+ if (opts.paths) {
94
+ for (const key of Object.keys(opts.paths)) {
95
+ const value = opts.paths[key];
96
+ if (value === undefined)
97
+ continue;
98
+ const seg = normalizeSegment(value);
99
+ if (seg)
100
+ _segments[key] = seg;
101
+ }
102
+ }
103
+ }
104
+ /**
105
+ * Junta o prefixo do console de conta com um subpath arbitrário, tratando o
106
+ * prefixo raiz (`'/'`) como `''` na composição: sem isso o resultado seria
107
+ * `'//<sub>'`, que num `<form action>`/`fetch()` é URL protocol-relative (o
108
+ * browser lê `<sub>` como HOST, não como path).
109
+ *
110
+ * Base canônica de `accountPath()` e de QUALQUER outra composição
111
+ * prefixo+subpath fora das TELAS fixas (ex.: o `{prefix}/api` da JSON API em
112
+ * `register_auth_host`). Novas composições devem passar por aqui em vez de
113
+ * reimplementar `${accountPrefix()}/algo` — é exatamente essa duplicação que
114
+ * reproduz o bug do `//` quando o prefixo normaliza pra raiz.
115
+ *
116
+ * @example
117
+ * joinAccountPath('api') // default → '/account/api'
118
+ */
119
+ export function joinAccountPath(sub) {
120
+ const base = _prefix === '/' ? '' : _prefix;
121
+ return `${base}/${sub}`;
122
+ }
123
+ /**
124
+ * Retorna o path completo de uma TELA do console de conta (prefixo + segmento).
125
+ * Para os action-subpaths (POSTs de dentro da tela) concatene o subpath fixo:
126
+ * `accountPath('security') + '/password'`.
127
+ *
128
+ * @example
129
+ * accountPath('security') // default → '/account/security'
130
+ * accountPath('confirm') // default → '/account/confirm'
131
+ */
132
+ export function accountPath(key) {
133
+ return joinAccountPath(_segments[key]);
134
+ }
135
+ /**
136
+ * Retorna o prefixo BRUTO do console de conta (default `'/account'`; pode ser
137
+ * `'/'` na raiz). Para compor `{prefix}/algo` (ex.: a JSON API, cujo segmento
138
+ * `api` é fixo — contrato de máquina), use `joinAccountPath('algo')`: ela
139
+ * colapsa a raiz e evita o `//`. Este getter existe para os casos (ex.: os
140
+ * asserts de teste) que precisam do valor cru do prefixo.
141
+ */
142
+ export function accountPrefix() {
143
+ return _prefix;
144
+ }
145
+ /**
146
+ * Mapa `{ chave → path completo }` de TODAS as telas. Injetado como prop global
147
+ * `accountPaths` nas views Edge, para que os `<form action>`/`fetch()` respeitem
148
+ * os overrides sem cada view conhecer o prefixo.
149
+ */
150
+ export function accountPathsMap() {
151
+ const out = {};
152
+ for (const key of Object.keys(_segments)) {
153
+ out[key] = accountPath(key);
154
+ }
155
+ return out;
156
+ }
157
+ /** Restaura os defaults — uso em testes (isola o singleton entre casos). */
158
+ export function resetAccountPaths() {
159
+ _prefix = DEFAULT_ACCOUNT_PREFIX;
160
+ _segments = { ...DEFAULT_ACCOUNT_SEGMENTS };
161
+ }
@@ -1,7 +1,7 @@
1
+ import type { OrgInvitation, OrgMember, OrgSummary } from '../../accounts/account_store.js';
1
2
  import type { ResolvedServerConfig } from '../../define_config.js';
2
- import type { OrgSummary, OrgMember, OrgInvitation } from '../../accounts/account_store.js';
3
- import type { AdminActor } from './admin_users_service.js';
4
3
  import type { SettingsCapability } from '../runtime_settings.js';
4
+ import type { AdminActor } from './admin_users_service.js';
5
5
  export interface OrgWithMemberCount extends OrgSummary {
6
6
  memberCount: number;
7
7
  }
@@ -1,5 +1,6 @@
1
1
  import { supportsOrganizations } from '../../accounts/account_store.js';
2
- import { resolveRoleCatalogList, isRoleInCatalog } from '../runtime_toggles.js';
2
+ import { accountPath } from '../account_paths.js';
3
+ import { isRoleInCatalog, resolveRoleCatalogList } from '../runtime_toggles.js';
3
4
  /**
4
5
  * Lógica de gestão de organizações compartilhada entre o console admin (HTML)
5
6
  * e a Admin REST API (JSON). Usada pelos `AdminOrgsController` e `ApiOrgsController`.
@@ -267,7 +268,7 @@ export class AdminOrgsService {
267
268
  });
268
269
  // Dispara mail hook (best-effort)
269
270
  if (this.cfg.mail?.onOrgInvitation) {
270
- const acceptUrl = `${origin}/account/orgs/invitations/${token}/accept`;
271
+ const acceptUrl = `${origin}${accountPath('orgs')}/invitations/${token}/accept`;
271
272
  try {
272
273
  await this.cfg.mail.onOrgInvitation({
273
274
  email: input.email,
@@ -1,20 +1,20 @@
1
- import type { HttpContext } from "@adonisjs/core/http";
2
- import type { ResolvedServerConfig } from "../../define_config.js";
3
- import type { OidcService } from "../../provider/oidc_service.js";
4
- import type { AuthAccount } from "../../accounts/account_store.js";
5
- import { type DeletionResult } from "../account_deletion_service.js";
6
- import type { SettingsCapability } from "../runtime_settings.js";
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { AuthAccount } from '../../accounts/account_store.js';
3
+ import type { ResolvedServerConfig } from '../../define_config.js';
4
+ import type { OidcService } from '../../provider/oidc_service.js';
5
+ import { type DeletionResult } from '../account_deletion_service.js';
6
+ import type { SettingsCapability } from '../runtime_settings.js';
7
7
  /** Quem disparou a operação (para auditoria). `admin-api` quando via REST API. */
8
8
  export interface AdminActor {
9
9
  actorId: string | null;
10
10
  ip: string | null;
11
11
  /** Marca metadata da auditoria — 'admin-api' nas escritas via REST, 'admin' no console HTML. */
12
- source?: "admin-api" | "admin";
12
+ source?: 'admin-api' | 'admin';
13
13
  }
14
14
  /** Resultado da deleção via admin: false quando o store não suporta hard delete. */
15
15
  export type DeleteUserResult = {
16
16
  ok: false;
17
- reason: "not_found" | "unsupported";
17
+ reason: 'not_found' | 'unsupported';
18
18
  } | {
19
19
  ok: true;
20
20
  result: DeletionResult;
@@ -34,7 +34,7 @@ export type EnqueueDeletion = (input: {
34
34
  actor: {
35
35
  actorId: string | null;
36
36
  ip: string | null;
37
- source: "admin" | "admin-api";
37
+ source: 'admin' | 'admin-api';
38
38
  };
39
39
  }) => Promise<string>;
40
40
  export interface CreateUserInput {
@@ -50,10 +50,10 @@ export type CreateUserResult = {
50
50
  invited: boolean;
51
51
  } | {
52
52
  ok: false;
53
- reason: "email_taken";
53
+ reason: 'email_taken';
54
54
  } | {
55
55
  ok: false;
56
- reason: "password_policy";
56
+ reason: 'password_policy';
57
57
  /** Chave i18n da regra violada + params para interpolar. */
58
58
  messageKey: string;
59
59
  messageParams?: Record<string, string | number>;
@@ -141,7 +141,7 @@ export declare class AdminUsersService {
141
141
  *
142
142
  * @returns código i18n/erro quando a operação deve ser bloqueada; `null` quando OK.
143
143
  */
144
- guardGlobalRolesChange(targetId: string, newRoles: string[], actorId: string | null): Promise<"last_admin" | "cannot_self_demote" | null>;
144
+ guardGlobalRolesChange(targetId: string, newRoles: string[], actorId: string | null): Promise<'last_admin' | 'cannot_self_demote' | null>;
145
145
  /** Atualiza nome/avatar (capacidade opcional). Retorna a conta ou null. */
146
146
  updateProfile(accountId: string, patch: {
147
147
  name?: string | null;
@@ -1,9 +1,9 @@
1
- import { randomBytes } from "node:crypto";
2
- import { supportsAccountDeletion, supportsAccountStatus, supportsProfile, supportsCountByGlobalRole, } from "../../accounts/account_store.js";
3
- import { sendPasswordResetEmail } from "../default_mailer.js";
4
- import { AccountDeletionService, } from "../account_deletion_service.js";
5
- import { PasswordPolicyError } from "../../password/password_manager.js";
6
- import { resolveEffectiveRolesCatalog } from "../runtime_toggles.js";
1
+ import { randomBytes } from 'node:crypto';
2
+ import { supportsAccountDeletion, supportsAccountStatus, supportsCountByGlobalRole, supportsProfile, } from '../../accounts/account_store.js';
3
+ import { PasswordPolicyError } from '../../password/password_manager.js';
4
+ import { AccountDeletionService } from '../account_deletion_service.js';
5
+ import { sendPasswordResetEmail } from '../default_mailer.js';
6
+ import { resolveEffectiveRolesCatalog } from '../runtime_toggles.js';
7
7
  /**
8
8
  * Lógica de gestão de usuários compartilhada entre o console admin (B6, HTML) e a
9
9
  * Admin REST API (R6, JSON). Encapsula o fluxo "create + invite", reset de senha,
@@ -24,9 +24,9 @@ export class AdminUsersService {
24
24
  const store = this.cfg.accountStore;
25
25
  const existing = await store.findByEmail(input.email);
26
26
  if (existing)
27
- return { ok: false, reason: "email_taken" };
27
+ return { ok: false, reason: 'email_taken' };
28
28
  const hasPassword = !!input.password;
29
- const initialPassword = input.password ?? randomBytes(24).toString("hex");
29
+ const initialPassword = input.password ?? randomBytes(24).toString('hex');
30
30
  let account;
31
31
  try {
32
32
  account = await store.create({
@@ -40,7 +40,7 @@ export class AdminUsersService {
40
40
  if (error instanceof PasswordPolicyError) {
41
41
  return {
42
42
  ok: false,
43
- reason: "password_policy",
43
+ reason: 'password_policy',
44
44
  messageKey: error.key,
45
45
  messageParams: error.params,
46
46
  };
@@ -48,7 +48,7 @@ export class AdminUsersService {
48
48
  throw error;
49
49
  }
50
50
  await this.cfg.audit?.record({
51
- type: "user.created",
51
+ type: 'user.created',
52
52
  accountId: account.id,
53
53
  email: input.email,
54
54
  actorId: actor.actorId,
@@ -70,7 +70,7 @@ export class AdminUsersService {
70
70
  return null;
71
71
  await this.sendResetEmail(ctx, account.email);
72
72
  await this.cfg.audit?.record({
73
- type: "user.password_reset_sent",
73
+ type: 'user.password_reset_sent',
74
74
  accountId,
75
75
  email: account.email,
76
76
  actorId: actor.actorId,
@@ -92,7 +92,7 @@ export class AdminUsersService {
92
92
  else
93
93
  await store.enableAccount(accountId);
94
94
  await this.cfg.audit?.record({
95
- type: disable ? "user.disabled" : "user.enabled",
95
+ type: disable ? 'user.disabled' : 'user.enabled',
96
96
  accountId,
97
97
  actorId: actor.actorId,
98
98
  ip: actor.ip,
@@ -123,7 +123,7 @@ export class AdminUsersService {
123
123
  // Roles que o usuário não tinha E que não estão no catálogo = inválidas.
124
124
  for (const role of roles) {
125
125
  if (!catalogNames.has(role) && !currentRoles.has(role)) {
126
- return "admin.roles.unknown_role";
126
+ return 'admin.roles.unknown_role';
127
127
  }
128
128
  }
129
129
  }
@@ -137,7 +137,7 @@ export class AdminUsersService {
137
137
  /** Roles globais que conferem acesso de admin (default ['ADMIN']). */
138
138
  adminRoles() {
139
139
  const roles = this.cfg.admin?.roles;
140
- return roles && roles.length > 0 ? roles : ["ADMIN"];
140
+ return roles && roles.length > 0 ? roles : ['ADMIN'];
141
141
  }
142
142
  /** Um conjunto de roles contém ao menos uma role de admin? */
143
143
  hasAdminRole(roles) {
@@ -226,11 +226,11 @@ export class AdminUsersService {
226
226
  return null;
227
227
  // Auto-rebaixamento: o ator removendo a própria role de admin.
228
228
  if (actorId && actorId === targetId)
229
- return "cannot_self_demote";
229
+ return 'cannot_self_demote';
230
230
  // Último admin: se o target é o único admin, a remoção causaria lockout.
231
231
  const admins = await this.countAdmins();
232
232
  if (admins <= 1)
233
- return "last_admin";
233
+ return 'last_admin';
234
234
  return null;
235
235
  }
236
236
  /** Atualiza nome/avatar (capacidade opcional). Retorna a conta ou null. */
@@ -251,15 +251,15 @@ export class AdminUsersService {
251
251
  async delete(oidc, accountId, actor, enqueue) {
252
252
  const store = this.cfg.accountStore;
253
253
  if (!supportsAccountDeletion(store))
254
- return { ok: false, reason: "unsupported" };
254
+ return { ok: false, reason: 'unsupported' };
255
255
  const account = await store.findById(accountId);
256
256
  if (!account)
257
- return { ok: false, reason: "not_found" };
258
- const source = actor.source === "admin" ? "admin" : "admin-api";
257
+ return { ok: false, reason: 'not_found' };
258
+ const source = actor.source === 'admin' ? 'admin' : 'admin-api';
259
259
  // Trilha administrativa ANTES do cascade — assim esta linha também é
260
260
  // anonimizada na etapa de anonimização do audit (não reintroduz PII).
261
261
  await this.cfg.audit?.record({
262
- type: "user.deleted",
262
+ type: 'user.deleted',
263
263
  accountId,
264
264
  email: account.email,
265
265
  actorId: actor.actorId,
@@ -1,7 +1,7 @@
1
1
  import '../augmentations.js';
2
2
  import { AdminClientsService } from '../admin_clients_service.js';
3
- import { clientDto, createdClientDto, apiError } from './dto.js';
4
- import { clientInputValidator, clientCreateInput, clientPartialInput } from '../admin_validators.js';
3
+ import { clientCreateInput, clientInputValidator, clientPartialInput, } from '../admin_validators.js';
4
+ import { apiError, clientDto, createdClientDto } from './dto.js';
5
5
  /** Resolve o serviço (== OidcService) + o AdminClientsService. */
6
6
  async function clientsService(ctx) {
7
7
  const service = await ctx.containerResolver.make('authkit.server');
@@ -1,9 +1,9 @@
1
1
  import '../augmentations.js';
2
- import { TokenVerifyService } from './token_verify_service.js';
3
2
  import { AdminSessionsService } from '../admin_sessions_service.js';
4
3
  import { computeAdminStats } from '../admin_stats_service.js';
5
- import { auditDto, apiError } from './dto.js';
6
4
  import { tokenVerifyValidator } from '../admin_validators.js';
5
+ import { apiError, auditDto } from './dto.js';
6
+ import { TokenVerifyService } from './token_verify_service.js';
7
7
  /**
8
8
  * Endpoints utilitários da Admin REST API: log de auditoria (`GET /audit`) e
9
9
  * introspecção genérica de token (`POST /tokens/verify`).
@@ -1,8 +1,8 @@
1
1
  import '../augmentations.js';
2
- import { AdminOrgsService } from './admin_orgs_service.js';
3
- import { orgDto, orgDetailDto, orgInvitationDto, apiError } from './dto.js';
2
+ import { orgAddMemberValidator, orgCreateValidator, orgInvitationValidator, orgMemberRoleValidator, orgUpdateValidator, } from '../admin_validators.js';
4
3
  import { resolveRuntimeSettings } from '../runtime_settings.js';
5
- import { orgCreateValidator, orgUpdateValidator, orgAddMemberValidator, orgMemberRoleValidator, orgInvitationValidator, } from '../admin_validators.js';
4
+ import { AdminOrgsService } from './admin_orgs_service.js';
5
+ import { apiError, orgDetailDto, orgDto, orgInvitationDto } from './dto.js';
6
6
  /** Lê a config + monta o actor `admin-api` para auditoria. */
7
7
  async function ctxBits(ctx) {
8
8
  const service = await ctx.containerResolver.make('authkit.server');
@@ -1,7 +1,7 @@
1
1
  import '../augmentations.js';
2
+ import { SettingLockedError, isSettingLocked, lockedSettingKeys } from '../config_locks.js';
2
3
  import { resolveRuntimeSettings } from '../runtime_settings.js';
3
- import { settingDto, apiError } from './dto.js';
4
- import { isSettingLocked, lockedSettingKeys, SettingLockedError } from '../config_locks.js';
4
+ import { apiError, settingDto } from './dto.js';
5
5
  /** 423 Locked: a setting foi travada via defineConfig (não editável em runtime). */
6
6
  function lockedResponse(ctx, err) {
7
7
  return ctx.response
@@ -16,8 +16,8 @@ function notSupported(ctx) {
16
16
  function resolveOrgId(ctx) {
17
17
  const qs = ctx.request.qs();
18
18
  if ('organizationId' in qs) {
19
- const v = qs['organizationId'];
20
- return v && v.trim() ? v.trim() : null;
19
+ const v = qs.organizationId;
20
+ return v?.trim() ? v.trim() : null;
21
21
  }
22
22
  return null;
23
23
  }
@@ -99,7 +99,13 @@ export default class ApiSettingsController {
99
99
  metadata: { key, value: body.value, organizationId: orgId },
100
100
  });
101
101
  const saved = await svc.getSetting(key, orgId);
102
- return settingDto({ key, organizationId: orgId, value: saved, updatedAt: new Date(), updatedBy: null });
102
+ return settingDto({
103
+ key,
104
+ organizationId: orgId,
105
+ value: saved,
106
+ updatedAt: new Date(),
107
+ updatedBy: null,
108
+ });
103
109
  }
104
110
  /** DELETE /settings/:key */
105
111
  async destroy(ctx) {
@@ -1,5 +1,5 @@
1
- import "../augmentations.js";
2
- import type { HttpContext } from "@adonisjs/core/http";
1
+ import '../augmentations.js';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
3
  /**
4
4
  * Recurso de usuários da Admin REST API (R6). JSON puro (camelCase), erros no
5
5
  * envelope `{ error: { code, message } }`. Toda escrita audita com `actor: 'admin-api'`.