@adonis-agora/authkit-server 0.66.3 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export type { AccountDeletionCapability, AccountImportCapability, AccountSecurit
7
7
  export { supportsAccountDeletion, supportsAccountImport, supportsAccountSecurity, supportsAccountStatus, supportsEmailVerificationStatus, supportsLoginMethodsPreference, supportsMagicLink, supportsMfa, supportsOrganizations, supportsOtpLogin, supportsPasskeys, supportsProfile, supportsProviderIdentity, } from './src/accounts/account_store.js';
8
8
  export type { AccountSecretEncrypter, LucidAccountStoreOptions, } from './src/accounts/lucid_account_store.js';
9
9
  export { appKeyEncrypter, lucidAccountStore } from './src/accounts/lucid_account_store.js';
10
+ export { AuthOrganization, AuthOrganizationInvitation, AuthOrganizationMember, defaultOrganizationModels, } from './src/accounts/lucid_store/organization_models.js';
10
11
  export type { LucidStoresModels, LucidStoresOptions, LucidStoresResult, } from './src/accounts/lucid_stores.js';
11
12
  export { lucidStores } from './src/accounts/lucid_stores.js';
12
13
  export type { AuditEvent, AuditEventType, AuditPage, AuditSink, ListAuditParams, StoredAuditEvent, } from './src/audit/audit_sink.js';
package/build/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  export { configure } from './commands/configure.js';
6
6
  export { supportsAccountDeletion, supportsAccountImport, supportsAccountSecurity, supportsAccountStatus, supportsEmailVerificationStatus, supportsLoginMethodsPreference, supportsMagicLink, supportsMfa, supportsOrganizations, supportsOtpLogin, supportsPasskeys, supportsProfile, supportsProviderIdentity, } from './src/accounts/account_store.js';
7
7
  export { appKeyEncrypter, lucidAccountStore } from './src/accounts/lucid_account_store.js';
8
+ export { AuthOrganization, AuthOrganizationInvitation, AuthOrganizationMember, defaultOrganizationModels, } from './src/accounts/lucid_store/organization_models.js';
8
9
  export { lucidStores } from './src/accounts/lucid_stores.js';
9
10
  export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
10
11
  export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
@@ -218,7 +218,10 @@ export default class AuthkitServerProvider {
218
218
  if (!db)
219
219
  return; // host sem @adonisjs/lucid — nada a gerenciar
220
220
  const { ensureAuthkitSchema } = await import('../src/schema/ensure.js');
221
- const report = await ensureAuthkitSchema(db, { connection: config.schema.connection });
221
+ const report = await ensureAuthkitSchema(db, {
222
+ connection: config.schema.connection,
223
+ accountTable: config.accountStore?.accountTable,
224
+ });
222
225
  const logger = await this.app.container.make('logger').catch(() => null);
223
226
  if (report.created.length > 0) {
224
227
  logger?.info('authkit: created tables %s', report.created.join(', '));
@@ -226,6 +229,13 @@ export default class AuthkitServerProvider {
226
229
  for (const [table, columns] of Object.entries(report.altered)) {
227
230
  logger?.info('authkit: added columns to %s: %s', table, columns.join(', '));
228
231
  }
232
+ if (!report.loginMethods.ensured) {
233
+ // Sem este aviso o host não tinha como saber: a coluna não foi criada e a
234
+ // preferência de método de login por conta fica no-op em silêncio.
235
+ logger?.warn('authkit: tabela da conta "%s" não existe — a coluna `login_methods` não foi ' +
236
+ 'garantida e a preferência de método de login por conta não vai funcionar. ' +
237
+ 'Defina `accountStore.accountTable` (ou crie a tabela) se o nome estiver errado.', report.loginMethods.table);
238
+ }
229
239
  }
230
240
  catch (error) {
231
241
  const logger = await this.app.container.make('logger').catch(() => null);
@@ -627,6 +627,20 @@ export type AccountStore = CoreAccountStore & {
627
627
  * blocos `Partial<...>` de capacidades probáveis.
628
628
  */
629
629
  readonly connectionName?: string;
630
+ /**
631
+ * Nome da tabela da conta (deriva de `Model.table` — e, se o model ainda não
632
+ * bootou, da naming strategy; ver `lucid_account_store.ts`). Mesmo espírito do
633
+ * {@link AccountStore.connectionName}: metadado opcional, não método de
634
+ * capacidade.
635
+ *
636
+ * Existe porque a coluna opcional `login_methods` é garantida no boot pelo
637
+ * `ensureAuthkitSchema`, e ele precisa saber em QUAL tabela ela pertence. Sem
638
+ * este metadado só resta assumir `users`, e aí uma conta cuja tabela tem outro
639
+ * nome (por exemplo `auth_users`, que é o que o scaffold da lib usa) fica com
640
+ * a coluna numa tabela que ninguém consulta — sem erro, sem aviso.
641
+ * Undefined → `users` (back-compat com stores próprios).
642
+ */
643
+ readonly accountTable?: string;
630
644
  } & Partial<MfaCapability & WebauthnCapability & ProviderIdentityCapability & AccountSecurityCapability & AccountStatusCapability & ProfileCapability & MagicLinkCapability & OtpLoginCapability & EmailVerificationStatusCapability & AccountDeletionCapability & AccountImportCapability & OrganizationsCapability & PasswordHistoryCapability & PasswordExpirationCapability & LoginMethodsPreferenceCapability>;
631
645
  /** Type guard: o store implementa a capacidade de MFA / TOTP. */
632
646
  export declare function supportsMfa(store: AccountStore): store is AccountStore & MfaCapability;
@@ -136,12 +136,29 @@ export interface LucidAccountStoreOptions {
136
136
  */
137
137
  pwnedFetch?: FetchLike;
138
138
  /**
139
- * Models Lucid para organizations (multi-tenancy). Quando os três forem fornecidos,
140
- * a capacidade `OrganizationsCapability` fica disponível no store. Os models devem
141
- * ser tabelas `auth_organizations`, `auth_organization_members` e
142
- * `auth_organization_invitations`. Ausente → capability AUSENTE (sem tabelas = desligado).
139
+ * Models Lucid para organizations (multi-tenancy).
140
+ *
141
+ * - **Ausente (default)** → usa os models DEFAULT da lib
142
+ * ({@link defaultOrganizationModels}), que já mapeiam as três tabelas
143
+ * lib-owned (`auth_organizations`, `auth_organization_members`,
144
+ * `auth_organization_invitations`). A `OrganizationsCapability` passa a
145
+ * existir por padrão. Isso é seguro porque as rotas do console de conta para
146
+ * orgs JÁ eram montadas por default (`register_auth_host`, bloco `if
147
+ * (mountOrgs)`, com controller capability-probed); antes, sem os models, a
148
+ * tela montada respondia 403; agora ela funciona. Não há tela nova — só uma
149
+ * que deixou de estar quebrada. As tabelas são criadas/evoluídas pelo
150
+ * `ensureAuthkitSchema`, então o mapeamento não é decisão do host.
151
+ * - `true` → idêntico ao default (atalho explícito; é o que apps existentes
152
+ * já usam e continua valendo).
153
+ * - `{ OrgModel, MemberModel, InvitationModel }` → escape hatch, para quem
154
+ * guarda as tabelas de auth numa conexão/schema próprios (os defaults não
155
+ * declaram `static connection`).
156
+ * - `false` → opt-out explícito: `OrganizationsCapability` AUSENTE no store.
157
+ * Use quando a dependência atual é `supportsOrganizations === false` (ex.:
158
+ * store/rotas que assumem a ausência). O `authkit:doctor` avisa se
159
+ * `organizations.enabled: true` e o store não tem a capability.
143
160
  */
144
- organizationModels?: {
161
+ organizationModels?: true | false | {
145
162
  OrgModel: any;
146
163
  MemberModel: any;
147
164
  InvitationModel: any;
@@ -153,23 +170,6 @@ export interface LucidAccountStoreOptions {
153
170
  */
154
171
  emailTokens?: EmailTokensConfigInput;
155
172
  }
156
- /**
157
- * Implementação default do {@link AccountStore} sobre um model Lucid composto
158
- * de `withAuthUser()` + `withCredentials()` (+ opcionalmente `withMfa()`). O
159
- * model carrega `connection`/`table` (app-específico) e, por convenção, uma
160
- * coluna `fullName` (mapeada de `name`).
161
- *
162
- * Composição por CAPACIDADE: o núcleo + MFA são sempre montados; passkeys
163
- * (WebAuthn) e account linking por provider só são montados quando o model
164
- * correspondente é fornecido — caso contrário a capacidade fica ABSENTE (os
165
- * métodos não existem no objeto retornado, em vez de presentes-mas-lançando).
166
- *
167
- * @remarks Para capabilities que dependem de tabelas opcionais (ex.:
168
- * `auth_password_history`), use {@link lucidAccountStoreAsync} que probe o DB
169
- * e monta o store já com as capabilities detectadas, sem a necessidade de
170
- * fornecer um model separado. A versão síncrona (`lucidAccountStore`) é mantida
171
- * por back-compat — capabilities de tabela ficam AUSENTES nela.
172
- */
173
173
  export declare function lucidAccountStore(Model: any, options?: LucidAccountStoreOptions): AccountStore;
174
174
  /**
175
175
  * Options estendidas para uso em testes ou quando o DB é injetado diretamente
@@ -3,6 +3,7 @@ import { PasswordManager } from '../password/password_manager.js';
3
3
  import { buildCore } from './lucid_store/core.js';
4
4
  import { buildLoginMethods, supportsLoginMethodsColumn } from './lucid_store/login_methods.js';
5
5
  import { buildMfa } from './lucid_store/mfa.js';
6
+ import { defaultOrganizationModels } from './lucid_store/organization_models.js';
6
7
  import { buildOrganizations } from './lucid_store/organizations.js';
7
8
  import { buildPasswordExpiration, buildPasswordHistory } from './lucid_store/password_hygiene.js';
8
9
  import { buildProviderIdentity } from './lucid_store/provider_identity.js';
@@ -103,23 +104,24 @@ export function appKeyEncrypter() {
103
104
  },
104
105
  };
105
106
  }
106
- /**
107
- * Implementação default do {@link AccountStore} sobre um model Lucid composto
108
- * de `withAuthUser()` + `withCredentials()` (+ opcionalmente `withMfa()`). O
109
- * model carrega `connection`/`table` (app-específico) e, por convenção, uma
110
- * coluna `fullName` (mapeada de `name`).
111
- *
112
- * Composição por CAPACIDADE: o núcleo + MFA são sempre montados; passkeys
113
- * (WebAuthn) e account linking por provider só são montados quando o model
114
- * correspondente é fornecido — caso contrário a capacidade fica ABSENTE (os
115
- * métodos não existem no objeto retornado, em vez de presentes-mas-lançando).
116
- *
117
- * @remarks Para capabilities que dependem de tabelas opcionais (ex.:
118
- * `auth_password_history`), use {@link lucidAccountStoreAsync} que probe o DB
119
- * e monta o store já com as capabilities detectadas, sem a necessidade de
120
- * fornecer um model separado. A versão síncrona (`lucidAccountStore`) é mantida
121
- * por back-compat — capabilities de tabela ficam AUSENTES nela.
122
- */
107
+ function resolveAccountTable(Model) {
108
+ try {
109
+ if (typeof Model?.table === 'string' && Model.table.length > 0) {
110
+ return Model.table;
111
+ }
112
+ const naming = Model?.namingStrategy;
113
+ if (naming && typeof naming.tableName === 'function') {
114
+ const resolved = naming.tableName(Model);
115
+ if (typeof resolved === 'string' && resolved.length > 0) {
116
+ return resolved;
117
+ }
118
+ }
119
+ }
120
+ catch {
121
+ // Model ainda não pronto (ou não-Lucid) — metadado é opcional.
122
+ }
123
+ return undefined;
124
+ }
123
125
  export function lucidAccountStore(Model, options = {}) {
124
126
  const mfaIssuer = options.mfaIssuer ?? 'AuthKit';
125
127
  const recoveryCodeCount = options.recoveryCodeCount ?? 8;
@@ -128,7 +130,15 @@ export function lucidAccountStore(Model, options = {}) {
128
130
  const encrypter = options.encrypter === false ? undefined : (options.encrypter ?? appKeyEncrypter());
129
131
  const ProviderIdentityModel = options.providerIdentityModel;
130
132
  const WebauthnCredentialModel = options.webauthnCredentialModel;
131
- const OrgModels = options.organizationModels;
133
+ // Organizations é padrão: ausente OU `true` → models default da lib. O
134
+ // opt-out explícito é `false`. O trio explícito segue como escape hatch.
135
+ const orgModelsOption = options.organizationModels;
136
+ const usesDefaultOrgModels = orgModelsOption === undefined || orgModelsOption === true;
137
+ const OrgModels = orgModelsOption === false
138
+ ? undefined
139
+ : usesDefaultOrgModels
140
+ ? defaultOrganizationModels
141
+ : orgModelsOption;
132
142
  // RP do WebAuthn: usado nas cerimônias. Default do rpName cai no mfaIssuer.
133
143
  const webauthn = options.webauthn ?? {
134
144
  rpName: mfaIssuer,
@@ -199,6 +209,10 @@ export function lucidAccountStore(Model, options = {}) {
199
209
  const store = {
200
210
  ...buildCore(ctx),
201
211
  ...buildMfa(ctx),
212
+ // Metadado (não capacidade): a tabela da conta, para o ensure da coluna
213
+ // `login_methods` e o doctor saberem onde ela pertence em vez de assumir
214
+ // `users`. Ver `resolveAccountTable`.
215
+ accountTable: resolveAccountTable(Model),
202
216
  ...(ProviderIdentityModel ? buildProviderIdentity(ctx, ProviderIdentityModel) : {}),
203
217
  ...(WebauthnCredentialModel
204
218
  ? buildWebauthn(ctx, WebauthnCredentialModel, webauthn, ceremonies)
@@ -216,17 +230,23 @@ export function lucidAccountStore(Model, options = {}) {
216
230
  // Preferência por usuário de tipos de login: só quando o model tem a coluna
217
231
  // `login_methods` (JSONB). Sem a coluna → capacidade ausente (feature no-op).
218
232
  ...(supportsLoginMethodsColumn(Model) ? buildLoginMethods(ctx) : {}),
219
- // Organizations (multi-tenancy): só quando os três models foram fornecidos.
233
+ // Organizations (multi-tenancy): por padrão usa os models default da lib;
234
+ // ausente só com `organizationModels: false` (opt-out explícito).
220
235
  ...(OrgModels
221
- ? buildOrganizations({
222
- OrgModel: OrgModels.OrgModel,
223
- MemberModel: OrgModels.MemberModel,
224
- InvitationModel: OrgModels.InvitationModel,
225
- findAccountEmail: async (accountId) => {
226
- const row = await Model.find(accountId);
227
- return row?.email ?? null;
228
- },
229
- })
236
+ ? {
237
+ // Origem dos models, para o `authkit:doctor` reportar sem re-inferir.
238
+ // NÃO faz parte do contrato AccountStore.
239
+ __organizationModelsSource: usesDefaultOrgModels ? 'default' : 'explicit',
240
+ ...buildOrganizations({
241
+ OrgModel: OrgModels.OrgModel,
242
+ MemberModel: OrgModels.MemberModel,
243
+ InvitationModel: OrgModels.InvitationModel,
244
+ findAccountEmail: async (accountId) => {
245
+ const row = await Model.find(accountId);
246
+ return row?.email ?? null;
247
+ },
248
+ }),
249
+ }
230
250
  : {}),
231
251
  // Config de senha resolvida — exposta (não-enumerável) para o authkit:doctor
232
252
  // inspecionar policy/checkPwned. NÃO faz parte do contrato AccountStore.
@@ -0,0 +1,67 @@
1
+ import { BaseModel } from '@adonisjs/lucid/orm';
2
+ import type { DateTime } from 'luxon';
3
+ /**
4
+ * Models default das três tabelas de organizations.
5
+ *
6
+ * Estas tabelas são LIB-OWNED: quem as cria e evolui é o `ensureAuthkitSchema`
7
+ * (ver `TABLES` em `src/schema/ensure.ts`). Exigir que cada host reescrevesse
8
+ * este mapeamento à mão rendia duas coisas ruins — boilerplate sem nenhuma
9
+ * decisão do host, e drift silencioso: uma coluna nova nestas tabelas chega
10
+ * pelo `autoManage` sem que o model escrito à mão no host saiba dela, e o
11
+ * sintoma aparece longe da causa.
12
+ *
13
+ * Use com `organizationModels: true` em {@link lucidAccountStore}. O caminho
14
+ * explícito (`{ OrgModel, MemberModel, InvitationModel }`) continua valendo como
15
+ * escape hatch — é para quem guarda as tabelas de auth numa conexão/schema
16
+ * próprios (`static connection = 'auth'`), que estes defaults não declaram.
17
+ *
18
+ * Não crie migration para estas tabelas: elas são criadas/atualizadas pelo
19
+ * `schema.autoManage` do authkit.
20
+ */
21
+ export declare class AuthOrganization extends BaseModel {
22
+ static table: string;
23
+ /** Os ids são sempre fornecidos pelo builder (randomUUID) — nunca pelo banco. */
24
+ static selfAssignPrimaryKey: boolean;
25
+ id: string;
26
+ name: string;
27
+ slug: string;
28
+ logoUrl: string | null;
29
+ /**
30
+ * Coluna `json`. O contrato público (`OrgSummary.metadata`) já é
31
+ * `Record<string, unknown> | null`, e é o que o builder grava/lê — declarar o
32
+ * mesmo aqui mantém o model alinhado ao que a lib promete.
33
+ */
34
+ metadata: Record<string, unknown> | null;
35
+ createdAt: DateTime | null;
36
+ updatedAt: DateTime | null;
37
+ }
38
+ export declare class AuthOrganizationMember extends BaseModel {
39
+ static table: string;
40
+ static selfAssignPrimaryKey: boolean;
41
+ id: string;
42
+ organizationId: string;
43
+ accountId: string;
44
+ role: string;
45
+ createdAt: DateTime | null;
46
+ updatedAt: DateTime | null;
47
+ }
48
+ export declare class AuthOrganizationInvitation extends BaseModel {
49
+ static table: string;
50
+ static selfAssignPrimaryKey: boolean;
51
+ id: string;
52
+ organizationId: string;
53
+ email: string;
54
+ role: string;
55
+ tokenHash: string;
56
+ invitedBy: string;
57
+ expiresAt: DateTime;
58
+ acceptedAt: DateTime | null;
59
+ createdAt: DateTime | null;
60
+ updatedAt: DateTime | null;
61
+ }
62
+ /** O trio que {@link lucidAccountStore} aceita em `organizationModels: true`. */
63
+ export declare const defaultOrganizationModels: {
64
+ readonly OrgModel: typeof AuthOrganization;
65
+ readonly MemberModel: typeof AuthOrganizationMember;
66
+ readonly InvitationModel: typeof AuthOrganizationInvitation;
67
+ };
@@ -0,0 +1,113 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { BaseModel, column } from '@adonisjs/lucid/orm';
8
+ /**
9
+ * Models default das três tabelas de organizations.
10
+ *
11
+ * Estas tabelas são LIB-OWNED: quem as cria e evolui é o `ensureAuthkitSchema`
12
+ * (ver `TABLES` em `src/schema/ensure.ts`). Exigir que cada host reescrevesse
13
+ * este mapeamento à mão rendia duas coisas ruins — boilerplate sem nenhuma
14
+ * decisão do host, e drift silencioso: uma coluna nova nestas tabelas chega
15
+ * pelo `autoManage` sem que o model escrito à mão no host saiba dela, e o
16
+ * sintoma aparece longe da causa.
17
+ *
18
+ * Use com `organizationModels: true` em {@link lucidAccountStore}. O caminho
19
+ * explícito (`{ OrgModel, MemberModel, InvitationModel }`) continua valendo como
20
+ * escape hatch — é para quem guarda as tabelas de auth numa conexão/schema
21
+ * próprios (`static connection = 'auth'`), que estes defaults não declaram.
22
+ *
23
+ * Não crie migration para estas tabelas: elas são criadas/atualizadas pelo
24
+ * `schema.autoManage` do authkit.
25
+ */
26
+ export class AuthOrganization extends BaseModel {
27
+ static table = 'auth_organizations';
28
+ /** Os ids são sempre fornecidos pelo builder (randomUUID) — nunca pelo banco. */
29
+ static selfAssignPrimaryKey = true;
30
+ }
31
+ __decorate([
32
+ column({ isPrimary: true })
33
+ ], AuthOrganization.prototype, "id", void 0);
34
+ __decorate([
35
+ column()
36
+ ], AuthOrganization.prototype, "name", void 0);
37
+ __decorate([
38
+ column()
39
+ ], AuthOrganization.prototype, "slug", void 0);
40
+ __decorate([
41
+ column()
42
+ ], AuthOrganization.prototype, "logoUrl", void 0);
43
+ __decorate([
44
+ column()
45
+ ], AuthOrganization.prototype, "metadata", void 0);
46
+ __decorate([
47
+ column.dateTime({ autoCreate: true })
48
+ ], AuthOrganization.prototype, "createdAt", void 0);
49
+ __decorate([
50
+ column.dateTime({ autoCreate: true, autoUpdate: true })
51
+ ], AuthOrganization.prototype, "updatedAt", void 0);
52
+ export class AuthOrganizationMember extends BaseModel {
53
+ static table = 'auth_organization_members';
54
+ static selfAssignPrimaryKey = true;
55
+ }
56
+ __decorate([
57
+ column({ isPrimary: true })
58
+ ], AuthOrganizationMember.prototype, "id", void 0);
59
+ __decorate([
60
+ column()
61
+ ], AuthOrganizationMember.prototype, "organizationId", void 0);
62
+ __decorate([
63
+ column()
64
+ ], AuthOrganizationMember.prototype, "accountId", void 0);
65
+ __decorate([
66
+ column()
67
+ ], AuthOrganizationMember.prototype, "role", void 0);
68
+ __decorate([
69
+ column.dateTime({ autoCreate: true })
70
+ ], AuthOrganizationMember.prototype, "createdAt", void 0);
71
+ __decorate([
72
+ column.dateTime({ autoCreate: true, autoUpdate: true })
73
+ ], AuthOrganizationMember.prototype, "updatedAt", void 0);
74
+ export class AuthOrganizationInvitation extends BaseModel {
75
+ static table = 'auth_organization_invitations';
76
+ static selfAssignPrimaryKey = true;
77
+ }
78
+ __decorate([
79
+ column({ isPrimary: true })
80
+ ], AuthOrganizationInvitation.prototype, "id", void 0);
81
+ __decorate([
82
+ column()
83
+ ], AuthOrganizationInvitation.prototype, "organizationId", void 0);
84
+ __decorate([
85
+ column()
86
+ ], AuthOrganizationInvitation.prototype, "email", void 0);
87
+ __decorate([
88
+ column()
89
+ ], AuthOrganizationInvitation.prototype, "role", void 0);
90
+ __decorate([
91
+ column()
92
+ ], AuthOrganizationInvitation.prototype, "tokenHash", void 0);
93
+ __decorate([
94
+ column()
95
+ ], AuthOrganizationInvitation.prototype, "invitedBy", void 0);
96
+ __decorate([
97
+ column.dateTime()
98
+ ], AuthOrganizationInvitation.prototype, "expiresAt", void 0);
99
+ __decorate([
100
+ column.dateTime()
101
+ ], AuthOrganizationInvitation.prototype, "acceptedAt", void 0);
102
+ __decorate([
103
+ column.dateTime({ autoCreate: true })
104
+ ], AuthOrganizationInvitation.prototype, "createdAt", void 0);
105
+ __decorate([
106
+ column.dateTime({ autoCreate: true, autoUpdate: true })
107
+ ], AuthOrganizationInvitation.prototype, "updatedAt", void 0);
108
+ /** O trio que {@link lucidAccountStore} aceita em `organizationModels: true`. */
109
+ export const defaultOrganizationModels = {
110
+ OrgModel: AuthOrganization,
111
+ MemberModel: AuthOrganizationMember,
112
+ InvitationModel: AuthOrganizationInvitation,
113
+ };
@@ -14,8 +14,16 @@ export interface LucidStoresModels {
14
14
  providerIdentity?: any;
15
15
  /** Model de `withWebauthnCredential()` — habilita passkeys. */
16
16
  webauthnCredential?: any;
17
- /** Trio de models de organizations — habilita multi-tenancy. */
18
- organizations?: {
17
+ /**
18
+ * Organizations (multi-tenancy) — habilita a `OrganizationsCapability`.
19
+ *
20
+ * **Ausente → ligada por padrão** (models default da lib; as três tabelas são
21
+ * lib-owned, criadas pelo `ensureAuthkitSchema`). `true` é o atalho explícito
22
+ * para o mesmo caminho; `false` é o opt-out (capability ausente). O trio
23
+ * explícito fica como escape hatch para quem guarda as tabelas de auth numa
24
+ * conexão/schema próprios.
25
+ */
26
+ organizations?: true | false | {
19
27
  OrgModel: any;
20
28
  MemberModel: any;
21
29
  InvitationModel: any;
@@ -37,9 +45,14 @@ export type LucidStoresOptions = Omit<LucidAccountStoreOptions, 'providerIdentit
37
45
  * const { accountStore, patStore, audit } = lucidStores(
38
46
  * { account: AuthUser, pat: PersonalAccessToken, audit: AuditLog,
39
47
  * providerIdentity: ProviderIdentity, webauthnCredential: WebauthnCredential,
40
- * organizations: { OrgModel: Organization, MemberModel: OrganizationMember, InvitationModel: OrganizationInvitation } },
48
+ * organizations: true },
41
49
  * { mfaIssuer: 'educ(a)ção', webauthn }
42
50
  * )
43
51
  * ```
52
+ *
53
+ * Organizations é ligada por padrão (models default da lib); `organizations:
54
+ * false` desliga. Se as tabelas de auth vivem numa conexão/schema próprios, passe
55
+ * o trio explícito (`{ OrgModel, MemberModel, InvitationModel }`) — os defaults
56
+ * não declaram `static connection`.
44
57
  */
45
58
  export declare function lucidStores(models: LucidStoresModels, options?: LucidStoresOptions): LucidStoresResult;
@@ -10,10 +10,15 @@ import { lucidAccountStore } from './lucid_account_store.js';
10
10
  * const { accountStore, patStore, audit } = lucidStores(
11
11
  * { account: AuthUser, pat: PersonalAccessToken, audit: AuditLog,
12
12
  * providerIdentity: ProviderIdentity, webauthnCredential: WebauthnCredential,
13
- * organizations: { OrgModel: Organization, MemberModel: OrganizationMember, InvitationModel: OrganizationInvitation } },
13
+ * organizations: true },
14
14
  * { mfaIssuer: 'educ(a)ção', webauthn }
15
15
  * )
16
16
  * ```
17
+ *
18
+ * Organizations é ligada por padrão (models default da lib); `organizations:
19
+ * false` desliga. Se as tabelas de auth vivem numa conexão/schema próprios, passe
20
+ * o trio explícito (`{ OrgModel, MemberModel, InvitationModel }`) — os defaults
21
+ * não declaram `static connection`.
17
22
  */
18
23
  export function lucidStores(models, options = {}) {
19
24
  const accountStore = lucidAccountStore(models.account, {
@@ -119,7 +119,11 @@ export declare function checkAccessTokens(input: DoctorInput): Finding | null;
119
119
  /**
120
120
  * Organizations (multi-tenancy). Informa se a capacidade está disponível
121
121
  * (store expõe createOrg) e avisa se `organizations.enabled: true` no config mas
122
- * a capacidade não está presente no store (organizationModels não foram passados).
122
+ * a capacidade não está presente no store.
123
+ *
124
+ * Com `lucidAccountStore()`, a capability existe POR PADRÃO (models default da
125
+ * lib); o aviso abaixo só é alcançável para store não-lucid que não a implementa
126
+ * ou para um store lucid construído com `organizationModels: false` (opt-out).
123
127
  */
124
128
  export declare function checkOrganizations(input: DoctorInput): Finding | null;
125
129
  /**
@@ -488,7 +488,11 @@ export function checkAccessTokens(input) {
488
488
  /**
489
489
  * Organizations (multi-tenancy). Informa se a capacidade está disponível
490
490
  * (store expõe createOrg) e avisa se `organizations.enabled: true` no config mas
491
- * a capacidade não está presente no store (organizationModels não foram passados).
491
+ * a capacidade não está presente no store.
492
+ *
493
+ * Com `lucidAccountStore()`, a capability existe POR PADRÃO (models default da
494
+ * lib); o aviso abaixo só é alcançável para store não-lucid que não a implementa
495
+ * ou para um store lucid construído com `organizationModels: false` (opt-out).
492
496
  */
493
497
  export function checkOrganizations(input) {
494
498
  const cfg = input.authkitConfig;
@@ -501,15 +505,26 @@ export function checkOrganizations(input) {
501
505
  return {
502
506
  level: 'warn',
503
507
  message: 'organizations.enabled: true, but the accountStore has no OrganizationsCapability — ' +
504
- 'pass `organizationModels: { OrgModel, MemberModel, InvitationModel }` to `lucidAccountStore()`. ' +
505
- 'Expected tables: auth_organizations, auth_organization_members, auth_organization_invitations.',
508
+ 'with `lucidAccountStore()` it is present by default; if you passed ' +
509
+ '`organizationModels: false`, drop the opt-out (or pass the explicit ' +
510
+ '`{ OrgModel, MemberModel, InvitationModel }` trio when the auth tables live on their ' +
511
+ 'own connection/schema). Expected tables: auth_organizations, ' +
512
+ 'auth_organization_members, auth_organization_invitations.',
506
513
  };
507
514
  }
508
515
  if (storeSupports) {
509
516
  const roles = cfg.organizations?.roles ?? ['owner', 'admin', 'member'];
517
+ // Origem dos models: default da lib (organizationModels ausente/true) ou
518
+ // trio explícito do host. Ausente em store não-lucid → wording genérica.
519
+ const source = store.__organizationModelsSource;
520
+ const models = source === 'default'
521
+ ? 'lib defaults (organizationModels omitted or true)'
522
+ : source === 'explicit'
523
+ ? 'host-provided explicit trio'
524
+ : 'lib defaults or host-provided models';
510
525
  return {
511
526
  level: 'ok',
512
- message: `organizations capability present (roles: ${roles.join(', ')}).`,
527
+ message: `organizations capability present (models: ${models}; roles: ${roles.join(', ')}).`,
513
528
  };
514
529
  }
515
530
  // Auto mode (enabled === undefined) and store doesn't support — silently ok (opt-in).
@@ -26,12 +26,28 @@
26
26
  export interface EnsureSchemaOptions {
27
27
  /** Conexão Lucid a usar. Default: conexão primária. */
28
28
  connection?: string;
29
+ /**
30
+ * Tabela da conta, onde a coluna opcional `login_methods` pertence. Vem do
31
+ * metadado `accountStore.accountTable` (o provider repassa no boot). Undefined
32
+ * → `users`, que era o único valor possível antes deste metadado existir.
33
+ */
34
+ accountTable?: string;
29
35
  }
30
36
  export interface EnsureSchemaReport {
31
37
  /** Tabelas criadas do zero nesta execução. */
32
38
  created: string[];
33
39
  /** Colunas adicionadas em tabelas já existentes: tabela → colunas. */
34
40
  altered: Record<string, string[]>;
41
+ /**
42
+ * Desfecho da coluna `login_methods`. `ensured: false` significa que a tabela
43
+ * da conta não existe no banco, então NADA foi feito — e é o caso que
44
+ * silenciava o problema: o host precisa saber que a preferência de método de
45
+ * login não vai funcionar até a tabela existir.
46
+ */
47
+ loginMethods: {
48
+ table: string;
49
+ ensured: boolean;
50
+ };
35
51
  }
36
52
  /**
37
53
  * Garante que as tabelas do authkit existem e têm todas as colunas que esta
@@ -234,7 +234,11 @@ async function columnExists(conn, table, column) {
234
234
  */
235
235
  export async function ensureAuthkitSchema(db, options = {}) {
236
236
  const conn = options.connection ? db.connection(options.connection) : db.connection();
237
- const report = { created: [], altered: {} };
237
+ const report = {
238
+ created: [],
239
+ altered: {},
240
+ loginMethods: { table: options.accountTable ?? 'users', ensured: false },
241
+ };
238
242
  for (const def of TABLES) {
239
243
  if (!(await tableExists(conn, def.name))) {
240
244
  try {
@@ -260,29 +264,48 @@ export async function ensureAuthkitSchema(db, options = {}) {
260
264
  report.altered[def.name].push(column);
261
265
  }
262
266
  }
263
- // Coluna `login_methods` em `auth.users` — a tabela é HOST-owned (não está em
264
- // TABLES porque o nome/shape são decisão do app), mas a LI B consome a coluna
265
- // (LoginMethodsPreferenceCapability). Alguns deploys de host só migram o schema
266
- // do domínio, não o schema `auth` — então a migration manual da coluna pode
267
- // nunca rodar, e isso derrubava TODO login/callback OIDC com "column users.login_methods
268
- // does not exist" no instante em que o model passou a declará-la.
269
- // Aqui garantimos: SE `auth.users` existe E a coluna falta, adicionamos. Nunca
270
- // criamos a tabela (host-owned). Aditivo + idempotente — roda em todo boot.
271
- try {
272
- if (await tableExists(conn, 'users')) {
273
- if (!(await columnExists(conn, 'users', 'login_methods'))) {
274
- await conn.schema.alterTable('users', (t) => {
267
+ // Coluna `login_methods` na tabela da CONTA — a tabela é HOST-owned (não está
268
+ // em TABLES porque o nome/shape são decisão do app), mas a LIB consome a
269
+ // coluna (LoginMethodsPreferenceCapability). Alguns deploys de host só migram
270
+ // o schema do domínio, não o schema de auth — então a migration manual da
271
+ // coluna pode nunca rodar, e isso derrubava TODO login/callback OIDC com
272
+ // "column ...login_methods does not exist" no instante em que o model passou a
273
+ // declará-la.
274
+ //
275
+ // Aqui garantimos: SE a tabela da conta existe E a coluna falta, adicionamos.
276
+ // Nunca criamos a tabela (host-owned). Aditivo + idempotente — roda em todo boot.
277
+ //
278
+ // O nome da tabela vem do store (`accountStore.accountTable`), NÃO de um
279
+ // `users` fixo: com a conta em `auth_users` (o nome que o próprio scaffold da
280
+ // lib usa), o `users` fixo acertava uma tabela qualquer de mesmo nome e a
281
+ // coluna ia parar no lugar errado sem erro nenhum.
282
+ const accountTable = options.accountTable ?? 'users';
283
+ if (await tableExists(conn, accountTable)) {
284
+ try {
285
+ if (!(await columnExists(conn, accountTable, 'login_methods'))) {
286
+ await conn.schema.alterTable(accountTable, (t) => {
275
287
  t.jsonb('login_methods').nullable();
276
288
  });
277
- report.altered.users = ['login_methods'];
289
+ report.altered[accountTable] = ['login_methods'];
278
290
  }
291
+ report.loginMethods.ensured = true;
279
292
  }
280
- }
281
- catch (error) {
282
- // Tabela host-owned pode não existir num banco que nunca criou users — não
283
- // é erro: fail-soft (a migração do host cuida). Nunca criar a tabela aqui.
284
- if (!(await tableExists(conn, 'users'))) {
285
- throw error; // alguém criou entre o probe e o ALTER — repropaga se sumiu
293
+ catch (error) {
294
+ /**
295
+ * Corrida entre instâncias subindo juntas: se a coluna já existe agora,
296
+ * outra ganhou o ALTER — segue o jogo. Qualquer outra falha PROPAGA.
297
+ *
298
+ * O re-probe tem de ser da COLUNA, não da tabela: checar a tabela fazia um
299
+ * ALTER que falhou virar `ensured: true`, ou seja, o report dizia sucesso e
300
+ * o boot não avisava nada — o silêncio que este bloco existe para acabar.
301
+ * (Mesma semântica do probe de `createTable` logo acima.)
302
+ */
303
+ if (await columnExists(conn, accountTable, 'login_methods')) {
304
+ report.loginMethods.ensured = true;
305
+ }
306
+ else {
307
+ throw error;
308
+ }
286
309
  }
287
310
  }
288
311
  return report;
@@ -3,7 +3,7 @@
3
3
  }}}
4
4
  import env from '#start/env'
5
5
  import AuthUser from '#models/auth_user'
6
- import { defineConfig, adapters, inertiaRenderer } from '@adonis-agora/authkit-server'
6
+ import { defineConfig, adapters, lucidAccountStore, inertiaRenderer } from '@adonis-agora/authkit-server'
7
7
 
8
8
  const authServerConfig = defineConfig({
9
9
  issuer: env.get('AUTHKIT_ISSUER'),
@@ -14,18 +14,9 @@ const authServerConfig = defineConfig({
14
14
  ],
15
15
  ttl: { accessToken: '15m', refreshToken: '30d' },
16
16
  globalRolesClaim: 'roles',
17
- findAccount: async (sub) => {
18
- const user = await AuthUser.find(sub)
19
- if (!user) return null
20
- return { id: user.id, email: user.email, globalRoles: user.globalRoles }
21
- },
22
- verifyCredentials: async (email, password) => {
23
- const user = await AuthUser.query().where('email', email).first()
24
- if (!user || !(await user.verifyPassword(password))) return null
25
- return { id: user.id }
26
- },
17
+ accountStore: lucidAccountStore(AuthUser),
27
18
  /**
28
- * Renderer Inertia/React: apenas as views listadas em `views` vão ao Inertia;
19
+ * Renderer Inertia/React: apenas as views listadas em "views" vão ao Inertia;
29
20
  * as demais (incluindo todas as telas admin/*) recaem silenciosamente no
30
21
  * renderer Edge built-in da lib — evitando SSR crash por página inexistente.
31
22
  *
@@ -11,10 +11,10 @@ export default class extends BaseSchema {
11
11
  async up() {
12
12
  this.schema.createTable(this.tableName, (table) => {
13
13
  /**
14
- * String, NÃO increments(): o hook `@beforeCreate` do model scaffoldado
15
- * (`models/auth_user.stub`) atribui um `randomUUID()` antes do insert.
14
+ * String, NÃO increments(): o hook @beforeCreate do model scaffoldado
15
+ * (models/auth_user.stub) atribui um randomUUID() antes do insert.
16
16
  * Uma coluna auto-increment aceitaria o INSERT mesmo assim, mas o valor
17
- * do UUID seria descartado e o `id` do model voltaria como o rowid
17
+ * do UUID seria descartado e o id do model voltaria como o rowid
18
18
  * interno do banco — a conta ficaria inalcançável pelo id real na
19
19
  * próxima request. Ver packages/authkit-server/stubs/models/auth_user.stub.
20
20
  */
@@ -34,7 +34,7 @@ export default class extends BaseSchema {
34
34
 
35
35
  // Coluna própria do model scaffoldado (não vem de nenhum mixin): a tela
36
36
  // de signup embutida sempre coleta "Nome" e o Lucid store passa esse
37
- // valor direto para `AuthUser.create()` — sem esta coluna o primeiro
37
+ // valor direto para AuthUser.create() — sem esta coluna o primeiro
38
38
  // signup quebra com "Cannot define 'fullName' on 'AuthUser' model,
39
39
  // since it is not defined as a model property".
40
40
  table.string('full_name').nullable()
@@ -20,7 +20,7 @@ import { withAuthUser, withCredentials } from '@adonis-agora/authkit-server'
20
20
  export default class AuthUser extends compose(BaseModel, withAuthUser(), withCredentials()) {
21
21
  /**
22
22
  * Sem isto, o Lucid ignora o id atribuído pelo hook abaixo e sobrescreve
23
- * `id` com o retorno bruto do INSERT (o rowid interno do SQLite/Postgres)
23
+ * id com o retorno bruto do INSERT (o rowid interno do SQLite/Postgres)
24
24
  * assim que a linha é salva — mesmo resultado prático de não ter o hook: a
25
25
  * conta some do próprio id que acabou de criar.
26
26
  */
@@ -31,7 +31,7 @@ export default class AuthUser extends compose(BaseModel, withAuthUser(), withCre
31
31
 
32
32
  /**
33
33
  * Nem withAuthUser() nem withCredentials() geram o id — sem este hook o
34
- * Lucid insere NULL nesta coluna string e o `id` do model volta como o
34
+ * Lucid insere NULL nesta coluna string e o id do model volta como o
35
35
  * rowid interno do banco, tornando a conta inalcançável pelo id real na
36
36
  * próxima request.
37
37
  */
@@ -42,7 +42,7 @@ export default class AuthUser extends compose(BaseModel, withAuthUser(), withCre
42
42
 
43
43
  /**
44
44
  * A tela de signup embutida sempre coleta um campo "Nome", e o Lucid store
45
- * passa esse valor direto para `AuthUser.create()` — sem esta coluna o
45
+ * passa esse valor direto para AuthUser.create() — sem esta coluna o
46
46
  * primeiro signup quebra com "Cannot define 'fullName' on 'AuthUser'
47
47
  * model, since it is not defined as a model property".
48
48
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/authkit-server",
3
- "version": "0.66.3",
3
+ "version": "0.68.0",
4
4
  "description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
5
5
  "license": "MIT",
6
6
  "author": "dudousxd",
@@ -153,6 +153,7 @@
153
153
  "react-dom": "19.2.8",
154
154
  "react-error-boundary": "6.1.5",
155
155
  "recharts": "3.10.1",
156
+ "tempura": "^0.4.1",
156
157
  "typescript": "7.0.2",
157
158
  "vite": "8.2.2"
158
159
  },
@@ -6,7 +6,7 @@ description: >-
6
6
  routes every IdP app must register (show/login/consent on AuthInteractionController),
7
7
  `node ace configure --ui=edge|react|headless` presets, the shell-controller +
8
8
  service.interactions split (details(ctx), login(ctx,{email,password}), consent(ctx)),
9
- overriding verifyCredentials in config/authkit.ts, renderers edgeRenderer/inertiaRenderer,
9
+ overriding accountStore.verifyCredentials in config/authkit.ts, renderers edgeRenderer/inertiaRenderer,
10
10
  and end-to-end testing with @adonis-agora/authkit-testing (createTestIdentity,
11
11
  mintTestIdToken, serveJwks, fakeAuthenticator). Use when the authorization flow 404s at
12
12
  the login screen, wiring custom login UI, plugging an external user base, or testing
@@ -81,24 +81,30 @@ the shell only translates between HTTP and those calls.
81
81
  Source: `packages/authkit-server/README.md` § UI de login/consent ("o controller
82
82
  ejetado é casca: a lógica vive em `service.interactions`").
83
83
 
84
- ### Pattern 2 — plug your user base via `verifyCredentials`
84
+ ### Pattern 2 — plug your user base via `accountStore.verifyCredentials`
85
85
 
86
- `verifyCredentials` in `config/authkit.ts` decides whether credentials are valid;
87
- `service.interactions.login` calls it. The default queries the `AuthUser` model by
88
- email and uses `verifyPassword` — override to authenticate against anything else:
86
+ `verifyCredentials` on the configured `accountStore` decides whether credentials
87
+ are valid; `service.interactions.login` calls it. The default
88
+ `lucidAccountStore(AuthUser)` queries the `AuthUser` model by email and uses the
89
+ `withCredentials` mixin — override the store method to authenticate against
90
+ anything else (`findAccount`/`verifyCredentials` are NOT top-level `defineConfig`
91
+ keys; `AuthServerConfigInput` accepts only `accountStore`, from which the lib
92
+ derives both):
89
93
 
90
94
  ```ts
91
95
  // config/authkit.ts
92
96
  defineConfig({
93
97
  issuer: env.get('AUTHKIT_ISSUER'),
94
98
  adapter: adapters.redis({ connection: 'main' }),
95
- accountStore: lucidAccountStore(AuthUser),
96
- verifyCredentials: async (email, password) => {
97
- // Return the account on success; throw/falsy paths fail the login.
98
- const account = await AuthUser.query().where('email', email).first()
99
- if (!account) throw new Error('Invalid credentials')
100
- await verifyPassword(account.passwordHash, password)
101
- return account
99
+ accountStore: {
100
+ ...lucidAccountStore(AuthUser),
101
+ verifyCredentials: async (email, password) => {
102
+ // Return the account on success; throw/falsy paths fail the login.
103
+ const account = await AuthUser.query().where('email', email).first()
104
+ if (!account) throw new Error('Invalid credentials')
105
+ await verifyPassword(account.passwordHash, password)
106
+ return account
107
+ },
102
108
  },
103
109
  })
104
110
  ```
@@ -3,7 +3,7 @@
3
3
  }}}
4
4
  import env from '#start/env'
5
5
  import AuthUser from '#models/auth_user'
6
- import { defineConfig, adapters, inertiaRenderer } from '@adonis-agora/authkit-server'
6
+ import { defineConfig, adapters, lucidAccountStore, inertiaRenderer } from '@adonis-agora/authkit-server'
7
7
 
8
8
  const authServerConfig = defineConfig({
9
9
  issuer: env.get('AUTHKIT_ISSUER'),
@@ -14,18 +14,9 @@ const authServerConfig = defineConfig({
14
14
  ],
15
15
  ttl: { accessToken: '15m', refreshToken: '30d' },
16
16
  globalRolesClaim: 'roles',
17
- findAccount: async (sub) => {
18
- const user = await AuthUser.find(sub)
19
- if (!user) return null
20
- return { id: user.id, email: user.email, globalRoles: user.globalRoles }
21
- },
22
- verifyCredentials: async (email, password) => {
23
- const user = await AuthUser.query().where('email', email).first()
24
- if (!user || !(await user.verifyPassword(password))) return null
25
- return { id: user.id }
26
- },
17
+ accountStore: lucidAccountStore(AuthUser),
27
18
  /**
28
- * Renderer Inertia/React: apenas as views listadas em `views` vão ao Inertia;
19
+ * Renderer Inertia/React: apenas as views listadas em "views" vão ao Inertia;
29
20
  * as demais (incluindo todas as telas admin/*) recaem silenciosamente no
30
21
  * renderer Edge built-in da lib — evitando SSR crash por página inexistente.
31
22
  *
@@ -11,10 +11,10 @@ export default class extends BaseSchema {
11
11
  async up() {
12
12
  this.schema.createTable(this.tableName, (table) => {
13
13
  /**
14
- * String, NÃO increments(): o hook `@beforeCreate` do model scaffoldado
15
- * (`models/auth_user.stub`) atribui um `randomUUID()` antes do insert.
14
+ * String, NÃO increments(): o hook @beforeCreate do model scaffoldado
15
+ * (models/auth_user.stub) atribui um randomUUID() antes do insert.
16
16
  * Uma coluna auto-increment aceitaria o INSERT mesmo assim, mas o valor
17
- * do UUID seria descartado e o `id` do model voltaria como o rowid
17
+ * do UUID seria descartado e o id do model voltaria como o rowid
18
18
  * interno do banco — a conta ficaria inalcançável pelo id real na
19
19
  * próxima request. Ver packages/authkit-server/stubs/models/auth_user.stub.
20
20
  */
@@ -34,7 +34,7 @@ export default class extends BaseSchema {
34
34
 
35
35
  // Coluna própria do model scaffoldado (não vem de nenhum mixin): a tela
36
36
  // de signup embutida sempre coleta "Nome" e o Lucid store passa esse
37
- // valor direto para `AuthUser.create()` — sem esta coluna o primeiro
37
+ // valor direto para AuthUser.create() — sem esta coluna o primeiro
38
38
  // signup quebra com "Cannot define 'fullName' on 'AuthUser' model,
39
39
  // since it is not defined as a model property".
40
40
  table.string('full_name').nullable()
@@ -20,7 +20,7 @@ import { withAuthUser, withCredentials } from '@adonis-agora/authkit-server'
20
20
  export default class AuthUser extends compose(BaseModel, withAuthUser(), withCredentials()) {
21
21
  /**
22
22
  * Sem isto, o Lucid ignora o id atribuído pelo hook abaixo e sobrescreve
23
- * `id` com o retorno bruto do INSERT (o rowid interno do SQLite/Postgres)
23
+ * id com o retorno bruto do INSERT (o rowid interno do SQLite/Postgres)
24
24
  * assim que a linha é salva — mesmo resultado prático de não ter o hook: a
25
25
  * conta some do próprio id que acabou de criar.
26
26
  */
@@ -31,7 +31,7 @@ export default class AuthUser extends compose(BaseModel, withAuthUser(), withCre
31
31
 
32
32
  /**
33
33
  * Nem withAuthUser() nem withCredentials() geram o id — sem este hook o
34
- * Lucid insere NULL nesta coluna string e o `id` do model volta como o
34
+ * Lucid insere NULL nesta coluna string e o id do model volta como o
35
35
  * rowid interno do banco, tornando a conta inalcançável pelo id real na
36
36
  * próxima request.
37
37
  */
@@ -42,7 +42,7 @@ export default class AuthUser extends compose(BaseModel, withAuthUser(), withCre
42
42
 
43
43
  /**
44
44
  * A tela de signup embutida sempre coleta um campo "Nome", e o Lucid store
45
- * passa esse valor direto para `AuthUser.create()` — sem esta coluna o
45
+ * passa esse valor direto para AuthUser.create() — sem esta coluna o
46
46
  * primeiro signup quebra com "Cannot define 'fullName' on 'AuthUser'
47
47
  * model, since it is not defined as a model property".
48
48
  */