@adonis-agora/authkit-server 1.0.0-rc.1 → 1.0.0-rc.3

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 (98) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +4 -5
  3. package/build/commands/clients_create.d.ts +4 -0
  4. package/build/commands/clients_create.js +97 -0
  5. package/build/commands/commands.json +14 -0
  6. package/build/index.d.ts +8 -11
  7. package/build/index.js +5 -9
  8. package/build/providers/authkit_server_provider.js +6 -8
  9. package/build/src/agents/config.d.ts +9 -13
  10. package/build/src/agents/config.js +17 -11
  11. package/build/src/agents/delegation_service.js +3 -3
  12. package/build/src/agents/delegation_store.d.ts +3 -2
  13. package/build/src/agents/delegation_store.js +6 -5
  14. package/build/src/agents/extension.d.ts +261 -0
  15. package/build/src/agents/extension.js +40 -0
  16. package/build/src/agents/middleware.js +1 -1
  17. package/build/src/agents/protocol.d.ts +4 -4
  18. package/build/src/agents/registry_store.d.ts +3 -2
  19. package/build/src/agents/registry_store.js +1 -1
  20. package/build/src/agents/runtime.d.ts +26 -7
  21. package/build/src/agents/runtime.js +110 -75
  22. package/build/src/audit/audit_sink.d.ts +1 -1
  23. package/build/src/audit/audit_sink.js +6 -1
  24. package/build/src/define_config.d.ts +16 -12
  25. package/build/src/define_config.js +11 -7
  26. package/build/src/host/access_token_verifier.js +7 -0
  27. package/build/src/host/account_api/account_api_controller.js +8 -6
  28. package/build/src/host/account_session_sign_in.d.ts +12 -0
  29. package/build/src/host/account_session_sign_in.js +19 -0
  30. package/build/src/host/admin_api/api_clients_controller.d.ts +37 -0
  31. package/build/src/host/admin_api/api_clients_controller.js +31 -1
  32. package/build/src/host/admin_api/dto.d.ts +3 -1
  33. package/build/src/host/admin_api/dto.js +2 -0
  34. package/build/src/host/admin_clients_service.d.ts +20 -0
  35. package/build/src/host/admin_clients_service.js +55 -0
  36. package/build/src/host/admin_console/console_clients_controller.d.ts +41 -0
  37. package/build/src/host/admin_console/console_clients_controller.js +34 -1
  38. package/build/src/host/admin_console/console_personal_agents_controller.d.ts +1 -6
  39. package/build/src/host/admin_console/console_personal_agents_controller.js +50 -30
  40. package/build/src/host/admin_sessions_service.js +8 -5
  41. package/build/src/host/admin_validators.d.ts +29 -0
  42. package/build/src/host/admin_validators.js +30 -0
  43. package/build/src/host/auth_host_config.d.ts +6 -2
  44. package/build/src/host/controllers/account_apps_controller.js +15 -11
  45. package/build/src/host/csrf.d.ts +3 -3
  46. package/build/src/host/csrf.js +3 -13
  47. package/build/src/host/default_mailer.d.ts +11 -6
  48. package/build/src/host/default_mailer.js +16 -12
  49. package/build/src/host/i18n.d.ts +3 -14
  50. package/build/src/host/i18n.js +15 -13
  51. package/build/src/host/register_auth_host.js +30 -61
  52. package/build/src/host/ui-dist/assets/index-u0bMxkLg.js +67 -0
  53. package/build/src/host/ui-dist/index.html +1 -1
  54. package/build/src/provider/build_provider.js +37 -6
  55. package/build/src/provider/oidc_service.d.ts +1 -1
  56. package/build/src/provider/oidc_service.js +1 -1
  57. package/build/src/schema/ensure.d.ts +14 -0
  58. package/build/src/schema/ensure.js +43 -150
  59. package/build/src/service_tenants/client_metadata.d.ts +39 -0
  60. package/build/src/service_tenants/client_metadata.js +80 -0
  61. package/build/src/service_tenants/config.d.ts +44 -0
  62. package/build/src/service_tenants/config.js +44 -0
  63. package/build/src/service_tenants/provider_hooks.d.ts +52 -0
  64. package/build/src/service_tenants/provider_hooks.js +124 -0
  65. package/build/src/service_tenants/tenant_verifier.d.ts +73 -0
  66. package/build/src/service_tenants/tenant_verifier.js +104 -0
  67. package/package.json +2 -2
  68. package/build/src/agents/poppy/client_registry.d.ts +0 -50
  69. package/build/src/agents/poppy/client_registry.js +0 -260
  70. package/build/src/agents/poppy/config.d.ts +0 -396
  71. package/build/src/agents/poppy/config.js +0 -228
  72. package/build/src/agents/poppy/dpop.d.ts +0 -61
  73. package/build/src/agents/poppy/dpop.js +0 -158
  74. package/build/src/agents/poppy/email_code_sign_in.d.ts +0 -27
  75. package/build/src/agents/poppy/email_code_sign_in.js +0 -140
  76. package/build/src/agents/poppy/errors.d.ts +0 -25
  77. package/build/src/agents/poppy/errors.js +0 -25
  78. package/build/src/agents/poppy/replay.d.ts +0 -25
  79. package/build/src/agents/poppy/replay.js +0 -106
  80. package/build/src/agents/poppy/resource.d.ts +0 -100
  81. package/build/src/agents/poppy/resource.js +0 -129
  82. package/build/src/agents/poppy/safe_fetch.d.ts +0 -48
  83. package/build/src/agents/poppy/safe_fetch.js +0 -262
  84. package/build/src/agents/poppy/service.d.ts +0 -293
  85. package/build/src/agents/poppy/service.js +0 -1458
  86. package/build/src/agents/poppy/session_jwt.d.ts +0 -30
  87. package/build/src/agents/poppy/session_jwt.js +0 -133
  88. package/build/src/agents/poppy/store.d.ts +0 -106
  89. package/build/src/agents/poppy/store.js +0 -261
  90. package/build/src/agents/poppy/web_session.d.ts +0 -39
  91. package/build/src/agents/poppy/web_session.js +0 -122
  92. package/build/src/host/controllers/poppy_consent_controller.d.ts +0 -19
  93. package/build/src/host/controllers/poppy_consent_controller.js +0 -199
  94. package/build/src/host/controllers/poppy_controller.d.ts +0 -33
  95. package/build/src/host/controllers/poppy_controller.js +0 -219
  96. package/build/src/host/poppy_session_key.d.ts +0 -9
  97. package/build/src/host/poppy_session_key.js +0 -9
  98. package/build/src/host/ui-dist/assets/index-D0EIeyKK.js +0 -67
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @adonis-agora/authkit-server
2
2
 
3
+ ## 1.0.0-rc.3
4
+
5
+ ### Minor Changes
6
+
7
+ - [#460](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/460) [`1858ee8`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/1858ee837bb4edcf0578f86d224693ac9a86a495) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Service tenants: a client can act as one partition of another service, such as a durable control plane.
8
+
9
+ - `serviceTenants: { resources: { 'urn:agora:durable': { expiresIn: 600 } } }` in `config/authkit.ts` declares the resources (RFC 8707) that issue service-tenant tokens: JWT access tokens (RFC 9068) with `aud` = the resource and the client's `partition` and `capabilities` as claims.
10
+ - A service-tenant client is confidential, uses only `client_credentials` and has no redirect URIs. Create and edit it from the console (**Service tenant** kind), the Admin API and the SDKs (`serviceTenant: { partition, capabilities? }`), or `node ace authkit:clients:create --partition=acme --capability=reports`.
11
+ - Any client can now be disabled and enabled again (console, `POST /clients/:id/disable|enable`, SDK `clients.disable/enable`): the token endpoint answers `invalid_client` from the next request on.
12
+ - `authkitTenantVerifier()` (authkit-server) verifies those tokens against the local issuer and keys and returns `{ tenant, capabilities }`; `authkitTenantToken({ issuer, clientId, clientSecret, resource })` (authkit-client) fetches, caches and refreshes them on the tenant side. Both fit durable's `verifyTenant` and `tenant.token` as a function or a class, without depending on durable.
13
+ - New audit events: `client.disabled`, `client.enabled`, `service_tenant.token_issued`.
14
+ - Access-token verification (`oidcBearerGuard`, in-process and remote) now refuses a token whose `sub` is a client (a `client_credentials` token), so a service-tenant token never authenticates a user.
15
+
16
+ ## 1.0.0-rc.2
17
+
18
+ ### Major Changes
19
+
20
+ - [#456](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/456) [`9c12ef9`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/9c12ef9c1c49db9d54a7da6d241264499ad76e18) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Poppy (the Personal Agent Protocol) moves out of `@adonis-agora/authkit-server` into the new `@adonis-agora/authkit-poppy` package, and authkit-server gains a stable extension surface for personal-agent protocols. See [Install `@adonis-agora/authkit-poppy` for Poppy](https://github.com/DavideCarvalho/adonis-agora-authkit/blob/main/apps/docs/content/docs/migrating-to-1-0.mdx#install-adonis-agoraauthkit-poppy-for-poppy).
21
+
22
+ Breaking changes (`@adonis-agora/authkit-server`):
23
+
24
+ - `personalAgents.poppy` is removed: install `@adonis-agora/authkit-poppy` and use `personalAgents: { extensions: [poppy({ ... })] }` with the same options. A config that still has `personalAgents.poppy` fails at boot. Routes, tables, tokens and sessions are unchanged, so no data migration is needed.
25
+ - Every Poppy export (`PoppyConfigInput` and the other `Poppy*` types, `poppyEmailCodeSignIn`, `verifyPoppyRequest`, `poppyAuth`, `poppyOf`, `poppyWebSession`, `poppyWebSessionOf`, `installPoppySlots`, `POPPY_AUTHENTICATE_SLOT`, `POPPY_WEB_SESSION_KEY`, `PoppyError`, `verifyDpopProof`, `accessTokenHash`, `hmacNonceSource`, `databaseReplayStore`, `memoryReplayStore`, `redisReplayStore`, `safeFetchJson`, `isBlockedAddress`, `SafeFetchError`, `maskEmail`) now comes from `@adonis-agora/authkit-poppy`.
26
+ - `mail.onPoppySignInCode` is removed: pass `sendCode` to `poppyEmailCodeSignIn()`.
27
+ - `authkitCsrfExceptions` no longer takes `poppyPrefix`; extensions' endpoints are exempted from the config (`personalAgentExtensions: false` turns that off).
28
+ - `ensureAuthkitSchema()` no longer creates the `auth_poppy_*` tables (the extension's tables are ensured at boot; `ensurePoppySchema()` for migrations).
29
+ - Admin console API: an extension's `protocols` entry is `{ label, requireRegistration, hostResolver, allowHttpIdentifiers, identifierLabel, identifierPlaceholder }`.
30
+
31
+ New, stable for 1.x: `personalAgents.extensions` and the types `PersonalAgentExtension`, `PersonalAgentExtensionDefinition`, `PersonalAgentExtensionContext`, `PersonalAgentRouteKit`, `PersonalAgentHost`, `PersonalAgentGrantLedger`, `PersonalAgentGrant`, `PersonalAgentRefreshToken`, `PersonalAgentAccessTokens`, `PersonalAgentProtocolRuntime`, `PersonalAgentGrantSummary`, `PersonalAgentConsoleSummary`, `ResolvedPersonalAgentExtension`, `AuthkitTable`; the functions `personalAgentExtensionRuntime`, `ensureAuthkitTables`, `sendAuthkitCodeEmail`, `signInAccountSession` and `signOutAccountSession`; and the `tables` option of `ensureAuthkitSchema`.
32
+
33
+ Breaking changes (`@adonis-agora/authkit-react`):
34
+
35
+ - `PersonalAgentProtocol` is `'pact'` or any extension id, and `PersonalAgentsOverview.protocols` has one entry per extension (`PersonalAgentExtensionOverview`) instead of a fixed `poppy` key. `AccountAgentGrant.protocol` uses `PersonalAgentProtocol`.
36
+
3
37
  ## 1.0.0-rc.1
4
38
 
5
39
  ### Major Changes
package/README.md CHANGED
@@ -15,11 +15,10 @@ wrapper around [`oidc-provider`](https://github.com/panva/node-oidc-provider).
15
15
  auth via `acr_values`, Dynamic Client Registration (RFC 7591/7592).
16
16
  - **Personal agents** — AI assistants acting for your users: agent identity by signed JWT
17
17
  (JWKS, no shared secrets) and user-approved, revocable delegation with scopes you define,
18
- over a pluggable protocol adapter ([PACT](https://openpactprotocol.org) built in).
19
- Plus the [Personal Agent Protocol ("Poppy")](https://personalagentprotocol.org/docs/spec):
20
- discovery, signed `Poppy-Session` agent sessions, Direct/Device/Mediated sign-in, MCP and browser sessions.
21
- ⚠️ **Experimental** — tracks the spec's Draft 0.3 and will change (possibly breaking, outside
22
- semver majors) while the spec is a draft.
18
+ over a pluggable protocol adapter ([PACT](https://openpactprotocol.org) built in), plus
19
+ `personalAgents.extensions` for protocols shipped as their own packages — the
20
+ [Personal Agent Protocol ("Poppy")](https://personalagentprotocol.org/docs/spec) is
21
+ [`@adonis-agora/authkit-poppy`](https://www.npmjs.com/package/@adonis-agora/authkit-poppy).
23
22
  - **Native apps** — RFC 8252 native clients (`authkit:clients:create --native`: private-use
24
23
  scheme / claimed https / loopback redirects, always public + PKCE) and the `@adonisjs/auth`
25
24
  guards `oidcRpGuard` (session) and `oidcBearerGuard` (`Authorization: Bearer` access tokens,
@@ -11,8 +11,10 @@ import type { CommandOptions } from '@adonisjs/core/types/ace';
11
11
  * node ace authkit:clients:create --client-id=my-api --redirect-uri=https://api/cb --redirect-uri=https://api/cb2 --grant=client_credentials
12
12
  * node ace authkit:clients:create --redirect-uri=https://app/cb --json
13
13
  * node ace authkit:clients:create --client-id=my-mobile --native --redirect-uri=com.example.app:/oauth
14
+ * node ace authkit:clients:create --client-id=worker-acme --partition=acme --capability=reports
14
15
  */
15
16
  export default class AuthkitClientsCreate extends BaseCommand {
17
+ #private;
16
18
  static commandName: string;
17
19
  static description: string;
18
20
  static help: string[];
@@ -25,6 +27,8 @@ export default class AuthkitClientsCreate extends BaseCommand {
25
27
  native?: boolean;
26
28
  backchannelLogoutUri?: string;
27
29
  clientSecret?: string;
30
+ partition?: string;
31
+ capability?: string[];
28
32
  json?: boolean;
29
33
  run(): Promise<void>;
30
34
  }
@@ -16,6 +16,7 @@ import { BaseCommand, flags } from '@adonisjs/core/ace';
16
16
  * node ace authkit:clients:create --client-id=my-api --redirect-uri=https://api/cb --redirect-uri=https://api/cb2 --grant=client_credentials
17
17
  * node ace authkit:clients:create --redirect-uri=https://app/cb --json
18
18
  * node ace authkit:clients:create --client-id=my-mobile --native --redirect-uri=com.example.app:/oauth
19
+ * node ace authkit:clients:create --client-id=worker-acme --partition=acme --capability=reports
19
20
  */
20
21
  export default class AuthkitClientsCreate extends BaseCommand {
21
22
  static commandName = 'authkit:clients:create';
@@ -41,9 +42,18 @@ export default class AuthkitClientsCreate extends BaseCommand {
41
42
  ' node ace authkit:clients:create --redirect-uri=https://app/cb --backchannel-logout-uri=https://app/bc',
42
43
  ' node ace authkit:clients:create --client-id=my-app --redirect-uri=https://a/cb --redirect-uri=https://b/cb --json',
43
44
  ' node ace authkit:clients:create --client-id=my-mobile --native --redirect-uri=com.example.app:/oauth',
45
+ '',
46
+ 'Service tenant (a process that acts as one partition, e.g. a durable tenant pod):',
47
+ 'use --partition (and --capability, repeatable). Implies a confidential client with',
48
+ 'only the client_credentials grant and no redirect URIs. Needs serviceTenants.resources',
49
+ 'in config/authkit.ts.',
50
+ ' node ace authkit:clients:create --client-id=worker-acme --partition=acme --capability=reports',
44
51
  ];
45
52
  static options = { startApp: true };
46
53
  async run() {
54
+ if (this.partition !== undefined || this.capability?.length) {
55
+ return this.#createServiceTenant();
56
+ }
47
57
  const redirectUris = this.redirectUri ?? [];
48
58
  if (redirectUris.length === 0) {
49
59
  this.logger.logError('❌ --redirect-uri é obrigatório. Passe ao menos uma URI de callback.');
@@ -120,6 +130,83 @@ export default class AuthkitClientsCreate extends BaseCommand {
120
130
  this.logger.info('');
121
131
  }
122
132
  }
133
+ /** `--partition`: a service tenant (client_credentials only, `partition` claim). */
134
+ async #createServiceTenant() {
135
+ if (!this.partition) {
136
+ this.logger.logError('❌ --capability needs --partition.');
137
+ this.exitCode = 1;
138
+ return;
139
+ }
140
+ const conflicting = [
141
+ this.redirectUri?.length && '--redirect-uri',
142
+ this.postLogoutUri?.length && '--post-logout-uri',
143
+ this.public && '--public',
144
+ this.native && '--native',
145
+ this.backchannelLogoutUri && '--backchannel-logout-uri',
146
+ this.grant?.some((g) => g !== 'client_credentials') && '--grant',
147
+ ].filter(Boolean);
148
+ if (conflicting.length) {
149
+ this.logger.logError(`❌ ${conflicting.join(', ')} cannot be used with --partition (a service tenant only uses client_credentials).`);
150
+ this.exitCode = 1;
151
+ return;
152
+ }
153
+ const service = await this.app.container.make('authkit.server');
154
+ const { AdminClientsService } = await import('../src/host/admin_clients_service.js');
155
+ const { ClientMetadataError } = await import('../src/host/client_metadata.js');
156
+ const svc = new AdminClientsService(service);
157
+ const input = {
158
+ clientId: this.clientId,
159
+ applicationType: 'web',
160
+ redirectUris: [],
161
+ postLogoutRedirectUris: [],
162
+ grantTypes: ['client_credentials'],
163
+ tokenEndpointAuthMethod: 'client_secret_basic',
164
+ serviceTenant: { partition: this.partition, capabilities: this.capability ?? [] },
165
+ };
166
+ let created;
167
+ try {
168
+ created = this.clientSecret
169
+ ? await svc.createWithSecret(input, this.clientSecret)
170
+ : await svc.create(input);
171
+ }
172
+ catch (err) {
173
+ if (err instanceof ClientMetadataError) {
174
+ this.logger.logError(`❌ ${err.message}`);
175
+ this.exitCode = 1;
176
+ return;
177
+ }
178
+ throw err;
179
+ }
180
+ const tenant = (await svc.find(created.clientId))?.serviceTenant;
181
+ await service.config.audit
182
+ ?.record({
183
+ type: 'client.created',
184
+ clientId: created.clientId,
185
+ ip: null,
186
+ metadata: { actor: 'cli', partition: tenant?.partition },
187
+ })
188
+ .catch(() => { });
189
+ if (this.json) {
190
+ this.logger.info(JSON.stringify({
191
+ clientId: created.clientId,
192
+ clientSecret: created.clientSecret,
193
+ grantTypes: ['client_credentials'],
194
+ serviceTenant: tenant,
195
+ resources: Object.keys(service.config.serviceTenants.resources),
196
+ }, null, 2));
197
+ return;
198
+ }
199
+ this.logger.success(`Service tenant created: ${created.clientId}`);
200
+ this.logger.info(` partition: ${tenant?.partition}`);
201
+ if (tenant?.capabilities.length) {
202
+ this.logger.info(` capabilities: ${tenant.capabilities.join(', ')}`);
203
+ }
204
+ this.logger.info(` resources: ${Object.keys(service.config.serviceTenants.resources).join(', ')}`);
205
+ this.logger.info('');
206
+ this.logger.success('CLIENT SECRET (shown ONCE - store it now):');
207
+ this.logger.success(` ${created.clientSecret}`);
208
+ this.logger.info('');
209
+ }
123
210
  }
124
211
  __decorate([
125
212
  flags.string({ description: 'client_id desejado. Omitir gera um UUID aleatório.' })
@@ -155,6 +242,16 @@ __decorate([
155
242
  description: 'Usa este client_secret em vez de gerar um (client confidencial). Útil para manter o secret que os RPs já usam.',
156
243
  })
157
244
  ], AuthkitClientsCreate.prototype, "clientSecret", void 0);
245
+ __decorate([
246
+ flags.string({
247
+ description: 'Service tenant: the partition its tokens act as (`partition` claim). Implies client_credentials only, no redirect URIs.',
248
+ })
249
+ ], AuthkitClientsCreate.prototype, "partition", void 0);
250
+ __decorate([
251
+ flags.array({
252
+ description: 'Service tenant: capability granted in its tokens (repeatable). Needs --partition.',
253
+ })
254
+ ], AuthkitClientsCreate.prototype, "capability", void 0);
158
255
  __decorate([
159
256
  flags.boolean({
160
257
  description: 'Output em JSON machine-readable (inclui clientId e clientSecret).',
@@ -130,6 +130,20 @@
130
130
  "type": "string",
131
131
  "description": "Usa este client_secret em vez de gerar um (client confidencial)."
132
132
  },
133
+ {
134
+ "name": "partition",
135
+ "flagName": "partition",
136
+ "required": false,
137
+ "type": "string",
138
+ "description": "Service tenant: the partition its tokens act as (`partition` claim). Implies client_credentials only, no redirect URIs."
139
+ },
140
+ {
141
+ "name": "capability",
142
+ "flagName": "capability",
143
+ "required": false,
144
+ "type": "array",
145
+ "description": "Service tenant: capability granted in its tokens (repeatable). Needs --partition."
146
+ },
133
147
  {
134
148
  "name": "json",
135
149
  "flagName": "json",
package/build/index.d.ts CHANGED
@@ -15,19 +15,12 @@ export type { PersonalAgentIdentity } from './src/agents/agent_identity.js';
15
15
  export { PersonalAgentVerifier } from './src/agents/agent_identity.js';
16
16
  export type { PersonalAgentDelegationConfigInput, PersonalAgentRegistration, PersonalAgentResolver, PersonalAgentsConfigInput, ResolvedPersonalAgentsConfig, } from './src/agents/config.js';
17
17
  export type { DelegationContext, DelegationGrantSummary, DelegationReceipt, } from './src/agents/delegation_service.js';
18
+ export type { AuthkitTable, PersonalAgentAccessTokens, PersonalAgentConsoleSummary, PersonalAgentExtension, PersonalAgentExtensionContext, PersonalAgentExtensionDefinition, PersonalAgentGrant, PersonalAgentGrantLedger, PersonalAgentGrantSummary, PersonalAgentHost, PersonalAgentProtocolRuntime, PersonalAgentRefreshToken, PersonalAgentRouteKit, ResolvedPersonalAgentExtension, } from './src/agents/extension.js';
18
19
  export type { PersonalAgentAuthOptions, PersonalAgentRequestContext, } from './src/agents/middleware.js';
19
20
  export { personalAgentAuth, personalAgentOf, personalAgentReceipt, personalAgentSecurity, personalAgentStepUp, } from './src/agents/middleware.js';
20
- export type { PoppyAgentProtocolEntry, PoppyApiEntry, PoppyBrowserLogin, PoppyClientsConfigInput, PoppyConfigInput, PoppyLimiter, PoppyMediatedConfigInput, PoppyMediatedField, PoppyMediatedResult, PoppyMediatedVerifyInput, PoppyPrincipalBase, PoppyReplayStore, PoppyScopeHint, ResolvedPoppyConfig, } from './src/agents/poppy/config.js';
21
- export { accessTokenHash, type DpopNonceSource, type DpopResult, hmacNonceSource, type VerifyDpopInput, verifyDpopProof, } from './src/agents/poppy/dpop.js';
22
- export { maskEmail, type PoppyEmailCodeSignInOptions, poppyEmailCodeSignIn, } from './src/agents/poppy/email_code_sign_in.js';
23
- export { PoppyError, type PoppyErrorCode } from './src/agents/poppy/errors.js';
24
- export { databaseReplayStore, memoryReplayStore, redisReplayStore, } from './src/agents/poppy/replay.js';
25
- export { installPoppySlots, POPPY_AUTHENTICATE_SLOT, type PoppyAuthenticate, type PoppyAuthResult, type PoppyPrincipal, type PoppySlotRequest, poppyAuth, poppyOf, verifyPoppyRequest, writePoppyAuthError, } from './src/agents/poppy/resource.js';
26
- export { isBlockedAddress, SafeFetchError, safeFetchJson, } from './src/agents/poppy/safe_fetch.js';
27
- export type { PoppyAuthError, PoppyGrantSummary, PoppySessionState, PoppyTokenResponse, PoppyVerifyOptions, } from './src/agents/poppy/service.js';
28
- export { type PoppyWebSessionMarker, poppyWebSession, poppyWebSessionOf, } from './src/agents/poppy/web_session.js';
29
21
  export type { BuiltinProtocolId, PactOptions, PersonalAgentProtocol, } from './src/agents/protocol.js';
30
22
  export { pact, pactProtocol } from './src/agents/protocol.js';
23
+ export { type PersonalAgentRuntimeSource, personalAgentExtensionRuntime, } from './src/agents/runtime.js';
31
24
  export type { AuditEvent, AuditEventType, AuditPage, AuditSink, ListAuditParams, StoredAuditEvent, } from './src/audit/audit_sink.js';
32
25
  export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
33
26
  export type { ConsoleAuthorize, ConsoleAuthorizeResult, ConsoleAuthorizer, ConsoleAuthorizerClass, } from './src/console_authorize.js';
@@ -58,6 +51,7 @@ export type { AccountPathKey, AccountPathsOptions } from './src/host/account_pat
58
51
  export { accountPath, accountPrefix, joinAccountPath, } from './src/host/account_paths.js';
59
52
  export type { AccountConfirmMethod, AccountConfirmProps, AccountEmailConfirmedProps, AccountLoginProps, AccountMfaProps, AccountSecurityProps, } from './src/host/account_screen_props.js';
60
53
  export { ACCOUNT_SESSION_KEY } from './src/host/account_session_key.js';
54
+ export { signInAccountSession, signOutAccountSession, } from './src/host/account_session_sign_in.js';
61
55
  export { ACTIVE_ORG_COOKIE, ACTIVE_ORG_COOKIE_TTL, decodeActiveOrgCookie, encodeActiveOrgCookie, readActiveOrgFromKoaCtx, } from './src/host/active_org_cookie.js';
62
56
  export type { AddMemberInput as AdminAddMemberInput, CreateInvitationInput as AdminCreateInvitationInput, CreateOrgInput as AdminCreateOrgInput, OrgDetail, OrgWithMemberCount, UpdateOrgInput as AdminUpdateOrgInput, } from './src/host/admin_api/admin_orgs_service.js';
63
57
  export { AdminOrgsService } from './src/host/admin_api/admin_orgs_service.js';
@@ -92,6 +86,7 @@ export type { CustomLoginIdentity, CustomLoginMethod, CustomLoginMethodBinding,
92
86
  export { authenticateCustomLogin, beginCustomLogin, completeCustomLogin, } from './src/host/custom_login.js';
93
87
  export type { CustomMfaContext, CustomMfaDescription, CustomMfaDescriptor, CustomMfaField, CustomMfaMethod, CustomMfaMethodBinding, CustomMfaMethodConstructor, CustomMfaMethods, } from './src/host/custom_mfa.js';
94
88
  export { beginCustomMfa, customMfaViewProps, verifyCustomMfa } from './src/host/custom_mfa.js';
89
+ export { sendAuthkitCodeEmail } from './src/host/default_mailer.js';
95
90
  export { normalizeEmailIdentifier } from './src/host/email_identifier.js';
96
91
  export type { ResolveGeo } from './src/host/geo.js';
97
92
  export { GEO_RESOLVE_TIMEOUT_MS, resolveGeoSafe } from './src/host/geo.js';
@@ -111,7 +106,6 @@ export { OidcRpGuard, oidcRpGuard } from './src/host/oidc_rp_guard.js';
111
106
  export { evaluateLoginOtp, generateOtpCode, OTP_LOGIN_DEFAULTS, type OtpLoginConfigInput, type OtpVerifyOutcome, type ResolvedOtpLoginConfig, resolveOtpLoginConfig, } from './src/host/otp_login.js';
112
107
  export type { PersistentRpOptions } from './src/host/persistent_rp_session.js';
113
108
  export { endRpSession } from './src/host/persistent_rp_session.js';
114
- export { POPPY_WEB_SESSION_KEY } from './src/host/poppy_session_key.js';
115
109
  export type { AuthThrottles, ThrottleMiddleware } from './src/host/rate_limit.js';
116
110
  export { createAuthThrottles } from './src/host/rate_limit.js';
117
111
  export type { AccountScreensOptions, AuthHostOptions, AuthHostRouteMap, } from './src/host/register_auth_host.js';
@@ -163,5 +157,8 @@ export { OidcService } from './src/provider/oidc_service.js';
163
157
  export { checkClientRegistration, classifyRedirect, type RedirectUriPolicy, type RegistrationOperation, RegistrationPolicyError, type ResolvedRedirectUriPolicy, type ValidateRegistrationHook, } from './src/provider/registration_policy.js';
164
158
  export { registerOidcRoutes } from './src/register_routes.js';
165
159
  export type { EnsureSchemaOptions, EnsureSchemaReport } from './src/schema/ensure.js';
166
- export { ensureAuthkitSchema } from './src/schema/ensure.js';
160
+ export { ensureAuthkitSchema, ensureAuthkitTables } from './src/schema/ensure.js';
161
+ export type { ServiceTenantInfo } from './src/service_tenants/client_metadata.js';
162
+ export type { ResolvedServiceTenantResource, ResolvedServiceTenantsConfig, ServiceTenantResourceInput, ServiceTenantsConfigInput, } from './src/service_tenants/config.js';
163
+ export { AuthkitTenantVerifier, type AuthkitTenantVerifierFn, type AuthkitTenantVerifierOptions, authkitTenantVerifier, type TenantTokenIssuer, type TenantVerifierInput, type VerifiedTenant, } from './src/service_tenants/tenant_verifier.js';
167
164
  export { stubsRoot } from './stubs/main.js';
package/build/index.js CHANGED
@@ -10,14 +10,8 @@ export { lucidStores } from './src/accounts/lucid_stores.js';
10
10
  export { ProviderIdentities, ProviderIdentitiesUnsupportedError, } from './src/accounts/provider_identities.js';
11
11
  export { PersonalAgentVerifier } from './src/agents/agent_identity.js';
12
12
  export { personalAgentAuth, personalAgentOf, personalAgentReceipt, personalAgentSecurity, personalAgentStepUp, } from './src/agents/middleware.js';
13
- export { accessTokenHash, hmacNonceSource, verifyDpopProof, } from './src/agents/poppy/dpop.js';
14
- export { maskEmail, poppyEmailCodeSignIn, } from './src/agents/poppy/email_code_sign_in.js';
15
- export { PoppyError } from './src/agents/poppy/errors.js';
16
- export { databaseReplayStore, memoryReplayStore, redisReplayStore, } from './src/agents/poppy/replay.js';
17
- export { installPoppySlots, POPPY_AUTHENTICATE_SLOT, poppyAuth, poppyOf, verifyPoppyRequest, writePoppyAuthError, } from './src/agents/poppy/resource.js';
18
- export { isBlockedAddress, SafeFetchError, safeFetchJson, } from './src/agents/poppy/safe_fetch.js';
19
- export { poppyWebSession, poppyWebSessionOf, } from './src/agents/poppy/web_session.js';
20
13
  export { pact, pactProtocol } from './src/agents/protocol.js';
14
+ export { personalAgentExtensionRuntime, } from './src/agents/runtime.js';
21
15
  export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
22
16
  export { authorizeByToken } from './src/console_authorize.js';
23
17
  export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
@@ -39,6 +33,7 @@ export { AccountExportService } from './src/host/account_export_service.js';
39
33
  */
40
34
  export { accountPath, accountPrefix, joinAccountPath, } from './src/host/account_paths.js';
41
35
  export { ACCOUNT_SESSION_KEY } from './src/host/account_session_key.js';
36
+ export { signInAccountSession, signOutAccountSession, } from './src/host/account_session_sign_in.js';
42
37
  // Organizations (multi-tenancy)
43
38
  export { ACTIVE_ORG_COOKIE, ACTIVE_ORG_COOKIE_TTL, decodeActiveOrgCookie, encodeActiveOrgCookie, readActiveOrgFromKoaCtx, } from './src/host/active_org_cookie.js';
44
39
  export { AdminOrgsService } from './src/host/admin_api/admin_orgs_service.js';
@@ -65,6 +60,7 @@ export { consoleLoginUrl, getAccountId, hasAccountSession, realAccountId, } from
65
60
  export { authkitCsrfExceptions } from './src/host/csrf.js';
66
61
  export { authenticateCustomLogin, beginCustomLogin, completeCustomLogin, } from './src/host/custom_login.js';
67
62
  export { beginCustomMfa, customMfaViewProps, verifyCustomMfa } from './src/host/custom_mfa.js';
63
+ export { sendAuthkitCodeEmail } from './src/host/default_mailer.js';
68
64
  export { normalizeEmailIdentifier } from './src/host/email_identifier.js';
69
65
  export { GEO_RESOLVE_TIMEOUT_MS, resolveGeoSafe } from './src/host/geo.js';
70
66
  export { BUILTIN_MESSAGES, DEFAULT_LOCALE, DEFAULT_MESSAGES, PT_BR_MESSAGES, resolveMessages, translate, } from './src/host/i18n.js';
@@ -89,7 +85,6 @@ export { OidcRpGuard, oidcRpGuard } from './src/host/oidc_rp_guard.js';
89
85
  // Login por OTP (código digitável): config + helpers puros.
90
86
  export { evaluateLoginOtp, generateOtpCode, OTP_LOGIN_DEFAULTS, resolveOtpLoginConfig, } from './src/host/otp_login.js';
91
87
  export { endRpSession } from './src/host/persistent_rp_session.js';
92
- export { POPPY_WEB_SESSION_KEY } from './src/host/poppy_session_key.js';
93
88
  export { createAuthThrottles } from './src/host/rate_limit.js';
94
89
  export { registerAuthHost } from './src/host/register_auth_host.js';
95
90
  export { edgeRenderer } from './src/host/renderers/edge_renderer.js';
@@ -140,5 +135,6 @@ export { generatePatToken, hashPatToken } from './src/pat/pat_tokens.js';
140
135
  export { OidcService } from './src/provider/oidc_service.js';
141
136
  export { checkClientRegistration, classifyRedirect, RegistrationPolicyError, } from './src/provider/registration_policy.js';
142
137
  export { registerOidcRoutes } from './src/register_routes.js';
143
- export { ensureAuthkitSchema } from './src/schema/ensure.js';
138
+ export { ensureAuthkitSchema, ensureAuthkitTables } from './src/schema/ensure.js';
139
+ export { AuthkitTenantVerifier, authkitTenantVerifier, } from './src/service_tenants/tenant_verifier.js';
144
140
  export { stubsRoot } from './stubs/main.js';
@@ -134,8 +134,8 @@ export default class AuthkitServerProvider {
134
134
  personalAgents: config.personalAgents
135
135
  ? {
136
136
  prefix: config.personalAgents.prefix,
137
- ...(config.personalAgents.poppy
138
- ? { poppyPrefix: config.personalAgents.poppy.prefix }
137
+ ...(config.personalAgents.extensions?.length
138
+ ? { extensions: config.personalAgents.extensions }
139
139
  : {}),
140
140
  }
141
141
  : undefined,
@@ -154,12 +154,9 @@ export default class AuthkitServerProvider {
154
154
  const logger = await this.app.container.make('logger').catch(() => null);
155
155
  warnAdminConsoleUnauthorized(logger);
156
156
  }
157
- // Poppy: o slot global que o `@adonis-agora/agent` usa para autenticar o endpoint de
158
- // conversas (e o MCP) sem importar este pacote — o contrato é o símbolo.
159
- if (config.personalAgents?.poppy) {
160
- const { installPoppySlots } = await import('../src/agents/poppy/resource.js');
161
- const { poppyUrls } = await import('../src/agents/poppy/service.js');
162
- installPoppySlots(poppyUrls(config.issuer, config.personalAgents.poppy.prefix).issuer);
157
+ // `personalAgents.extensions`: o boot de cada uma (slots globais, etc.).
158
+ for (const extension of config.personalAgents?.extensions ?? []) {
159
+ await extension.boot?.();
163
160
  }
164
161
  // Auto-montagem das rotas (`config.routes`). Chama a MESMA função exportada que o
165
162
  // `start/routes.ts` chamaria; não há segunda implementação. "As rotas não subiram" não pode
@@ -268,6 +265,7 @@ export default class AuthkitServerProvider {
268
265
  const report = await ensureAuthkitSchema(db, {
269
266
  connection: config.schema.connection,
270
267
  accountTable: config.accountStore?.accountTable,
268
+ tables: config.personalAgents?.extensions?.flatMap((e) => e.tables ?? []),
271
269
  });
272
270
  const logger = await this.app.container.make('logger').catch(() => null);
273
271
  if (report.created.length > 0) {
@@ -12,7 +12,7 @@
12
12
  * recibos) não depende de protocolo; o formato do fio vem do adapter em
13
13
  * `protocol` (default: PACT — https://openpactprotocol.org). Ver `protocol.ts`.
14
14
  */
15
- import { type PoppyConfigInput, type ResolvedPoppyConfig } from './poppy/config.js';
15
+ import { type PersonalAgentExtension, type ResolvedPersonalAgentExtension } from './extension.js';
16
16
  import { type BuiltinProtocolId, type PersonalAgentProtocol } from './protocol.js';
17
17
  /** Registro de um personal agent conhecido (PACT §3.1). */
18
18
  export interface PersonalAgentRegistration {
@@ -58,8 +58,8 @@ export interface PersonalAgentsConfigInput {
58
58
  /**
59
59
  * Valor que os personal agents põem no `aud` do JWT deles (PACT). Opaco e
60
60
  * atribuído por ESTE app no registro do agente — um valor por app, não
61
- * derivado de URL. Liga o PACT; obrigatório, a não ser num app só-Poppy
62
- * (`poppy` sem `audience`).
61
+ * derivado de URL. Liga o PACT; obrigatório, a não ser num app que só usa
62
+ * `extensions` (sem `audience`).
63
63
  */
64
64
  audience?: string;
65
65
  /**
@@ -79,14 +79,10 @@ export interface PersonalAgentsConfigInput {
79
79
  /** Prefixo das rotas (`{prefix}/oauth/*`, `{prefix}/consent`). Default: `/agents`. */
80
80
  prefix?: string;
81
81
  /**
82
- * Personal Agent Protocol ("Poppy", https://personalagentprotocol.org) — o
83
- * segundo protocolo, ao lado do PACT. Um app pode servir os dois. Ver
84
- * `poppy/config.ts`.
85
- *
86
- * @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
87
- * de forma incompatível fora de majors enquanto ela for draft.
82
+ * Outros protocolos de personal agents, de pacotes à parte, ao lado do PACT
83
+ * (ex.: `poppy()` de `@adonis-agora/authkit-poppy`). Ver {@link PersonalAgentExtension}.
88
84
  */
89
- poppy?: PoppyConfigInput;
85
+ extensions?: PersonalAgentExtension[];
90
86
  }
91
87
  export interface ResolvedPersonalAgentDelegationConfig {
92
88
  interfaceUrl: string;
@@ -108,11 +104,11 @@ export interface ResolvedPersonalAgentsConfig {
108
104
  open: boolean;
109
105
  delegation?: ResolvedPersonalAgentDelegationConfig;
110
106
  prefix: string;
111
- /** Poppy resolvido (undefined = desligado). */
112
- poppy?: ResolvedPoppyConfig;
107
+ /** `extensions` resolvidas, na ordem do config. */
108
+ extensions: ResolvedPersonalAgentExtension[];
113
109
  }
114
110
  export declare function normalizePersonalAgentsPrefix(prefix: string | undefined): string;
115
- export declare function resolvePersonalAgentsConfig(input: PersonalAgentsConfigInput | undefined): ResolvedPersonalAgentsConfig | undefined;
111
+ export declare function resolvePersonalAgentsConfig(input: PersonalAgentsConfigInput | undefined, issuer?: string): ResolvedPersonalAgentsConfig | undefined;
116
112
  /** `"a b c"` → `['a','b','c']` sem duplicatas, na ordem. */
117
113
  export declare function parseScope(value: string | null | undefined): string[];
118
114
  export declare function formatScope(scopes: Iterable<string>): string;
@@ -12,7 +12,7 @@
12
12
  * recibos) não depende de protocolo; o formato do fio vem do adapter em
13
13
  * `protocol` (default: PACT — https://openpactprotocol.org). Ver `protocol.ts`.
14
14
  */
15
- import { resolvePoppyConfig, } from './poppy/config.js';
15
+ import { resolvePersonalAgentExtensions, } from './extension.js';
16
16
  import { BUILTIN_PROTOCOLS, } from './protocol.js';
17
17
  const SCOPE_ID = /^[\x21\x23-\x5B\x5D-\x7E]+$/; // RFC 6749 §3.3 scope-token
18
18
  function assertUrl(value, what) {
@@ -37,19 +37,20 @@ export function normalizePersonalAgentsPrefix(prefix) {
37
37
  return '/agents';
38
38
  return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
39
39
  }
40
- export function resolvePersonalAgentsConfig(input) {
40
+ export function resolvePersonalAgentsConfig(input, issuer = '') {
41
41
  if (!input)
42
42
  return undefined;
43
+ // 0.x → 1.0: o Poppy virou o pacote `@adonis-agora/authkit-poppy`.
44
+ if ('poppy' in input) {
45
+ throw new Error('authkit: `personalAgents.poppy` saiu do authkit-server — instale `@adonis-agora/authkit-poppy` e use `personalAgents.extensions: [poppy({ ... })]`.');
46
+ }
43
47
  const pact = !!input.audience?.trim();
44
- if (!pact && !input.poppy) {
45
- throw new Error('authkit: personalAgents.audience é obrigatório (o `aud` dos JWTs dos agentes PACT) — ou configure só `personalAgents.poppy`.');
48
+ if (!pact && !input.extensions?.length) {
49
+ throw new Error('authkit: personalAgents.audience é obrigatório (o `aud` dos JWTs dos agentes PACT) — ou configure só `personalAgents.extensions`.');
46
50
  }
47
51
  if (!pact && input.delegation) {
48
52
  throw new Error('authkit: personalAgents.delegation é do PACT e exige `personalAgents.audience`.');
49
53
  }
50
- if (input.protocol === 'poppy') {
51
- throw new Error('authkit: o Poppy não é um `protocol` do PACT — configure-o em `personalAgents.poppy` (os dois convivem).');
52
- }
53
54
  let resolveAgent;
54
55
  let staticAgents = null;
55
56
  if (typeof input.agents === 'function') {
@@ -94,9 +95,14 @@ export function resolvePersonalAgentsConfig(input) {
94
95
  throw new Error(`authkit: personalAgents.protocol "${String(input.protocol)}" desconhecido (embutidos: ${Object.keys(BUILTIN_PROTOCOLS).join(', ')}).`);
95
96
  }
96
97
  const prefix = normalizePersonalAgentsPrefix(input.prefix);
97
- const poppy = resolvePoppyConfig(input.poppy, input.delegation?.scopes);
98
- if (poppy && pact && (poppy.prefix === prefix || poppy.prefix.startsWith(`${prefix}/`))) {
99
- throw new Error(`authkit: personalAgents.poppy.prefix "${poppy.prefix}" não pode ficar debaixo de personalAgents.prefix ("${prefix}").`);
98
+ const extensions = resolvePersonalAgentExtensions(input.extensions, {
99
+ issuer,
100
+ delegationScopes: input.delegation?.scopes ? { ...input.delegation.scopes } : null,
101
+ });
102
+ for (const extension of extensions) {
103
+ if (pact && (extension.prefix === prefix || extension.prefix.startsWith(`${prefix}/`))) {
104
+ throw new Error(`authkit: o prefixo "${extension.prefix}" de personalAgents.extensions "${extension.id}" não pode ficar debaixo de personalAgents.prefix ("${prefix}").`);
105
+ }
100
106
  }
101
107
  return {
102
108
  pact,
@@ -107,7 +113,7 @@ export function resolvePersonalAgentsConfig(input) {
107
113
  open: input.open === true,
108
114
  delegation,
109
115
  prefix,
110
- poppy,
116
+ extensions,
111
117
  };
112
118
  }
113
119
  /** `"a b c"` → `['a','b','c']` sem duplicatas, na ordem. */
@@ -31,11 +31,11 @@ function newUserCode() {
31
31
  return `${code.slice(0, 4)}-${code.slice(4)}`;
32
32
  }
33
33
  /**
34
- * A tabela de grants é compartilhada com o Poppy (refresh tokens, `pgrant_`):
35
- * o PACT só enxerga os dele.
34
+ * A tabela de grants é compartilhada com as `personalAgents.extensions` (cada uma com o seu
35
+ * prefixo de id): o PACT só enxerga os dele, `agrant_`.
36
36
  */
37
37
  function isPactGrant(id) {
38
- return !id.startsWith('pgrant_');
38
+ return id.startsWith('agrant_');
39
39
  }
40
40
  /** Aceita o código como o usuário digitar: minúsculas, sem hífen, com espaços. */
41
41
  export function normalizeUserCode(input) {
@@ -38,7 +38,8 @@ export interface GrantRow {
38
38
  updatedAt: Date;
39
39
  }
40
40
  export interface LiveGrantFilter {
41
- protocol?: 'pact' | 'poppy';
41
+ /** Só os grants com este prefixo de id (`agrant_` = PACT; o `grantIdPrefix` de uma extension). */
42
+ idPrefix?: string;
42
43
  clientId?: string;
43
44
  accountId?: string;
44
45
  }
@@ -88,7 +89,7 @@ export declare class DelegationStore {
88
89
  }): Promise<GrantRow[]>;
89
90
  countLiveGrants(now: Date, filter?: LiveGrantFilter): Promise<number>;
90
91
  /** Conexões vivas de um protocolo por agente: `client_id` → número de grants. */
91
- countLiveGrantsByClient(now: Date, protocol: 'pact' | 'poppy'): Promise<Map<string, number>>;
92
+ countLiveGrantsByClient(now: Date, idPrefix: string): Promise<Map<string, number>>;
92
93
  /** Ids dos grants não revogados de um agente (vivos ou não) — para revogar todos. */
93
94
  unrevokedGrantIdsOfClient(clientId: string): Promise<string[]>;
94
95
  /** Revoga um grant sem checar a conta — reação a reuso de refresh token. */
@@ -186,12 +186,13 @@ export class DelegationStore {
186
186
  // ─── console admin (todas as contas) ──────────────────────────────────────
187
187
  /**
188
188
  * Grants vivos (não revogados nem expirados em `now`), de todas as contas. O
189
- * protocolo sai do prefixo do id: `agrant_` (PACT) ou `pgrant_` (Poppy).
189
+ * protocolo sai do prefixo do id: `agrant_` (PACT) ou o `grantIdPrefix` de uma extension.
190
190
  */
191
191
  #live(now, filter = {}) {
192
192
  let q = this.conn().from(GRANT_TABLE).whereNull('revoked_at').where('expires_at', '>', now);
193
- if (filter.protocol)
194
- q = q.where('id', 'like', filter.protocol === 'poppy' ? 'pgrant_%' : 'agrant_%');
193
+ // O prefixo é `[a-z0-9]+_`: o `_` do LIKE (um caractere qualquer) casa com ele mesmo.
194
+ if (filter.idPrefix)
195
+ q = q.where('id', 'like', `${filter.idPrefix}%`);
195
196
  if (filter.clientId)
196
197
  q = q.where('client_id', filter.clientId);
197
198
  if (filter.accountId)
@@ -211,8 +212,8 @@ export class DelegationStore {
211
212
  return Number(row?.total ?? 0);
212
213
  }
213
214
  /** Conexões vivas de um protocolo por agente: `client_id` → número de grants. */
214
- async countLiveGrantsByClient(now, protocol) {
215
- const rows = await this.#live(now, { protocol })
215
+ async countLiveGrantsByClient(now, idPrefix) {
216
+ const rows = await this.#live(now, { idPrefix })
216
217
  .select('client_id')
217
218
  .count('* as total')
218
219
  .groupBy('client_id');