@authyon/server 0.2.0-beta.2 → 0.2.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@ SDK server-side para o [Authyon](https://authyon.com) — administração de amb
5
5
  ## Instalação da beta
6
6
 
7
7
  ```bash
8
- npm install --save-exact @authyon/server@0.2.0-beta.2
8
+ npm install --save-exact @authyon/server@0.2.0-beta.4
9
9
  ```
10
10
 
11
11
  Durante a beta, `npm install @authyon/server@beta` acompanha o prerelease mais recente. Fixar a versão exata é recomendado para builds reproduzíveis.
@@ -206,3 +206,168 @@ npm install
206
206
  npm run build # dist/ (ESM + CJS + .d.ts via tsup)
207
207
  npm run typecheck
208
208
  ```
209
+
210
+ ### Emitir uma credencial de integração do tenant
211
+
212
+ Requer o endpoint `POST /env/tenants/{tenantId}/credentials` no backend Authyon
213
+ e uma credencial de ambiente com `authyon:credentials:manage`.
214
+
215
+ ```ts
216
+ const credential = await authyon.environment.tenants.credentials.create(tenantId, {
217
+ description: "ERP financeiro",
218
+ permissions: ["monkeypay:transactions:read"],
219
+ });
220
+ // Entregue clientId e clientSecret ao operador: o segredo só é retornado uma vez.
221
+ ```
222
+
223
+ As permissões são explícitas e pertencem à integração; não há concessão automática de acesso total.
224
+
225
+ ## Credenciais: paginação, busca e detalhe
226
+
227
+ ```ts
228
+ const page = await authyon.environment.tenants.credentials.listPage(tenantId, {
229
+ search: "transactions",
230
+ skip: 0,
231
+ take: 25,
232
+ });
233
+ const detail = await authyon.environment.tenants.credentials.get(tenantId, credentialId);
234
+ ```
235
+
236
+ `page` contém `data`, `perPage` (número da página, começando em 1), `pageSize`,
237
+ `total`, `pages`, `hasNext` e `hasPrev`. `take` aceita 1–100 (padrão da API: 25),
238
+ `skip` é um deslocamento a partir de zero e `search` aceita até 200 caracteres.
239
+ A API pesquisa clientId, descrição e permissões antes de paginar.
240
+
241
+ O método existente `credentials.list(tenantId)` continua retornando um array:
242
+ aceita a resposta antiga e percorre todas as páginas da API atual. Prefira
243
+ `listPage` para tabelas ou grandes volumes. A leitura completa detecta páginas
244
+ sobrepostas/sem progresso e tem limite de 1.000 páginas; alterações concorrentes
245
+ podem exigir reiniciar a leitura, pois a API usa paginação por deslocamento.
246
+
247
+ O detalhe contém `permissions`, `createdBy` (`id`, `type`, `displayName`),
248
+ `createdAt`, `updatedAt`, `lastUsedAt`, `secretRotatedAt`, `revokedAt`, `isActive`,
249
+ `expiresAt`, `ageSeconds`, `lifetimeSeconds` e `accessTokenLifetimeSeconds`.
250
+ Listagem e detalhe projetam somente campos permitidos, sem segredo ou hash.
251
+ Registros antigos podem ter autor e atualização nulos. A credencial atual não
252
+ expira automaticamente: `expiresAt` é nulo; `lifetimeSeconds` é nulo enquanto
253
+ ativa e representa sua duração até a revogação quando revogada. A validade do
254
+ access token é separada (atualmente 1.800 segundos).
255
+
256
+ ## Scopes e ciclo de vida das credenciais
257
+
258
+ `scopes` é um alias de `permissions` na criação/atualização. Use somente um dos
259
+ campos, com uma lista explícita no formato `namespace:resource:action`. O SDK
260
+ normaliza espaços, caixa e duplicatas; não concede permissões automaticamente.
261
+ A API continua responsável pela autorização. O contrato antigo
262
+ `CreateTenantCredentialInput` e chamadas usando `permissions` são preservados.
263
+
264
+ ```ts
265
+ const issued = await authyon.environment.tenants.credentials.create(tenantId, {
266
+ description: "ERP financeiro",
267
+ scopes: ["monkeypay:transactions:read"],
268
+ });
269
+ // Armazene issued.clientSecret no gerenciador de segredos. Não registre a resposta.
270
+
271
+ // Token de um usuário da plataforma. Pode ser um callback assíncrono que
272
+ // consulta a sessão atual a cada operação, sem compartilhar tokens entre usuários.
273
+ const platform = authyon.platform(() => getCurrentPlatformAccessToken());
274
+ const scope = { workspaceId, environmentId, tenantId };
275
+ await platform.credentials.list(scope, { search: "ERP", skip: 0, take: 25 });
276
+ await platform.credentials.get(scope, credentialId);
277
+ await platform.credentials.create(scope, {
278
+ description: "Leitura",
279
+ permissions: ["monkeypay:transactions:read"],
280
+ });
281
+ await platform.credentials.updateScopes(scope, credentialId, ["monkeypay:transactions:read"]);
282
+ await platform.credentials.updatePermissions(scope, credentialId, {
283
+ permissions: ["monkeypay:transactions:read"],
284
+ });
285
+ const rotated = await platform.credentials.rotate(scope, credentialId);
286
+ await platform.credentials.revoke(scope, credentialId);
287
+ ```
288
+
289
+ Omita `tenantId` de `scope` para gerenciar credenciais do ambiente. Criação e
290
+ rotação retornam o segredo uma única vez. Alterar permissões substitui a lista
291
+ completa. A concessão OAuth continua recebendo apenas `clientId`/`clientSecret`;
292
+ `scopes` não é um parâmetro de redução de acesso na troca de token.
293
+
294
+ Os endpoints `/env` oferecem criação, listagem e detalhe de credenciais do
295
+ tenant. Atualização, rotação e revogação usam os endpoints `/platform` com
296
+ **token de usuário da plataforma**, sem fallback para credenciais de máquina.
297
+ Se a API exigir `auth.step_up_required`, solicite confirmação de senha na sua
298
+ aplicação e chame explicitamente `platform.auth.stepUp(currentPassword)` antes
299
+ de tentar a operação novamente. O SDK não repete mutações automaticamente.
300
+
301
+ ## Convites e remoção de acesso
302
+
303
+ ### Workspace
304
+
305
+ ```ts
306
+ const team = await platform.workspaces.team(workspaceId);
307
+ const invite = await platform.workspaces.members.invite(workspaceId, {
308
+ email: "pessoa@example.com",
309
+ role: "auditor", // ou "admin", sempre explícito
310
+ });
311
+ // invite.acceptUrl é sensível: entregue somente à pessoa convidada.
312
+ await platform.workspaces.invites.revoke(workspaceId, invite.inviteId);
313
+ await platform.workspaces.members.changeRole(workspaceId, memberId, "auditor");
314
+ await platform.workspaces.members.remove(workspaceId, memberId);
315
+ ```
316
+
317
+ `memberId` vem de `team.members`, e não é `userId`. O proprietário tem
318
+ `memberId: null`; a API protege proprietário, acesso próprio e permissões de
319
+ administração. `workspaces.invites.create` é um alias para `members.invite`.
320
+ Convites pendentes ficam em `team.pendingInvites`; revogar o convite invalida o
321
+ link. Para retirar acesso após aceite, remova o membro.
322
+
323
+ A pessoa convidada pode consultar/aceitar o convite por uma rota server-side:
324
+
325
+ ```ts
326
+ const preview = await authyon.workspaceInvites.preview(invitationToken);
327
+ await authyon.workspaceInvites.accept(invitationToken, {
328
+ name: "Pessoa",
329
+ password: registrationPassword,
330
+ });
331
+ ```
332
+
333
+ Esses métodos não enviam token de usuário nem credenciais de ambiente. Nome e
334
+ senha são necessários quando `preview.requiresRegistration` for verdadeiro;
335
+ para uma conta existente, use `accept(invitationToken)`.
336
+
337
+ ### Tenant
338
+
339
+ ```ts
340
+ const user = authyon.user(() => getCurrentUserAccessToken());
341
+ await user.tenants.members.invite(tenantId, {
342
+ email: "pessoa@example.com",
343
+ roles: ["reader"],
344
+ });
345
+ await user.tenants.members.list(tenantId, { skip: 0, take: 25 });
346
+ await user.tenants.members.remove(tenantId, userId);
347
+
348
+ // Administração por máquina: adicione uma conta existente por ID.
349
+ await authyon.environment.tenants.members.add(tenantId, userId, ["reader"]);
350
+ await authyon.environment.tenants.members.remove(tenantId, userId);
351
+ // Os métodos tenant(credentials).members.add/remove existentes continuam disponíveis.
352
+ // Administração com sessão da plataforma:
353
+ await platform.tenants.members.add(scope, userId, ["reader"]);
354
+ await platform.tenants.members.remove(scope, userId);
355
+ ```
356
+
357
+ Configure `envKey` para `user()`. O convite de tenant associa um usuário já
358
+ cadastrado no ambiente pelo e-mail; não cria conta e não envia link por e-mail.
359
+ A API exige associação/permissões do usuário chamador. No browser, os métodos
360
+ existentes `@authyon/auth` → `organization.members.invite/remove` continuam
361
+ atendendo esse fluxo. Nunca importe `@authyon/server` no browser.
362
+
363
+ ## Compatibilidade e segurança do transporte
364
+
365
+ Os métodos anteriores permanecem disponíveis. As novas chamadas exigem os
366
+ endpoints atuais da API e a migração `ClientCredentialMetadata` para metadados
367
+ persistidos. O SDK não altera o banco nem publica uma versão automaticamente.
368
+
369
+ O adaptador Fetch agora rejeita redirects para evitar reenviar tokens/segredos;
370
+ configure a URL final HTTPS da API. Adaptadores HTTP personalizados devem manter
371
+ essa política. Os logs internos omitem corpos/headers e ocultam tokens de
372
+ convite presentes no caminho. A auditoria de operações permanece na API; o SDK
373
+ não gera eventos duplicados ao consultar listagens de auditoria.