# VimineServer

> Referência da classe VimineServer do @vimine/sdk/server para clientes confidenciais.

URL: https://developers.vimine.network/pt/sdk/server/

```js
import { VimineServer } from '@vimine/sdk/server';
const vimineServer = new VimineServer({ clientId: 'vmc_…', clientSecret: process.env.VIMINE_SECRET });
```

Para os sistemas **da própria** associação: um cliente confidencial que se autentica com `client_credentials`,
lê o status das carteirinhas e opera o seu sandbox. Node ≥ 18. **O segredo nunca deve chegar a um navegador.**

## Opções

| Opção | Tipo | Padrão | |
|---|---|---|---|
| `clientId` | `string` | — | obrigatório |
| `clientSecret` | `string` | — | obrigatório; `vms_…` ou `vms_test_…` |
| `scopes` | `Scope[]` | todos os registrados | um subconjunto a pedir |
| `apiUrl` | `string` | `https://api.vimine.network` | |
| `fetch` | `typeof fetch` | `globalThis.fetch` | |

## Métodos

### `token()`

Um access token de cliente (`client_credentials`, HTTP Basic), guardado em cache até 30 segundos antes de vencer (1 hora);
uma única requisição mesmo com chamadas concorrentes.

### `request(path, init?)`

Uma chamada autenticada com `Authorization: Bearer`; JSON na ida e na volta; erros como
[`VimineError`](https://developers.vimine.network/pt/sdk/errors/). Um `401` (credenciais rotacionadas ou revogadas) é repetido uma vez com um token novo.

### `memberships.status(id)`

Status de uma carteirinha da associação, sem dados pessoais (`memberships:read`):

```js
const s = await vimineServer.memberships.status('membership-uuid');
// { id, status: 'active', verdict: 'valid', valid_until: '2027-03-31T22:59:59.000Z', membership_type: { cod: 'ORD' } }
```

### `signup(input, opts?)`

Cria uma conta Vimine para uma pessoa (`identity:signup`): ela recebe o e-mail para confirmar o endereço e escolher
uma senha. Responde sempre `{ status: 'accepted' }` — se o endereço já tinha uma conta não é revelado
a você (o dono dele é avisado, por e-mail). `opts.idempotencyKey` (gerada quando ausente).

```js
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi', phone: '+39 …' });
```

### `enroll(input, opts?)`

Envia um pedido de adesão para uma pessoa (`enroll:write`): um endereço novo recebe uma conta e um pedido *pendente*;
o dono de uma conta existente recebe, em vez disso, um link de confirmação (nada é gravado até ele usá-lo).
`accept_statuto` (a versão em vigor) é obrigatório; `privacy_notice` também, quando a associação
publica um aviso aos seus associados (`association(slug).privacy_notice`): a pessoa o lê no seu site e você passa
a versão mostrada. Veja [Integrações de servidor](https://developers.vimine.network/pt/guides/server/#fazer-a-adesão-de-associados-pelo-seu-sistema).

A pessoa é identificada por `codicefiscale` **ou** por `dob` + `birthplace` + `birth_country` — nunca por nenhum dos
dois (`422`, uma entrada `required` para cada dado de nascimento que falta). Um código que não confere com os dados de
nascimento é uma entrada `codicefiscale_mismatch` em `err.errors`, com `mismatches`, `hints` e `confirmable`: quando
`confirmable` é `true` e a pessoa confirma, repita com `codicefiscale_confirmed: true`. `address` (`MemberAddress`) quando
a associação coleta o endereço dos seus associados (`aps.member_address`). Veja
[Associados sem código fiscal](https://developers.vimine.network/pt/guides/members-without-cf/).

```js
// com código fiscal
await vimineServer.enroll({ ...person, codicefiscale: 'RSSMRA80A01H501U', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } }, { idempotencyKey: 'order-42' });
// sem código: data, local e país de nascimento
await vimineServer.enroll({ ...person, dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } });
```

### `checkins.create(token)`

Registra um check-in na entrada a partir do token lido no QR (`checkins:write`). Uma carteirinha responde `{ kind: 'card', verdict, status, membership_id, valid_until, valid_from, identity_check, checked_in_at }` — `identity_check: 'pending'` é uma observação a mostrar para quem cuida da entrada, não faz parte do `verdict` e não restringe nada ([guia](https://developers.vimine.network/pt/guides/members-without-cf/#na-entrada-a-verificação-de-identidade)); o QR de uma inscrição em evento responde `{ kind: 'registration', verdict, registration_id, event, first, membership_verdict, … }` (veja [Eventos e inscrições](https://developers.vimine.network/pt/guides/events/#na-entrada)).

### `events`

`events.list(params?)` · `events.get(slug)` — os eventos publicados da associação, incluindo os só para associados (qualquer token de cliente).

### `registrations`

| | |
|---|---|
| `registrations.listForEvent(slug, { status?, limit?, cursor? })` | as inscrições de um evento: id, status, tipo, carteirinha, check-in — sem dados pessoais (`registrations:read`, planos com listas via API) |
| `registrations.guest(slug, { email, first_name, last_name, registration_type, note? }, opts?)` | inscreve um **convidado** sem conta num evento público; sempre `{ status: 'accepted' }`; `Idempotency-Key` gerada (veja [convidados](https://developers.vimine.network/pt/guides/events/#convidados-eventos-públicos)) |

### `memberships.list(params?)`

As carteirinhas da associação (`memberships:read`, planos com listas): `{ items: [{ id, status, verdict, membership_type, issued_at, valid_until, updated_at }], next_cursor }`; `params`: `status`, `updated_since`, `limit`, `cursor`.

### `sandbox.members()` · `sandbox.reset()`

Só para clientes de teste: os associados sintéticos do [sandbox](https://developers.vimine.network/pt/guides/sandbox/) e a redefinição (nova senha
compartilhada, devolvida uma vez). Um cliente de produção recebe `403`.

### `public`

Os endpoints públicos, sem credenciais: veja [`publicApi`](https://developers.vimine.network/pt/sdk/public/).

## Um exemplo de middleware

```js title="express.js"
import express from 'express';
import { VimineServer, VimineError } from '@vimine/sdk/server';

const vimineServer = new VimineServer({ clientId: process.env.VIMINE_CLIENT_ID, clientSecret: process.env.VIMINE_SECRET });
const app = express();

app.get('/cards/:id/status', async (req, res) => {
    try {
        const { status, verdict, valid_until } = await vimineServer.memberships.status(req.params.id);
        res.json({ status, verdict, valid_until });
    } catch (err) {
        if (err instanceof VimineError && err.code === 'not_found') return res.status(404).end();
        throw err;
    }
});
```
