@softize/opus 19.0.0 → 20.0.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/CHANGELOG.md +193 -0
- package/bin/cli.mjs +5 -0
- package/bin/lib/check.mjs +198 -10
- package/bin/lib/copy.mjs +29 -0
- package/bin/lib/mcp.mjs +1 -1
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +5 -0
- package/docs/adr/0024-fill-height-propagates-by-context.md +118 -0
- package/docs/data-products.md +15 -9
- package/docs/protocol.md +3 -4
- package/docs/releasing.md +2 -2
- package/package.json +2 -2
- package/registry/skills/create-opus-action/scripts/scaffold.mjs +2 -1
- package/registry/templates/app/package.json +1 -1
- package/src/core/runtime.ts +96 -8
- package/src/core/types.ts +5 -2
- package/src/ui/components/patterns/action-form-card.tsx +11 -1
- package/src/ui/components/patterns/content-header.tsx +15 -3
- package/src/ui/components/patterns/fill-region.ts +150 -0
- package/src/ui/components/patterns/list.tsx +89 -78
- package/src/ui/components/patterns/page.tsx +20 -4
- package/src/ui/components/patterns/presentation.tsx +52 -37
- package/src/ui/components/patterns/split.tsx +44 -4
- package/src/ui/components/patterns/surface-anatomy.ts +35 -8
- package/src/ui/components/patterns/trigger.tsx +12 -2
- package/src/ui/components/primitives/alert.tsx +9 -1
- package/src/ui/components/primitives/avatar.tsx +7 -3
- package/src/ui/components/primitives/carousel.tsx +34 -5
- package/src/ui/components/primitives/checkbox.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -1
- package/src/ui/components/primitives/copyable.tsx +120 -10
- package/src/ui/components/primitives/dialog.tsx +41 -10
- package/src/ui/components/primitives/drawer.tsx +9 -1
- package/src/ui/components/primitives/empty.tsx +1 -1
- package/src/ui/components/primitives/icon-picker.tsx +6 -2
- package/src/ui/components/primitives/icon-tile.tsx +7 -0
- package/src/ui/components/primitives/input-group.tsx +9 -2
- package/src/ui/components/primitives/input-otp.tsx +1 -1
- package/src/ui/components/primitives/kbd.tsx +1 -1
- package/src/ui/components/primitives/label.tsx +3 -0
- package/src/ui/components/primitives/menu.tsx +5 -0
- package/src/ui/components/primitives/popover.tsx +1 -1
- package/src/ui/components/primitives/progress.tsx +9 -1
- package/src/ui/components/primitives/slider.tsx +62 -11
- package/src/ui/components/primitives/truncate.tsx +10 -1
- package/src/ui/docs/content/accordion.md +74 -27
- package/src/ui/docs/content/action-form-card.md +24 -15
- package/src/ui/docs/content/action-form-dialog.md +17 -7
- package/src/ui/docs/content/action-form.md +92 -77
- package/src/ui/docs/content/action-list-dialog.md +75 -38
- package/src/ui/docs/content/action-list.md +134 -52
- package/src/ui/docs/content/action-trigger.md +27 -10
- package/src/ui/docs/content/action-view.md +14 -14
- package/src/ui/docs/content/actions.md +161 -66
- package/src/ui/docs/content/ai.md +43 -44
- package/src/ui/docs/content/alert.md +83 -29
- package/src/ui/docs/content/ask.md +51 -26
- package/src/ui/docs/content/aspect-ratio.md +22 -24
- package/src/ui/docs/content/audit.md +23 -19
- package/src/ui/docs/content/auth.md +38 -19
- package/src/ui/docs/content/avatar.md +54 -5
- package/src/ui/docs/content/badge.md +29 -9
- package/src/ui/docs/content/breadcrumb.md +21 -8
- package/src/ui/docs/content/button.md +73 -43
- package/src/ui/docs/content/calendar.md +134 -26
- package/src/ui/docs/content/card.md +41 -15
- package/src/ui/docs/content/carousel.md +37 -6
- package/src/ui/docs/content/chat.md +118 -37
- package/src/ui/docs/content/checkbox.md +73 -7
- package/src/ui/docs/content/cli.md +94 -55
- package/src/ui/docs/content/collapsible.md +43 -19
- package/src/ui/docs/content/command.md +30 -8
- package/src/ui/docs/content/composer.md +23 -8
- package/src/ui/docs/content/content.md +31 -7
- package/src/ui/docs/content/copyable.md +39 -8
- package/src/ui/docs/content/customization.md +55 -46
- package/src/ui/docs/content/cycle.md +33 -18
- package/src/ui/docs/content/data-products.md +115 -0
- package/src/ui/docs/content/data-state.md +20 -6
- package/src/ui/docs/content/data.md +20 -19
- package/src/ui/docs/content/detail.md +12 -5
- package/src/ui/docs/content/dialog.md +107 -24
- package/src/ui/docs/content/dictionary-value.md +4 -4
- package/src/ui/docs/content/dock.md +54 -19
- package/src/ui/docs/content/dot.md +35 -5
- package/src/ui/docs/content/drawer.md +63 -19
- package/src/ui/docs/content/empty-value.md +20 -6
- package/src/ui/docs/content/empty.md +24 -3
- package/src/ui/docs/content/events.md +76 -16
- package/src/ui/docs/content/executions.md +9 -9
- package/src/ui/docs/content/field.md +21 -6
- package/src/ui/docs/content/getting-started.md +44 -34
- package/src/ui/docs/content/icon-picker.md +19 -13
- package/src/ui/docs/content/icon-tile.md +28 -5
- package/src/ui/docs/content/input-otp.md +58 -7
- package/src/ui/docs/content/input.md +22 -3
- package/src/ui/docs/content/item.md +53 -6
- package/src/ui/docs/content/kbd.md +5 -1
- package/src/ui/docs/content/label.md +13 -4
- package/src/ui/docs/content/log.md +5 -5
- package/src/ui/docs/content/markdown.md +5 -4
- package/src/ui/docs/content/mcp.md +49 -23
- package/src/ui/docs/content/menu.md +95 -10
- package/src/ui/docs/content/metric-card.md +12 -4
- package/src/ui/docs/content/observability.md +10 -9
- package/src/ui/docs/content/page.md +118 -12
- package/src/ui/docs/content/pagination.md +13 -5
- package/src/ui/docs/content/pane.md +55 -5
- package/src/ui/docs/content/popover.md +42 -5
- package/src/ui/docs/content/presentation.md +91 -47
- package/src/ui/docs/content/progress.md +27 -14
- package/src/ui/docs/content/queue.md +39 -21
- package/src/ui/docs/content/radio-group.md +26 -4
- package/src/ui/docs/content/router.md +29 -10
- package/src/ui/docs/content/runtime.md +90 -54
- package/src/ui/docs/content/scheduler.md +53 -21
- package/src/ui/docs/content/scroll-area.md +42 -35
- package/src/ui/docs/content/select.md +78 -33
- package/src/ui/docs/content/semantic-context.md +21 -2
- package/src/ui/docs/content/separator.md +15 -9
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +6 -1
- package/src/ui/docs/content/slider.md +37 -9
- package/src/ui/docs/content/spinner.md +4 -3
- package/src/ui/docs/content/split.md +19 -0
- package/src/ui/docs/content/storage.md +8 -9
- package/src/ui/docs/content/switch.md +10 -7
- package/src/ui/docs/content/table.md +46 -8
- package/src/ui/docs/content/tabs.md +14 -4
- package/src/ui/docs/content/testing.md +76 -31
- package/src/ui/docs/content/textarea.md +5 -4
- package/src/ui/docs/content/toast.md +48 -7
- package/src/ui/docs/content/toggle.md +3 -3
- package/src/ui/docs/content/tokens.md +15 -26
- package/src/ui/docs/content/tooltip.md +18 -2
- package/src/ui/docs/content/truncate.md +36 -6
- package/src/ui/docs/content/ui.md +74 -22
- package/src/ui/docs/content/upgrading.md +45 -36
- package/src/ui/docs/plugin.ts +36 -2
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/drivers/react.tsx +16 -8
- package/src/ui/meta.ts +31 -31
- package/src/vite/design.ts +16 -4
|
@@ -4,94 +4,130 @@ title: Runtime & adapters
|
|
|
4
4
|
|
|
5
5
|
# Runtime & adapters
|
|
6
6
|
|
|
7
|
-
O
|
|
8
|
-
|
|
9
|
-
o runtime
|
|
7
|
+
O runtime executa as actions registradas e entrega a elas as capacidades que o app configurou:
|
|
8
|
+
servidor HTTP, banco, autenticação, auditoria e as demais. Cada capacidade é um adapter opcional.
|
|
9
|
+
O app monta o runtime com as peças de que precisa, e o Opus não assume o controle do restante da
|
|
10
|
+
aplicação.
|
|
10
11
|
|
|
11
12
|
## O modelo
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Todo adapter declara `name` e `kind`. `init`, `dispose` e `healthCheck` são opcionais e acompanham o
|
|
15
|
+
ciclo de vida do runtime: `start()` inicializa os adapters, `dispose()` os desliga em ordem inversa
|
|
16
|
+
e `healthCheck()` reúne o estado de todos.
|
|
16
17
|
|
|
17
18
|
```ts
|
|
18
19
|
import { createRuntime } from '@softize/opus/core'
|
|
19
20
|
|
|
20
21
|
const runtime = createRuntime({
|
|
21
|
-
server: fastifyServer({ app }), //
|
|
22
|
+
server: fastifyServer({ app }), // expõe as actions como endpoints
|
|
22
23
|
data: kyselyData({ db }), // fornece ctx.db
|
|
23
|
-
auth:
|
|
24
|
-
audit: [pgAudit({ pool })], // trilha de auditoria
|
|
25
|
-
observability:
|
|
24
|
+
auth: jwtAuth({ secret, mapUser }), // resolve user, tenant e can
|
|
25
|
+
audit: [pgAudit({ pool })], // trilha de auditoria; aceita vários sinks
|
|
26
|
+
observability: openTelemetryObservability(), // span ativo e trace sem fornecedor fixo
|
|
26
27
|
storage: fsStorage({ root }), // fornece ctx.storage (experimental)
|
|
27
28
|
config: { env, i18n: { defaultLocale: 'pt-BR' } },
|
|
28
29
|
})
|
|
29
30
|
|
|
30
|
-
runtime.register([
|
|
31
|
+
runtime.register([workspaceDomain])
|
|
31
32
|
await runtime.start()
|
|
32
33
|
```
|
|
33
34
|
|
|
35
|
+
## Registrar domínios
|
|
36
|
+
|
|
37
|
+
Só o que foi registrado existe para o runtime: uma action fora do registro não é montada no servidor
|
|
38
|
+
nem pode ser executada. `runtime.register` aceita domínios criados com `defineDomain` e também
|
|
39
|
+
actions, reactions e schedules soltos, em uma mesma lista. Um domínio é achatado com seus
|
|
40
|
+
subdomínios; um nome repetido de action, reaction, schedule ou Produto de Dados lança erro, inclusive
|
|
41
|
+
entre domínios registrados separadamente.
|
|
42
|
+
|
|
43
|
+
O `start()` falha quando há reactions registradas sem `eventBus` (`runtime.eventbus_required`) ou
|
|
44
|
+
schedules sem `scheduler` (`runtime.scheduler_required`). A declaração de um domínio está em
|
|
45
|
+
[Actions & contratos](/docs/actions).
|
|
46
|
+
|
|
34
47
|
## As capacidades
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
Cada driver fica num subpath próprio do pacote. Drivers que dependem de bibliotecas maiores as
|
|
50
|
+
declaram como dependências opcionais: só quem usa o driver as instala.
|
|
38
51
|
|
|
39
52
|
| Capacidade | Fornece | Driver pronto |
|
|
40
53
|
|---|---|---|
|
|
41
|
-
| `server` |
|
|
42
|
-
| `data` | `ctx.db
|
|
43
|
-
| `auth` | `user
|
|
54
|
+
| `server` | expõe as actions por HTTP | `fastifyServer` — `@softize/opus/server/fastify` · `nodeServer` — `…/server/node` |
|
|
55
|
+
| `data` | `ctx.db`, verificação de drift e CRUD | `kyselyData`, `kyselyRepo`, `crudActions` — `@softize/opus/data/kysely` |
|
|
56
|
+
| `auth` | `user`, `tenantId` e `can` do contexto | `jwtAuth` — `…/auth/jwt` · `betterAuthSession` — `…/auth/better-auth` |
|
|
44
57
|
| `audit` | trilha por execução de action | `pgAudit` — `…/audit/pg` · `consoleAudit` — `…/audit/console` |
|
|
45
58
|
| `logger` | `ctx.log` estruturado | `pinoLogger` — `@softize/opus/log/pino` |
|
|
46
|
-
| `observability` | span ativo
|
|
47
|
-
| `eventBus` | `ctx.emit`
|
|
59
|
+
| `observability` | span ativo e propagação de trace | `openTelemetryObservability` — `@softize/opus/observability/opentelemetry` |
|
|
60
|
+
| `eventBus` | `ctx.emit` e reactions | `mittEvents` — `@softize/opus/events/mitt` |
|
|
48
61
|
| `queue` | jobs em background | `bullmqQueue` — `@softize/opus/queue/bullmq` |
|
|
49
|
-
| `scheduler` |
|
|
50
|
-
| `storage` | `ctx.storage`
|
|
51
|
-
| `cache` | `ctx.cache`
|
|
52
|
-
| `ai` | `ctx.ai`
|
|
53
|
-
| `client` | chamar actions de fora
|
|
62
|
+
| `scheduler` | schedules por cron ou intervalo | `nodeCronScheduler` — `@softize/opus/scheduler/node-cron` |
|
|
63
|
+
| `storage` | `ctx.storage` para arquivos | `fsStorage` — `…/storage/fs` · `s3Storage` — `…/storage/s3` |
|
|
64
|
+
| `cache` | `ctx.cache` de leitura (experimental) | `memoryCache` — `@softize/opus/cache/memory` |
|
|
65
|
+
| `ai` | `ctx.ai`: `complete`, `extract`, `run` e `runStream` | `anthropicAi` — `@softize/opus/ai/anthropic` |
|
|
66
|
+
| `client` | chamar actions de fora do servidor | `fetchClient` — `@softize/opus/client/fetch` |
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
`fastifyServer` devolve o adapter diretamente. `nodeServer` devolve `{ adapter, handler, hasRoute }`:
|
|
69
|
+
passe `adapter` ao runtime e ligue `handler` a um servidor `node:http`, ao Vite ou a um middleware no
|
|
70
|
+
estilo connect.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { createServer } from 'node:http'
|
|
74
|
+
import { nodeServer } from '@softize/opus/server/node'
|
|
75
|
+
|
|
76
|
+
const node = nodeServer()
|
|
77
|
+
const runtime = createRuntime({ server: node.adapter })
|
|
78
|
+
createServer(node.handler).listen(3000)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Fora do runtime, o harness de teste (`runAction` e `testContext`, de `@softize/opus/testing`) executa
|
|
82
|
+
uma action em unidade com as etapas centrais do `execute`: valida a entrada, exige autenticação
|
|
83
|
+
quando a action não é pública, avalia o `authorize`, roda o handler e valida a saída. Ele não roda os
|
|
84
|
+
`loads` (os dados carregados entram pela opção `loaded`) nem grava audit. Veja
|
|
85
|
+
[Testes de action](/docs/testing).
|
|
58
86
|
|
|
59
87
|
## O contexto do handler
|
|
60
88
|
|
|
61
|
-
|
|
62
|
-
|
|
89
|
+
O `ctx` recebido pelo handler reúne o que os adapters fornecem. Sem o adapter correspondente, o
|
|
90
|
+
campo chega como `null`, ou como `undefined` no caso de `db`, e o handler decide como seguir.
|
|
91
|
+
|
|
92
|
+
- `user`, `tenantId` e `can`, do adapter `auth`.
|
|
93
|
+
- `db`, do adapter `data`.
|
|
94
|
+
- `log`, do `logger`; sem ele, o runtime usa um logger de console.
|
|
95
|
+
- `emit`, que publica no `eventBus`.
|
|
96
|
+
- `storage`, `cache` e `ai`, dos adapters homônimos.
|
|
97
|
+
- `provenance`, que identifica a origem da execução: HTTP, schedule, reaction, job, agente de IA ou
|
|
98
|
+
integração.
|
|
99
|
+
- `trace`, quando há contexto de trace.
|
|
100
|
+
- `meta`, com dados livres da chamada.
|
|
63
101
|
|
|
64
|
-
|
|
65
|
-
`storage` (storage) · `cache` (cache) · `ai` (ai) · `provenance` (quem disparou: http, schedule,
|
|
66
|
-
reaction…) · `trace` (quando configurado) · `meta`.
|
|
102
|
+
## Trace e observabilidade
|
|
67
103
|
|
|
68
|
-
O core não depende de OpenTelemetry. O `ObservabilityAdapter` envolve actions e reactions
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
104
|
+
O core não depende de OpenTelemetry. O `ObservabilityAdapter` envolve actions e reactions com
|
|
105
|
+
`runInSpan`, e o `TraceContext` efetivo segue para o resultado, o audit e os eventos. Um job recebe
|
|
106
|
+
o trace da execução que o enfileirou, e `executeJob()` cria a execução filha no worker sem
|
|
107
|
+
enfileirar a action de novo. Uma falha de instrumentação é tratada de forma tolerante e nunca
|
|
108
|
+
executa o handler outra vez.
|
|
73
109
|
|
|
74
|
-
O core não
|
|
75
|
-
`
|
|
76
|
-
|
|
77
|
-
`
|
|
110
|
+
O core não lê headers HTTP. Os drivers Fastify e Node preenchem `ContextBase.trace` com a opção
|
|
111
|
+
`traceContext: 'w3c'`, desativada por padrão; outros transportes continuam responsáveis pela própria
|
|
112
|
+
fronteira. O registro de audit traz dois campos: `traceContext`, com o contexto de trace (`traceId`, `spanId` e flags), e `trace`, com o
|
|
113
|
+
`requestId` e a action de origem (`parentActionId`). Os detalhes estão em [Observabilidade](/docs/observability).
|
|
78
114
|
|
|
79
|
-
Para actions,
|
|
80
|
-
|
|
81
|
-
representa span de erro. Reactions usam `resultKind: 'void'` e rejeitam em falha.
|
|
115
|
+
Para actions, a execução observada resolve com `ActionResult` e declara `resultKind:
|
|
116
|
+
'action-result'`: o driver inspeciona `result.ok`, e uma Promise resolvida com `ok: false` ainda
|
|
117
|
+
representa um span de erro. Reactions usam `resultKind: 'void'` e rejeitam em caso de falha.
|
|
82
118
|
|
|
83
|
-
##
|
|
119
|
+
## Execução sem requisição
|
|
84
120
|
|
|
85
|
-
|
|
86
|
-
|
|
121
|
+
Duas formas de código rodam sem uma requisição: um evento de domínio dispara uma
|
|
122
|
+
[reaction](/docs/events), e o tempo dispara um [schedule](/docs/scheduler), que executa uma action
|
|
123
|
+
com provenance própria. Ambos são registrados junto com as actions, e o manifest projeta os três.
|
|
87
124
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
`opus introspect` lista reactions, schedules e as ligações entre eles, mas só reconhece
|
|
126
|
+
declarações feitas com `defineAction`, `defineReaction` e `defineSchedule`. Actions do par
|
|
127
|
+
`defineContract` e `bindAction` e reactions do par `defineReactionContract` e `bindReaction` ficam de
|
|
128
|
+
fora do modelo que ele monta.
|
|
92
129
|
|
|
93
|
-
## Referência
|
|
130
|
+
## Referência completa
|
|
94
131
|
|
|
95
|
-
O contrato completo
|
|
96
|
-
|
|
97
|
-
que você instalou.
|
|
132
|
+
O contrato completo, com tipos, garantias, ordem de execução e erros, está em `docs/protocol.md`,
|
|
133
|
+
dentro do pacote instalado. Como o changelog, ele acompanha a versão que o projeto usa.
|
|
@@ -4,62 +4,94 @@ title: Agendador
|
|
|
4
4
|
|
|
5
5
|
# Agendador
|
|
6
6
|
|
|
7
|
-
Use um schedule para executar uma action por cron ou
|
|
8
|
-
agendamento e o runtime executa a action com provenance `schedule`,
|
|
7
|
+
Use um schedule para executar uma action por cron ou em intervalos, sem uma requisição. O
|
|
8
|
+
`SchedulerAdapter` registra o agendamento, e o runtime executa a action com provenance `schedule`,
|
|
9
|
+
que aparece no audit e no contexto do handler.
|
|
9
10
|
|
|
10
11
|
## O contrato
|
|
11
12
|
|
|
12
13
|
```ts
|
|
13
|
-
interface SchedulerAdapter {
|
|
14
|
+
interface SchedulerAdapter extends Adapter {
|
|
15
|
+
name: string // herdado de Adapter; identifica o driver
|
|
16
|
+
kind: 'scheduler'
|
|
14
17
|
register(spec: ScheduleDef, fire: () => Promise<void> | void): Unsubscribe
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
interface ScheduleDef {
|
|
18
21
|
name: string
|
|
19
|
-
action: string // action
|
|
20
|
-
cron?: string // '0 9 * * *' (
|
|
21
|
-
every?: string // '
|
|
22
|
-
timezone?: string // IANA,
|
|
23
|
-
input?: unknown | (() => unknown | Promise<unknown>) //
|
|
24
|
-
enabled?: boolean
|
|
22
|
+
action: string // action registrada, executada a cada disparo
|
|
23
|
+
cron?: string // '0 9 * * *' (todo dia às 9h)
|
|
24
|
+
every?: string // '15s', '5m', '1h', '1d': atalho de intervalo
|
|
25
|
+
timezone?: string // IANA, como 'America/Sao_Paulo'; sem ela, vale a hora local do processo
|
|
26
|
+
input?: unknown | (() => unknown | Promise<unknown>) // fixo ou calculado a cada disparo
|
|
27
|
+
enabled?: boolean // padrão true
|
|
28
|
+
description?: string
|
|
29
|
+
tags?: string[]
|
|
25
30
|
}
|
|
26
31
|
```
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
Declare `cron` ou `every`, não os dois. `every` aceita segundos e minutos até 59, horas até 23 e
|
|
34
|
+
somente `1d` para dias; intervalos maiores usam `cron`. Sem `input`, a action recebe `{}`.
|
|
30
35
|
|
|
31
36
|
## Driver
|
|
32
37
|
|
|
33
38
|
```ts
|
|
34
39
|
import { nodeCronScheduler } from '@softize/opus/scheduler/node-cron'
|
|
35
40
|
|
|
36
|
-
const scheduler = nodeCronScheduler()
|
|
41
|
+
const scheduler = nodeCronScheduler() // no mesmo processo do runtime
|
|
37
42
|
```
|
|
38
43
|
|
|
39
|
-
##
|
|
44
|
+
## Declarar no domínio
|
|
45
|
+
|
|
46
|
+
Declare o schedule com `defineSchedule` e registre-o no domínio, ao lado da action que ele executa:
|
|
40
47
|
|
|
41
48
|
```ts
|
|
42
|
-
import { defineSchedule } from '@softize/opus/core'
|
|
49
|
+
import { createRuntime, defineDomain, defineSchedule } from '@softize/opus/core'
|
|
50
|
+
import { caixaFechar } from './caixa-fechar.ts' // a action 'caixa.fechar', definida com bindAction
|
|
43
51
|
|
|
44
|
-
// Declarado no domínio, junto das actions:
|
|
45
52
|
const fecharDia = defineSchedule({
|
|
46
|
-
name: 'fechar-dia',
|
|
53
|
+
name: 'caixa.fechar-dia',
|
|
47
54
|
action: 'caixa.fechar',
|
|
48
55
|
cron: '0 23 * * *',
|
|
49
56
|
timezone: 'America/Sao_Paulo',
|
|
50
57
|
})
|
|
51
58
|
|
|
59
|
+
export const caixaDomain = defineDomain({
|
|
60
|
+
name: 'caixa',
|
|
61
|
+
actions: { caixaFechar },
|
|
62
|
+
schedules: [fecharDia],
|
|
63
|
+
})
|
|
64
|
+
|
|
52
65
|
const runtime = createRuntime({
|
|
53
66
|
// …server/data…
|
|
54
67
|
scheduler,
|
|
55
68
|
})
|
|
69
|
+
runtime.register([caixaDomain])
|
|
70
|
+
await runtime.start()
|
|
56
71
|
```
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
No `start()`, o runtime confere se cada schedule aponta para uma action registrada no mesmo runtime
|
|
74
|
+
e depois o registra no adapter. Um nome sem action registrada interrompe o `start()` com
|
|
75
|
+
`runtime.schedule_action_not_found`, antes de inicializar os adapters; a mensagem lista cada
|
|
76
|
+
schedule e a action que ele procurou. Com schedules registrados e sem `scheduler`, o `start()`
|
|
77
|
+
falha com `runtime.scheduler_required`. Um schedule com `enabled: false` não é registrado nem
|
|
78
|
+
conferido, então pode apontar para uma action que ainda não existe no ambiente.
|
|
79
|
+
|
|
80
|
+
## Preparar a action agendada
|
|
81
|
+
|
|
82
|
+
O schedule executa a action sem usuário: `ctx.user` é `null` e `ctx.can` nega tudo. Por isso, a
|
|
83
|
+
action alvo precisa declarar `public: true`; sem isso, cada disparo termina em
|
|
84
|
+
`auth.unauthenticated`. Para que ela não fique acessível por HTTP, declare também `internal: true`:
|
|
85
|
+
os servidores do Opus não expõem actions internas, e o schedule continua executando-a pelo runtime.
|
|
86
|
+
|
|
87
|
+
Quando um disparo não conclui a action, o runtime registra um erro no log com o schedule, a action,
|
|
88
|
+
o código e a mensagem do erro; o agendamento continua ativo e o próximo disparo executa a action de
|
|
89
|
+
novo. Uma falha dentro do pipeline da action, como `auth.unauthenticated` ou um erro do handler,
|
|
90
|
+
também fica registrada no audit. O callback `onError` do driver recebe somente erros lançados antes
|
|
91
|
+
da execução, como uma falha na função `input`.
|
|
60
92
|
|
|
61
93
|
## Limites atuais
|
|
62
94
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
O único driver é o `node-cron`, que roda no mesmo processo: o agendamento some se o processo cair e,
|
|
96
|
+
em um cluster, cada nó dispara o mesmo schedule. O modo design do Vite não registra schedules.
|
|
97
|
+
Backends duráveis ou distribuídos, como jobs repetidos do BullMQ ou Temporal, ainda não têm driver.
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
## Lista de altura fixa
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use `ScrollArea` quando um bloco precisa manter a própria altura e rolar o conteúdo que passar dela.
|
|
4
|
+
Dê a altura ao `ScrollArea`, como `h-48`, e coloque o conteúdo dentro. A barra vertical já vem
|
|
5
|
+
incluída; não é preciso acrescentar `ScrollBar`.
|
|
4
6
|
|
|
5
7
|
```tsx preview col
|
|
6
|
-
const
|
|
7
|
-
{ id: '
|
|
8
|
-
{ id: '
|
|
9
|
-
{ id: '
|
|
10
|
-
{ id: '
|
|
11
|
-
{ id: '
|
|
12
|
-
{ id: '
|
|
13
|
-
{ id: '
|
|
14
|
-
{ id: '
|
|
8
|
+
const orders = [
|
|
9
|
+
{ id: 'OS-1842', title: 'Revisão dos 20.000 km', vehicle: 'ABC-1D23' },
|
|
10
|
+
{ id: 'OS-1839', title: 'Troca das pastilhas de freio', vehicle: 'BRA-2E19' },
|
|
11
|
+
{ id: 'OS-1835', title: 'Alinhamento e balanceamento', vehicle: 'RIO-4F56' },
|
|
12
|
+
{ id: 'OS-1830', title: 'Diagnóstico de ruído na suspensão', vehicle: 'SPO-7G88' },
|
|
13
|
+
{ id: 'OS-1827', title: 'Troca de óleo e filtro', vehicle: 'ABC-1D23' },
|
|
14
|
+
{ id: 'OS-1821', title: 'Substituição da bateria', vehicle: 'CWB-3H45' },
|
|
15
|
+
{ id: 'OS-1818', title: 'Higienização do ar-condicionado', vehicle: 'BRA-2E19' },
|
|
16
|
+
{ id: 'OS-1814', title: 'Revisão dos 40.000 km', vehicle: 'POA-9J12' },
|
|
15
17
|
]
|
|
16
18
|
|
|
17
19
|
render(
|
|
18
20
|
<ScrollArea className="h-48 w-full rounded-md border border-border">
|
|
19
21
|
<div className="p-3">
|
|
20
|
-
{
|
|
21
|
-
<div key={
|
|
22
|
-
<p className="font-medium">{
|
|
23
|
-
<p className="text-xs text-muted-foreground">{
|
|
22
|
+
{orders.map((order) => (
|
|
23
|
+
<div key={order.id} className="rounded-md px-2 py-1.5 text-sm hover:bg-muted">
|
|
24
|
+
<p className="font-medium">{order.title}</p>
|
|
25
|
+
<p className="text-xs text-muted-foreground">{order.id} · {order.vehicle}</p>
|
|
24
26
|
</div>
|
|
25
27
|
))}
|
|
26
28
|
</div>
|
|
@@ -30,17 +32,18 @@ render(
|
|
|
30
32
|
|
|
31
33
|
## Trilho horizontal
|
|
32
34
|
|
|
33
|
-
Para rolar na horizontal, acrescente
|
|
35
|
+
Para rolar na horizontal, acrescente `<ScrollBar orientation="horizontal" />` como filho e mantenha
|
|
36
|
+
o conteúdo em uma linha que não quebra, com `flex` e `w-max`.
|
|
34
37
|
|
|
35
38
|
```tsx preview col
|
|
36
|
-
const
|
|
39
|
+
const services = ['Troca de óleo', 'Filtro de ar', 'Alinhamento', 'Balanceamento', 'Pastilhas de freio', 'Velas de ignição']
|
|
37
40
|
|
|
38
41
|
render(
|
|
39
42
|
<ScrollArea className="w-full rounded-md border border-border whitespace-nowrap">
|
|
40
43
|
<div className="flex w-max gap-2 p-3">
|
|
41
|
-
{
|
|
42
|
-
<span key={
|
|
43
|
-
{
|
|
44
|
+
{services.map((service) => (
|
|
45
|
+
<span key={service} className="rounded-md border border-border bg-muted px-3 py-1.5 text-sm">
|
|
46
|
+
{service}
|
|
44
47
|
</span>
|
|
45
48
|
))}
|
|
46
49
|
</div>
|
|
@@ -49,28 +52,30 @@ render(
|
|
|
49
52
|
)
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
##
|
|
55
|
+
## Histórico com divisórias
|
|
53
56
|
|
|
54
|
-
O conteúdo é livre
|
|
57
|
+
O conteúdo interno é livre. Neste exemplo, o histórico de uma ordem de serviço usa `Separator`
|
|
58
|
+
entre as linhas. A barra só aparece quando o conteúdo passa da altura e o ponteiro está sobre a
|
|
59
|
+
área; para mantê-la sempre visível, passe `type="always"`.
|
|
55
60
|
|
|
56
61
|
```tsx preview col
|
|
57
|
-
const
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'12:
|
|
62
|
+
const history = [
|
|
63
|
+
'08:02 Veículo recebido na oficina',
|
|
64
|
+
'08:15 Checklist de entrada concluído',
|
|
65
|
+
'08:40 Diagnóstico iniciado',
|
|
66
|
+
'09:10 Orçamento enviado ao cliente',
|
|
67
|
+
'09:32 Orçamento aprovado',
|
|
68
|
+
'10:05 Peças separadas no estoque',
|
|
69
|
+
'11:20 Serviço concluído',
|
|
70
|
+
'11:45 Teste de rodagem aprovado',
|
|
71
|
+
'12:00 Veículo liberado para retirada',
|
|
67
72
|
]
|
|
68
73
|
|
|
69
74
|
render(
|
|
70
75
|
<ScrollArea className="h-40 w-full rounded-md border border-border">
|
|
71
76
|
<div className="p-3 text-sm">
|
|
72
|
-
{
|
|
73
|
-
<div key={
|
|
77
|
+
{history.map((line, i) => (
|
|
78
|
+
<div key={line}>
|
|
74
79
|
{i > 0 && <Separator className="my-1.5" />}
|
|
75
80
|
<p className="text-muted-foreground">{line}</p>
|
|
76
81
|
</div>
|
|
@@ -84,11 +89,13 @@ render(
|
|
|
84
89
|
|
|
85
90
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
86
91
|
|---|---|---|---|
|
|
87
|
-
| `className` | `string` | |
|
|
88
|
-
| `
|
|
92
|
+
| `className` | `string` | | Define as dimensões da janela rolável. Sem uma dimensão limitada, não há conteúdo a recortar. |
|
|
93
|
+
| `type` | `'hover' \| 'scroll' \| 'auto' \| 'always'` | `'hover'` | Quando a barra aparece: sob o ponteiro, durante a rolagem, sempre que houver excedente ou sempre. |
|
|
94
|
+
| `children` | `ReactNode` | | Conteúdo da janela, incluindo uma `ScrollBar` horizontal quando necessária. |
|
|
89
95
|
|
|
90
96
|
## Propriedades de ScrollBar
|
|
91
97
|
|
|
92
98
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
93
99
|
|---|---|---|---|
|
|
94
100
|
| `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Direção da barra. A barra vertical já faz parte de `ScrollArea`. |
|
|
101
|
+
| `className` | `string` | | Ajusta o trilho da barra. |
|