@offscript/sdk 0.1.1 → 0.1.5
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 +32 -119
- package/dist/adapters/nuxt.cjs +3 -3
- package/dist/adapters/nuxt.js +2 -2
- package/dist/adapters/vanilla.cjs +5 -5
- package/dist/adapters/vanilla.d.ts +2 -3
- package/dist/adapters/vanilla.js +3 -3
- package/dist/adapters/vue.cjs +3 -3
- package/dist/adapters/vue.js +2 -2
- package/dist/chunk-2MY2FWIA.cjs +20 -0
- package/dist/chunk-2MY2FWIA.cjs.map +1 -0
- package/dist/{chunk-LFXHB4PN.js → chunk-6ROP37WI.js} +5 -6
- package/dist/chunk-6ROP37WI.js.map +1 -0
- package/dist/{chunk-B6GO5FE5.cjs → chunk-HPDLEAAL.cjs} +5 -6
- package/dist/chunk-HPDLEAAL.cjs.map +1 -0
- package/dist/{chunk-MBYNQSKA.js → chunk-V2YYWGIA.js} +5 -5
- package/dist/chunk-V2YYWGIA.js.map +1 -0
- package/dist/{chunk-3NX2AGXM.cjs → chunk-VYCDQLP7.cjs} +1084 -1170
- package/dist/chunk-VYCDQLP7.cjs.map +1 -0
- package/dist/{chunk-3OSCH7J2.js → chunk-XBXFGCUT.js} +1081 -1162
- package/dist/chunk-XBXFGCUT.js.map +1 -0
- package/dist/core/LifecycleManager.d.ts +1 -0
- package/dist/core/OffscriptSDK.d.ts +34 -52
- package/dist/core/RecordingStore.d.ts +26 -0
- package/dist/index.cjs +20 -40
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/playwright/PlaywrightDataContract.d.ts +0 -7
- package/dist/playwright.cjs +13 -13
- package/dist/playwright.js +1 -1
- package/dist/privacy/DataSanitizer.d.ts +1 -0
- package/dist/recorders/ActionRecorder.d.ts +1 -1
- package/dist/recorders/ContextRecorder.d.ts +2 -8
- package/dist/recorders/HTTPRecorder.d.ts +7 -2
- package/dist/types/config.d.ts +13 -41
- package/dist/types/events.d.ts +4 -23
- package/dist/types/recording.d.ts +20 -0
- package/dist/ui/RecordingControls.d.ts +62 -0
- package/dist/utils/errors.d.ts +1 -18
- package/docs/api-contract.md +4 -53
- package/docs/architecture.md +5 -34
- package/docs/event-contract.md +3 -24
- package/docs/playwright-contract.md +3 -37
- package/package.json +2 -2
- package/dist/chunk-3NX2AGXM.cjs.map +0 -1
- package/dist/chunk-3OSCH7J2.js.map +0 -1
- package/dist/chunk-B6GO5FE5.cjs.map +0 -1
- package/dist/chunk-HAPNSHFG.cjs +0 -20
- package/dist/chunk-HAPNSHFG.cjs.map +0 -1
- package/dist/chunk-LFXHB4PN.js.map +0 -1
- package/dist/chunk-MBYNQSKA.js.map +0 -1
- package/dist/core/ApiClient.d.ts +0 -24
- package/dist/core/SessionManager.d.ts +0 -44
- package/dist/transport/EventQueue.d.ts +0 -28
- package/dist/transport/EventTransport.d.ts +0 -84
- package/dist/transport/PersistentBuffer.d.ts +0 -60
- package/dist/transport/RetryManager.d.ts +0 -9
- package/dist/types/session.d.ts +0 -77
package/README.md
CHANGED
|
@@ -1,134 +1,47 @@
|
|
|
1
1
|
# @offscript/sdk
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Funciona em JS puro, Vue 2/3, Nuxt, React, Laravel Blade e Inertia, em SPA e MPA. O núcleo não depende de nenhum framework.
|
|
6
|
-
|
|
7
|
-
> Estado: `0.1.0`. Veja [Limitações conhecidas](#limitações-conhecidas) e o [relatório de testes](#testes).
|
|
8
|
-
|
|
9
|
-
## Instalação
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install @offscript/sdk
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Uso
|
|
3
|
+
Biblioteca de captura no navegador: DOM com rrweb, ações, navegação SPA, HTTP, console, erros, contexto e iframes. Não depende de backend para começar. Por padrão, os dados ficam em memória. Para continuar a mesma gravação entre documentos da mesma origem, o host pode fornecer uma `persistenceKey` estável e exclusiva da aba.
|
|
16
4
|
|
|
17
5
|
```ts
|
|
18
6
|
import { Offscript } from "@offscript/sdk";
|
|
19
7
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
platformId: "platform-id",
|
|
23
|
-
appVersion: "1.4.2",
|
|
24
|
-
recording: { rrweb: true, actions: true, http: true, console: true, errors: true },
|
|
25
|
-
privacy: { maskSensitiveInputs: true, captureRequestBodies: false, captureResponseBodies: false },
|
|
8
|
+
const sdk = new Offscript({
|
|
9
|
+
recording: { rrweb: true, actions: true, http: true, errors: true, iframes: true },
|
|
26
10
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
executionId: "execution-id",
|
|
32
|
-
sessionToken: "short-lived-session-token", // emitido pelo SEU backend; nunca uma chave permanente
|
|
11
|
+
await sdk.startRecording();
|
|
12
|
+
const result = await sdk.complete({
|
|
13
|
+
endpoint: "https://painel.example/api/recordings",
|
|
14
|
+
token: tokenForUpload,
|
|
33
15
|
});
|
|
34
|
-
await offscript.pauseRecording(); // retomar gera um novo snapshot completo
|
|
35
|
-
await offscript.resumeRecording();
|
|
36
|
-
const summary = await offscript.stopRecording(); // { flushed, pendingEvents, completed }
|
|
37
|
-
await offscript.destroy();
|
|
38
16
|
```
|
|
39
17
|
|
|
40
|
-
|
|
18
|
+
`complete` para os recorders e faz um único POST JSON com `Authorization: Bearer <token>`. O destino e o token são fornecidos pelo front-end apenas nesta operação. O SDK não lê tokens da URL nem conhece IDs do domínio do painel.
|
|
19
|
+
|
|
20
|
+
O payload contém `recording` (envelopes rrweb, ações, console, erros, contexto, iframes e ciclo de vida), `request` (envelopes HTTP) e `regression` (contrato Playwright com condições iniciais e passos). Não há transporte durante a captura nem reenvio automático. Chamadas concorrentes de `complete` compartilham o envio; após sucesso, chamadas repetidas retornam o resultado. Após falha, os dados continuam disponíveis para uma nova chamada explícita.
|
|
21
|
+
|
|
22
|
+
`stopRecording()` encerra localmente e devolve o payload sem publicar. `pauseRecording()` e `resumeRecording()` controlam a captura; retomar gera um snapshot completo. `discardRecording()` limpa os dados e volta ao estado inicial. `destroy()` libera a instrumentação sem enviar dados.
|
|
41
23
|
|
|
42
|
-
|
|
43
|
-
`idle → initializing → recording ⇄ paused → stopping → stopped` (e `error`). `offscript.getState()` devolve `{ status, session, pending, lastError }`.
|
|
24
|
+
O overlay aparece em `init()` quando `controls` está habilitado (padrão). Iniciar grava localmente. Para publicar ao clicar em Finalizar, configure o callback do host:
|
|
44
25
|
|
|
45
26
|
```ts
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Erros tipados: `ConfigError`, `AuthError`, `SessionExpiredError`, `SessionDisabledError`, `InvalidStateError`, `TransportError` (todos estendem `OffscriptError` com `code`).
|
|
51
|
-
|
|
52
|
-
### Autorização
|
|
53
|
-
A gravação só começa depois que `POST /sdk/sessions` autoriza o token e responde `recording.enabled: true`. O token é guardado só em `sessionStorage` (escopo da aba) e usado em `Authorization: Bearer`; renovações chegam em `sessionToken` nas respostas. O backend pode desativar remotamente via heartbeat.
|
|
54
|
-
|
|
55
|
-
## Configuração
|
|
56
|
-
|
|
57
|
-
| Opção | Padrão | Descrição |
|
|
58
|
-
|---|---|---|
|
|
59
|
-
| `apiUrl` | — | HTTPS obrigatório (HTTP só em localhost) |
|
|
60
|
-
| `platformId` | — | Plataforma do SDK |
|
|
61
|
-
| `appVersion` | — | Versão/build da app, enviada no contexto |
|
|
62
|
-
| `autoResume` | `true` | Retoma sessão persistida em `init()` |
|
|
63
|
-
| `correlationWindowMs` | `3000` | Janela para ligar http/erros à ação anterior |
|
|
64
|
-
| `heartbeatIntervalMs` | `30000` | Usado se o backend não informar |
|
|
65
|
-
| `recording.rrweb/actions/http/console/errors/context/iframes` | `true` | Liga cada módulo |
|
|
66
|
-
| `recording.mouseMove` | `false` | Trajetória do mouse nas *ações* (rrweb já grava o movimento) |
|
|
67
|
-
| `recording.consoleLevels` | todos | `log`, `info`, `warn`, `error` |
|
|
68
|
-
| `recording.throttleMs` | `100` | Amostragem de mousemove |
|
|
69
|
-
| `recording.rrwebCheckoutEveryMs` | `300000` | Snapshot completo periódico (0 desliga) |
|
|
70
|
-
| `recording.rrwebRecordCanvas` | `false` | Canvas (custoso) |
|
|
71
|
-
| `recording.testIdAttributes` | `data-testid, data-test, data-cy, data-qa` | Atributos de teste para seletores |
|
|
72
|
-
| `recording.stableAttributes` | `name, data-id, aria-label` | Atributos estáveis extras |
|
|
73
|
-
| `privacy.maskSensitiveInputs` | `true` | Máscara de inputs no replay |
|
|
74
|
-
| `privacy.maskAllText` | `false` | Máscara de todo texto no replay |
|
|
75
|
-
| `privacy.captureRequestBodies / captureResponseBodies` | `false` | Bodies HTTP |
|
|
76
|
-
| `privacy.allowedInputSelectors` | `[data-offscript-allow]` | Campos cujo valor pode ser gravado |
|
|
77
|
-
| `privacy.blockSelectors / maskTextSelectors / ignoreSelectors` | `[data-offscript-block]`… | Bloquear, mascarar texto, ignorar ações |
|
|
78
|
-
| `privacy.ignoreUrls` | `[]` | Requisições não capturadas (string ou RegExp) |
|
|
79
|
-
| `privacy.redactHeaders / redactKeys` | `[]` | Extras além do padrão |
|
|
80
|
-
| `privacy.maxBodyBytes` | `16384` | Limite de body capturado |
|
|
81
|
-
| `privacy.localRetentionMs` | `86400000` | Retenção local de eventos não enviados |
|
|
82
|
-
| `transport.*` | ver `DEFAULT_TRANSPORT` | lote, flush, memória, retries, `compress` (gzip; requer suporte no backend), `persist` (IndexedDB) |
|
|
83
|
-
|
|
84
|
-
### Privacidade (padrão seguro)
|
|
85
|
-
Senhas, tokens, `Authorization`, cookies, chaves de API, JWT, CPF/CNPJ e cartões (Luhn) são redigidos **antes** de persistir ou enviar — em headers, query, bodies, console, erros, URLs/atributos/textos do rrweb. Valores digitados não vão para as ações (viram `valueRef`) a não ser em campos com `data-offscript-allow`. Use `data-offscript-block` / `.offscript-block` para remover um elemento do replay e `data-offscript-ignore` para ignorar suas ações. Isso ajuda a atender a LGPD, mas **não a substitui**: a base legal, o aviso aos testadores, a retenção e a exclusão no servidor são responsabilidade da Offscript/cliente.
|
|
86
|
-
|
|
87
|
-
## Adaptadores
|
|
88
|
-
`@offscript/sdk/vue` (Vue 2/3, sem importar Vue), `@offscript/sdk/nuxt` (client-only), `@offscript/sdk/vanilla` (`createOffscript`, `startOffscript`). Exemplos em [examples/](./examples).
|
|
89
|
-
|
|
90
|
-
## Playwright
|
|
91
|
-
`offscript.exportPlaywrightData()` ou `buildPlaywrightContract()` (de `@offscript/sdk/playwright`) — ver [docs/playwright-contract.md](./docs/playwright-contract.md). O SDK não executa Playwright.
|
|
92
|
-
|
|
93
|
-
## Documentação
|
|
94
|
-
- [Arquitetura e decisões](./docs/architecture.md)
|
|
95
|
-
- [Contrato da API](./docs/api-contract.md) — **o backend da Offscript precisa implementá-lo; este repositório só traz um servidor de referência de testes**
|
|
96
|
-
- [Contrato de eventos](./docs/event-contract.md)
|
|
97
|
-
- [Contrato Playwright](./docs/playwright-contract.md)
|
|
98
|
-
|
|
99
|
-
## Limitações conhecidas
|
|
100
|
-
- **Iframes cross-origin (ex.: seats.io)**: nem o SDK nem o rrweb acessam o conteúdo interno. São registrados presença (`origin` + `path`, sem query), dimensões, posição, foco (quando observável) e interações visíveis na página principal. Caminhos futuros: instrumentação/eventos públicos do seats.io, ou captura complementar via Playwright em ambiente de teste autorizado — **não implementados**.
|
|
101
|
-
- **HTTP**: só `fetch` e `XMLHttpRequest` da página principal. Não captura WebSocket, requisições de iframes cross-origin, Service Workers, cookies HttpOnly, headers protegidos, nem `fetch` chamado antes do SDK iniciar. `duration` do fetch é até os headers. Bodies de streaming/binário são omitidos. Bodies de request do tipo `Request`/stream não são lidos.
|
|
102
|
-
- **Console**: o stack aponta para o wrapper; arquivo/linha de `console.*` não é o da chamada original no DevTools.
|
|
103
|
-
- **Entrega ao fechar a aba**: usa `fetch keepalive` (≤ 60 KB) sem ACK; o que não chegar é reenviado na próxima página da mesma aba. Se o navegador for encerrado abruptamente (crash, fechamento da última aba), **não há garantia de entrega** — eventos pendentes ficam no IndexedDB até a próxima sessão da aba/origem ou expirarem.
|
|
104
|
-
- **Multi-aba**: gravação por aba (cada uma com `tabId` e sequência próprios). A detecção de aba clonada exige `navigator.locks`.
|
|
105
|
-
- **Replay**: só reproduz o DOM gravado (iframe sandbox sem scripts). Canvas é opcional e custoso; vídeo/áudio e Shadow DOM fechado seguem as limitações do rrweb. `mousemove` sofre amostragem.
|
|
106
|
-
- **Backpressure**: com a fila cheia, eventos de baixa prioridade são descartados (`overflow`) e o SDK força novo snapshot rrweb.
|
|
107
|
-
- O `exportPlaywrightData()` do navegador cobre as ações da página atual (memória, até 5000); para a sessão inteira use `buildPlaywrightContract` com os eventos armazenados no backend.
|
|
108
|
-
- **Não verificado**: execução em aplicações Vue/Nuxt/Laravel/Inertia reais, navegadores além do Chromium, Safari/iOS (limites de `keepalive`/IndexedDB), carga em páginas muito grandes (só há métricas internas `getMetrics()`, sem benchmark).
|
|
109
|
-
|
|
110
|
-
## Desenvolvimento
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
npm install
|
|
114
|
-
npm run typecheck
|
|
115
|
-
npm test # 69 testes (vitest + jsdom + servidor HTTP de referência real)
|
|
116
|
-
npm run test:e2e # Playwright em Chromium real (npx playwright install chromium)
|
|
117
|
-
npm run build # tsup (ESM+CJS) + tsc (declarações)
|
|
27
|
+
const sdk = new Offscript({
|
|
28
|
+
onComplete: () => sdk.complete({ endpoint: destination, token: uploadToken }),
|
|
29
|
+
});
|
|
30
|
+
await sdk.init();
|
|
118
31
|
```
|
|
119
32
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
33
|
+
Sem callback, Finalizar apenas encerra localmente. `getState()` retorna `{ status, pending, lastError }`. Eventos públicos: `statusChange`, `error`, `recordingStart` e `recordingEnd` (captura encerrada, antes do upload).
|
|
34
|
+
|
|
35
|
+
As opções `recording` e `privacy` estão tipadas em `src/types/config.ts`. `captureSensitiveValues` vem desabilitada; habilitá-la inclui valores sensíveis na captura. Configure máscaras, seletores bloqueados e URLs ignoradas conforme a aplicação.
|
|
36
|
+
|
|
37
|
+
Adaptadores disponíveis: `@offscript/sdk/vanilla`, `/vue` e `/nuxt`. O módulo `/playwright` exporta geração e validação do contrato; não executa o navegador. Iframes de outra origem fornecem apenas metadados de presença, foco e dimensões.
|
|
38
|
+
|
|
39
|
+
Validação: `npm run typecheck`, `npm test`, `npm run build`, `npm run test:e2e` no pacote. Os testes de navegador exigem Chromium e suas bibliotecas de sistema.
|
|
40
|
+
|
|
41
|
+
## Continuidade entre páginas
|
|
42
|
+
|
|
43
|
+
Configure `persistenceKey` com uma chave opaca criada pelo host e mantida em `sessionStorage` na aba. Com a mesma chave em cada página, `init()` restaura o rascunho e retoma a captura quando ela estava ativa, preserva a pausa ou disponibiliza a gravação encerrada para envio. Sem essa opção, a captura continua apenas em memória.
|
|
44
|
+
|
|
45
|
+
Os eventos ficam no IndexedDB da origem. No descarregamento do documento, os últimos eventos ainda não confirmados são guardados em `sessionStorage` para a próxima página. `complete()` limpa o rascunho após o HTTP de sucesso; `discardRecording()` também o remove. `destroy()` fecha o armazenamento e libera a instrumentação, preservando o rascunho local.
|
|
46
|
+
|
|
47
|
+
O token continua sob responsabilidade do host. A bancada o recebe pela query, guarda na aba e remove o parâmetro da URL; páginas seguintes usam o valor da aba. Após envio bem-sucedido, a bancada apaga token e chave e fecha o overlay. Falhas mantêm os dados para nova tentativa. A continuidade exige a mesma origem e SDK inicializado em cada documento; armazenamento de navegador não é compartilhado entre domínios ou portas diferentes.
|
package/dist/adapters/nuxt.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkVYCDQLP7_cjs = require('../chunk-VYCDQLP7.cjs');
|
|
4
|
+
require('../chunk-HPDLEAAL.cjs');
|
|
5
5
|
|
|
6
6
|
// src/adapters/nuxt.ts
|
|
7
7
|
function createNuxtOffscript(config) {
|
|
8
8
|
if (typeof window === "undefined") return null;
|
|
9
|
-
const sdk = new
|
|
9
|
+
const sdk = new chunkVYCDQLP7_cjs.Offscript(config);
|
|
10
10
|
void sdk.init().catch(() => void 0);
|
|
11
11
|
return sdk;
|
|
12
12
|
}
|
package/dist/adapters/nuxt.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
5
|
-
require('../chunk-
|
|
3
|
+
var chunk2MY2FWIA_cjs = require('../chunk-2MY2FWIA.cjs');
|
|
4
|
+
require('../chunk-VYCDQLP7.cjs');
|
|
5
|
+
require('../chunk-HPDLEAAL.cjs');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
Object.defineProperty(exports, "createOffscript", {
|
|
10
10
|
enumerable: true,
|
|
11
|
-
get: function () { return
|
|
11
|
+
get: function () { return chunk2MY2FWIA_cjs.createOffscript; }
|
|
12
12
|
});
|
|
13
13
|
Object.defineProperty(exports, "startOffscript", {
|
|
14
14
|
enumerable: true,
|
|
15
|
-
get: function () { return
|
|
15
|
+
get: function () { return chunk2MY2FWIA_cjs.startOffscript; }
|
|
16
16
|
});
|
|
17
17
|
//# sourceMappingURL=vanilla.cjs.map
|
|
18
18
|
//# sourceMappingURL=vanilla.cjs.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Offscript } from "../core/OffscriptSDK";
|
|
2
2
|
import type { OffscriptConfig } from "../types/config";
|
|
3
|
-
|
|
4
|
-
/** Atalho para aplicações JS tradicionais, Blade e MPA: inicializa e retoma sessões persistidas. */
|
|
3
|
+
/** Atalho para aplicações JS tradicionais, Blade e MPA: inicializa a captura local. */
|
|
5
4
|
export declare function createOffscript(config: OffscriptConfig): Promise<Offscript>;
|
|
6
|
-
export declare function startOffscript(config: OffscriptConfig
|
|
5
|
+
export declare function startOffscript(config: OffscriptConfig): Promise<Offscript>;
|
package/dist/adapters/vanilla.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createOffscript, startOffscript } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
1
|
+
export { createOffscript, startOffscript } from '../chunk-V2YYWGIA.js';
|
|
2
|
+
import '../chunk-XBXFGCUT.js';
|
|
3
|
+
import '../chunk-6ROP37WI.js';
|
|
4
4
|
//# sourceMappingURL=vanilla.js.map
|
|
5
5
|
//# sourceMappingURL=vanilla.js.map
|
package/dist/adapters/vue.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkVYCDQLP7_cjs = require('../chunk-VYCDQLP7.cjs');
|
|
4
|
+
require('../chunk-HPDLEAAL.cjs');
|
|
5
5
|
|
|
6
6
|
// src/adapters/vue.ts
|
|
7
7
|
var OFFSCRIPT_KEY = "$offscript";
|
|
8
8
|
var OffscriptPlugin = {
|
|
9
9
|
install(app, config) {
|
|
10
|
-
const sdk = new
|
|
10
|
+
const sdk = new chunkVYCDQLP7_cjs.Offscript(config);
|
|
11
11
|
void sdk.init().catch(() => void 0);
|
|
12
12
|
if (app.config?.globalProperties) {
|
|
13
13
|
app.config.globalProperties[OFFSCRIPT_KEY] = sdk;
|
package/dist/adapters/vue.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkVYCDQLP7_cjs = require('./chunk-VYCDQLP7.cjs');
|
|
4
|
+
|
|
5
|
+
// src/adapters/vanilla.ts
|
|
6
|
+
async function createOffscript(config) {
|
|
7
|
+
const sdk = new chunkVYCDQLP7_cjs.Offscript(config);
|
|
8
|
+
await sdk.init();
|
|
9
|
+
return sdk;
|
|
10
|
+
}
|
|
11
|
+
async function startOffscript(config) {
|
|
12
|
+
const sdk = await createOffscript(config);
|
|
13
|
+
await sdk.startRecording();
|
|
14
|
+
return sdk;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.createOffscript = createOffscript;
|
|
18
|
+
exports.startOffscript = startOffscript;
|
|
19
|
+
//# sourceMappingURL=chunk-2MY2FWIA.cjs.map
|
|
20
|
+
//# sourceMappingURL=chunk-2MY2FWIA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/vanilla.ts"],"names":["Offscript"],"mappings":";;;;;AAIA,eAAsB,gBAAgB,MAAA,EAA6C;AACjF,EAAA,MAAM,GAAA,GAAM,IAAIA,2BAAA,CAAU,MAAM,CAAA;AAChC,EAAA,MAAM,IAAI,IAAA,EAAK;AACf,EAAA,OAAO,GAAA;AACT;AAEA,eAAsB,eAAe,MAAA,EAA6C;AAChF,EAAA,MAAM,GAAA,GAAM,MAAM,eAAA,CAAgB,MAAM,CAAA;AACxC,EAAA,MAAM,IAAI,cAAA,EAAe;AACzB,EAAA,OAAO,GAAA;AACT","file":"chunk-2MY2FWIA.cjs","sourcesContent":["import { Offscript } from \"../core/OffscriptSDK\";\nimport type { OffscriptConfig } from \"../types/config\";\n\n/** Atalho para aplicações JS tradicionais, Blade e MPA: inicializa a captura local. */\nexport async function createOffscript(config: OffscriptConfig): Promise<Offscript> {\n const sdk = new Offscript(config);\n await sdk.init();\n return sdk;\n}\n\nexport async function startOffscript(config: OffscriptConfig): Promise<Offscript> {\n const sdk = await createOffscript(config);\n await sdk.startRecording();\n return sdk;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/types/events.ts
|
|
2
2
|
var SCHEMA_VERSION = "1.0";
|
|
3
|
-
var SDK_VERSION = "0.1.
|
|
3
|
+
var SDK_VERSION = "0.1.5";
|
|
4
4
|
var ACTION_SCHEMA_VERSION = "1.0";
|
|
5
5
|
|
|
6
6
|
// src/playwright/SelectorGenerator.ts
|
|
@@ -273,7 +273,8 @@ function normalizeActions(actions) {
|
|
|
273
273
|
const mods = a.payload?.modifiers ?? [];
|
|
274
274
|
const key = a.payload?.key;
|
|
275
275
|
if (!key) break;
|
|
276
|
-
|
|
276
|
+
const held = mods.filter((m) => m !== key && (m !== "Shift" || key.length === 1));
|
|
277
|
+
steps.push(base("press", { key: [...held, key].join("+"), code: a.payload?.code }));
|
|
277
278
|
break;
|
|
278
279
|
}
|
|
279
280
|
case "select":
|
|
@@ -380,7 +381,6 @@ function buildPlaywrightContract(input) {
|
|
|
380
381
|
kind: PLAYWRIGHT_CONTRACT_KIND,
|
|
381
382
|
generatedAt: Date.now(),
|
|
382
383
|
sdkVersion: SDK_VERSION,
|
|
383
|
-
session: input.session,
|
|
384
384
|
initialConditions: {
|
|
385
385
|
url: ordered[0]?.url ?? first?.url,
|
|
386
386
|
viewport: first?.viewport ?? ordered[0]?.viewport,
|
|
@@ -404,7 +404,6 @@ function validatePlaywrightContract(c) {
|
|
|
404
404
|
if (o.kind !== PLAYWRIGHT_CONTRACT_KIND) errors.push("kind inv\xE1lido");
|
|
405
405
|
if (!o.contractVersion || !/^\d+\.\d+$/.test(o.contractVersion)) errors.push("contractVersion inv\xE1lida");
|
|
406
406
|
else if (o.contractVersion.split(".")[0] !== PLAYWRIGHT_CONTRACT_VERSION.split(".")[0]) errors.push(`vers\xE3o major incompat\xEDvel: ${o.contractVersion}`);
|
|
407
|
-
for (const k of ["sessionId", "executionId", "testCaseId", "platformId"]) if (!o.session?.[k]) errors.push(`session.${k} ausente`);
|
|
408
407
|
if (!Array.isArray(o.steps)) return [...errors, "steps ausente"];
|
|
409
408
|
let lastTs = -Infinity;
|
|
410
409
|
o.steps.forEach((s, i) => {
|
|
@@ -422,5 +421,5 @@ function validatePlaywrightContract(c) {
|
|
|
422
421
|
}
|
|
423
422
|
|
|
424
423
|
export { ACTION_SCHEMA_VERSION, CONTRACT_LIMITATIONS, PLAYWRIGHT_CONTRACT_KIND, PLAYWRIGHT_CONTRACT_VERSION, SCHEMA_VERSION, SDK_VERSION, SelectorGenerator, accessibleName, buildPlaywrightContract, implicitRole, isStableClass, isStableId, labelText, normalizeActions, validatePlaywrightContract };
|
|
425
|
-
//# sourceMappingURL=chunk-
|
|
426
|
-
//# sourceMappingURL=chunk-
|
|
424
|
+
//# sourceMappingURL=chunk-6ROP37WI.js.map
|
|
425
|
+
//# sourceMappingURL=chunk-6ROP37WI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/events.ts","../src/playwright/SelectorGenerator.ts","../src/playwright/ActionNormalizer.ts","../src/playwright/PlaywrightDataContract.ts"],"names":["css"],"mappings":"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","file":"chunk-6ROP37WI.js","sourcesContent":["export const SCHEMA_VERSION = \"1.0\";\nexport const SDK_VERSION = \"0.1.5\";\n\nexport type EventKind =\n | \"rrweb\"\n | \"action\"\n | \"http\"\n | \"console\"\n | \"error\"\n | \"context\"\n | \"iframe\"\n | \"lifecycle\";\n\n/** Envelope comum a todos os eventos. A ordem canônica é (tabId, sequence). */\nexport interface OffscriptEvent<T = unknown> {\n /** Identificador único (idempotência). */\n id: string;\n kind: EventKind;\n tabId: string;\n pageId: string;\n /** Sequência monotônica por aba, persistida entre páginas. */\n sequence: number;\n /** Momento em que o fato ocorreu (epoch ms). */\n timestamp: number;\n /** Ação do usuário mais recente dentro da janela de correlação. */\n relatedActionId?: string;\n relatedActionDeltaMs?: number;\n data: T;\n}\n\nexport const ACTION_SCHEMA_VERSION = \"1.0\";\n\nexport type ActionType =\n | \"click\"\n | \"dblclick\"\n | \"hover\"\n | \"mousemove\"\n | \"drag\"\n | \"input\"\n | \"keydown\"\n | \"select\"\n | \"check\"\n | \"scroll\"\n | \"navigate\"\n | \"reload\"\n | \"focus\"\n | \"blur\";\n\nexport interface SelectorCandidate {\n strategy: \"testid\" | \"attribute\" | \"role\" | \"label\" | \"placeholder\" | \"id\" | \"css\";\n /** Seletor em sintaxe Playwright (ex.: `role=button[name=\"Salvar\"]`). */\n selector: string;\n /** Único no documento no momento da ação. */\n unique: boolean;\n matches: number;\n}\n\nexport interface ElementDescriptor {\n tag: string;\n id?: string;\n role?: string;\n name?: string;\n text?: string;\n type?: string;\n testId?: string;\n classes?: string[];\n href?: string;\n inputName?: string;\n rect?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RecordedAction {\n schemaVersion: string;\n id: string;\n timestamp: number;\n /** Mesma sequência do envelope do evento. */\n sequence: number;\n type: ActionType;\n url: string;\n selector?: string;\n selectorCandidates?: SelectorCandidate[];\n selectorUnique?: boolean;\n element?: ElementDescriptor;\n coordinates?: { x: number; y: number };\n viewport?: { width: number; height: number };\n payload?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface HttpEventData {\n requestId: string;\n transport: \"fetch\" | \"xhr\";\n url: string;\n method: string;\n query?: Record<string, string | string[]>;\n requestHeaders?: Record<string, string>;\n requestBody?: CapturedBody;\n status?: number;\n statusText?: string;\n responseHeaders?: Record<string, string>;\n responseBody?: CapturedBody;\n startedAt: number;\n endedAt: number;\n durationMs: number;\n /** fetch: tempo até os headers; xhr: até loadend. */\n error?: { name: string; message: string };\n aborted?: boolean;\n /** Quantas requisições estavam em andamento quando esta começou. */\n concurrent: number;\n}\n\nexport interface CapturedBody {\n kind: \"text\" | \"json\" | \"form\" | \"binary\" | \"omitted\";\n value?: unknown;\n size?: number;\n truncated?: boolean;\n reason?: string;\n}\n\nexport interface ConsoleEventData {\n level: \"log\" | \"info\" | \"warn\" | \"error\";\n args: unknown[];\n message: string;\n stack?: string;\n url: string;\n}\n\nexport interface ErrorEventData {\n source: \"window.onerror\" | \"unhandledrejection\" | \"resource\";\n message: string;\n name?: string;\n stack?: string;\n file?: string;\n line?: number;\n column?: number;\n url: string;\n}\n\nexport interface ContextEventData {\n reason: \"initial\" | \"viewport\" | \"navigation\" | \"visibility\" | \"page-load\";\n url: string;\n referrer?: string;\n title?: string;\n navigationType?: string;\n browser?: { name?: string; version?: string };\n os?: string;\n userAgent: string;\n screen: { width: number; height: number };\n viewport: { width: number; height: number };\n devicePixelRatio: number;\n language: string;\n timezone?: string;\n online: boolean;\n visibility?: string;\n sdkVersion: string;\n /** A gravação guardou senhas, tokens e demais valores sem máscara. */\n captureSensitiveValues?: boolean;\n}\n\nexport interface IframeEventData {\n phase: \"present\" | \"removed\" | \"focus\" | \"blur\" | \"resized\";\n provider?: \"seatsio\" | \"unknown\";\n origin?: string;\n path?: string;\n crossOrigin: boolean;\n rect: { x: number; y: number; width: number; height: number };\n index: number;\n limitation: string;\n}\n\nexport interface LifecycleEventData {\n type:\n | \"recording-start\"\n | \"page-start\"\n | \"page-end\"\n | \"pause\"\n | \"resume\"\n | \"stop\"\n | \"navigation\"\n | \"overflow\"\n | \"recorder-error\";\n detail?: Record<string, unknown>;\n}\n","import type { ElementDescriptor, SelectorCandidate } from \"../types/events\";\n\nexport interface SelectorOptions {\n testIdAttributes: string[];\n stableAttributes: string[];\n}\n\nexport interface SelectorResult {\n selector: string;\n unique: boolean;\n candidates: SelectorCandidate[];\n}\n\nconst IMPLICIT_ROLES: Array<[string, string]> = [\n [\"a[href]\", \"link\"],\n [\"button\", \"button\"],\n [\"input[type=button],input[type=submit],input[type=reset]\", \"button\"],\n [\"input[type=checkbox]\", \"checkbox\"],\n [\"input[type=radio]\", \"radio\"],\n [\"input[type=range]\", \"slider\"],\n [\"input[type=search]\", \"searchbox\"],\n [\"input:not([type]),input[type=text],input[type=email],input[type=tel],input[type=url],input[type=password]\", \"textbox\"],\n [\"input[type=number]\", \"spinbutton\"],\n [\"textarea\", \"textbox\"],\n [\"select\", \"combobox\"],\n [\"h1,h2,h3,h4,h5,h6\", \"heading\"],\n [\"img[alt]\", \"img\"],\n [\"nav\", \"navigation\"],\n [\"main\", \"main\"],\n [\"ul,ol\", \"list\"],\n [\"li\", \"listitem\"],\n [\"table\", \"table\"],\n [\"dialog\", \"dialog\"],\n];\n\n/** Classes com cara de geradas (CSS-in-JS, hashes, utilitárias de estado). */\nconst UNSTABLE_CLASS = /^(css|sc|jsx|emotion|styled|_|svelte|ng-|ember|v-)[-_a-z0-9]*[0-9a-f]{4,}|^[a-z]{1,3}-(?=[0-9a-zA-Z]*\\d)[0-9a-zA-Z]{5,}$|\\b(?=[0-9a-f]*\\d)[0-9a-f]{6,}\\b|^(active|focus|hover|open|show|selected|disabled|loading|is-|has-)/i;\nconst UNSTABLE_ID = /\\d{4,}|[0-9a-f]{8,}|:r[0-9a-z]+:|^(ember|react|vue|__|ui-id-|headlessui)|^[a-z]+-[0-9a-f]{5,}$/i;\n\nconst q = (s: string): string => `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\nconst cssEsc = (s: string): string => (typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(s) : s.replace(/([^\\w-])/g, \"\\\\$1\"));\n\nexport function isStableId(id: string): boolean {\n return !!id && !UNSTABLE_ID.test(id);\n}\nexport function isStableClass(c: string): boolean {\n return !!c && !UNSTABLE_CLASS.test(c);\n}\n\nexport function implicitRole(el: Element): string | undefined {\n const explicit = el.getAttribute(\"role\");\n if (explicit) return explicit.split(/\\s+/)[0];\n for (const [sel, role] of IMPLICIT_ROLES) {\n try {\n if (el.matches(sel)) return role;\n } catch {\n /* seletor inválido no ambiente */\n }\n }\n return undefined;\n}\n\nconst norm = (s: string | null | undefined): string => (s ?? \"\").replace(/\\s+/g, \" \").trim();\n\nexport function labelText(el: Element): string {\n const doc = el.ownerDocument;\n const id = el.getAttribute(\"id\");\n if (id) {\n const l = doc.querySelector(`label[for=\"${cssEsc(id)}\"]`);\n if (l) return norm(l.textContent);\n }\n const wrap = el.closest(\"label\");\n if (wrap) return norm(wrap.textContent);\n return \"\";\n}\n\n/** Nome acessível simplificado (aria-labelledby, aria-label, label, alt, title, conteúdo). */\nexport function accessibleName(el: Element): string {\n const by = el.getAttribute(\"aria-labelledby\");\n if (by) {\n const t = by\n .split(/\\s+/)\n .map((id) => norm(el.ownerDocument.getElementById(id)?.textContent))\n .filter(Boolean)\n .join(\" \");\n if (t) return t;\n }\n const aria = norm(el.getAttribute(\"aria-label\"));\n if (aria) return aria;\n const tag = el.tagName.toLowerCase();\n if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") {\n const type = (el as HTMLInputElement).type;\n if (type === \"submit\" || type === \"button\" || type === \"reset\") return norm((el as HTMLInputElement).value);\n return labelText(el) || norm(el.getAttribute(\"placeholder\")) || norm(el.getAttribute(\"title\"));\n }\n if (tag === \"img\") return norm(el.getAttribute(\"alt\"));\n const text = norm(el.textContent);\n return (text || norm(el.getAttribute(\"title\"))).slice(0, 80);\n}\n\nfunction count(doc: Document, css: string): number {\n try {\n return doc.querySelectorAll(css).length;\n } catch {\n return 0;\n }\n}\n\nexport class SelectorGenerator {\n constructor(private readonly opts: SelectorOptions) {}\n\n generate(el: Element): SelectorResult {\n const doc = el.ownerDocument;\n const candidates: SelectorCandidate[] = [];\n const push = (strategy: SelectorCandidate[\"strategy\"], selector: string, matches: number) => {\n if (candidates.some((c) => c.selector === selector)) return;\n candidates.push({ strategy, selector, unique: matches === 1, matches });\n };\n\n for (const attr of this.opts.testIdAttributes) {\n const v = el.getAttribute(attr);\n if (v) push(\"testid\", `[${attr}=${q(v)}]`, count(doc, `[${attr}=${q(v)}]`));\n }\n for (const attr of this.opts.stableAttributes) {\n const v = el.getAttribute(attr);\n if (!v || attr === \"aria-label\") continue;\n const tag = el.tagName.toLowerCase();\n const css = `${tag}[${attr}=${q(v)}]`;\n push(\"attribute\", css, count(doc, css));\n }\n\n const role = implicitRole(el);\n const name = role ? accessibleName(el) : \"\";\n if (role && name) {\n push(\"role\", `role=${role}[name=${q(name)}]`, this.countRole(doc, role, name));\n }\n const label = [\"input\", \"textarea\", \"select\"].includes(el.tagName.toLowerCase()) ? labelText(el) : \"\";\n if (label) push(\"label\", `label=${q(label)}`, this.countByLabel(doc, label));\n const ph = el.getAttribute(\"placeholder\");\n if (ph) push(\"placeholder\", `[placeholder=${q(ph)}]`, count(doc, `[placeholder=${q(ph)}]`));\n\n const id = el.getAttribute(\"id\");\n if (id && isStableId(id)) push(\"id\", `#${cssEsc(id)}`, count(doc, `#${cssEsc(id)}`));\n\n const css = this.structuralCss(el);\n push(\"css\", css, count(doc, css));\n\n // Preferência: primeiro candidato único na ordem de prioridade; senão o primeiro; css como último.\n const best = candidates.find((c) => c.unique) ?? candidates[0];\n return { selector: best.selector, unique: best.unique, candidates };\n }\n\n private countRole(doc: Document, role: string, name: string): number {\n const sels = IMPLICIT_ROLES.filter(([, r]) => r === role).map(([s]) => s);\n sels.push(`[role=${q(role)}]`);\n let n = 0;\n let all: NodeListOf<Element>;\n try {\n all = doc.querySelectorAll(sels.join(\",\"));\n } catch {\n return 0;\n }\n all.forEach((e) => {\n if (accessibleName(e) === name) n++;\n });\n return n;\n }\n\n private countByLabel(doc: Document, label: string): number {\n let n = 0;\n doc.querySelectorAll(\"input,textarea,select\").forEach((e) => {\n if (labelText(e) === label) n++;\n });\n return n;\n }\n\n /** CSS estrutural: ancora no ancestral estável mais próximo; usa tag + classes estáveis + nth-of-type. */\n structuralCss(el: Element): string {\n const parts: string[] = [];\n let cur: Element | null = el;\n let depth = 0;\n while (cur && cur.nodeType === 1 && depth < 6) {\n const tag = cur.tagName.toLowerCase();\n if (tag === \"html\") break;\n const tid = this.opts.testIdAttributes.map((a) => [a, cur!.getAttribute(a)] as const).find(([, v]) => v);\n if (tid && cur !== el) {\n parts.unshift(`[${tid[0]}=${q(tid[1]!)}]`);\n break;\n }\n const id = cur.getAttribute(\"id\");\n if (id && isStableId(id)) {\n parts.unshift(`#${cssEsc(id)}`);\n break;\n }\n let seg = tag;\n const classes = Array.from(cur.classList).filter(isStableClass).slice(0, 2);\n if (classes.length) seg += classes.map((c) => `.${cssEsc(c)}`).join(\"\");\n const parent: Element | null = cur.parentElement;\n if (parent) {\n const same = Array.from(parent.children).filter((c) => c.tagName === cur!.tagName);\n if (same.length > 1) seg += `:nth-of-type(${same.indexOf(cur) + 1})`;\n }\n parts.unshift(seg);\n cur = parent;\n depth++;\n }\n return parts.join(\" > \");\n }\n\n describe(el: Element): ElementDescriptor {\n const tag = el.tagName.toLowerCase();\n const isField = tag === \"input\" || tag === \"textarea\" || tag === \"select\";\n const testId = this.opts.testIdAttributes.map((a) => el.getAttribute(a)).find(Boolean) ?? undefined;\n const role = implicitRole(el);\n const d: ElementDescriptor = { tag };\n const id = el.getAttribute(\"id\");\n if (id && isStableId(id)) d.id = id;\n if (role) d.role = role;\n const name = accessibleName(el);\n if (name) d.name = name.slice(0, 80);\n // Nunca inclui conteúdo textual de campos de formulário.\n if (!isField) {\n const text = norm(el.textContent);\n if (text) d.text = text.slice(0, 80);\n }\n const type = el.getAttribute(\"type\");\n if (type) d.type = type;\n if (testId) d.testId = testId;\n const classes = Array.from(el.classList).filter(isStableClass).slice(0, 5);\n if (classes.length) d.classes = classes;\n if (tag === \"a\") {\n const href = el.getAttribute(\"href\");\n if (href) d.href = href.split(\"#\")[0].split(\"?\")[0].slice(0, 200);\n }\n const nm = el.getAttribute(\"name\");\n if (nm && isField) d.inputName = nm;\n const r = el.getBoundingClientRect?.();\n if (r) d.rect = { x: Math.round(r.x), y: Math.round(r.y), width: Math.round(r.width), height: Math.round(r.height) };\n return d;\n }\n}\n","import type { RecordedAction } from \"../types/events\";\n\nexport type StepType = \"click\" | \"dblclick\" | \"fill\" | \"press\" | \"select\" | \"check\" | \"uncheck\" | \"hover\" | \"drag\" | \"scroll\" | \"navigate\" | \"reload\";\n\nexport interface NormalizedStep {\n type: StepType;\n timestamp: number;\n url: string;\n selector?: string;\n selectorUnique?: boolean;\n selectorCandidates?: RecordedAction[\"selectorCandidates\"];\n element?: RecordedAction[\"element\"];\n coordinates?: { x: number; y: number };\n viewport?: { width: number; height: number };\n args?: Record<string, unknown>;\n expectsNavigation?: { to: string };\n sourceActionIds: string[];\n causedByActionId?: string;\n metadata?: Record<string, unknown>;\n}\n\nconst CLICK_DEDUP_MS = 600;\nconst NAV_AFTER_ACTION_MS = 2500;\n\n/**\n * Converte ações brutas em passos semânticos mínimos, sem perder rastreabilidade:\n * - click, click, dblclick → dblclick\n * - click em checkbox/radio + check → check/uncheck\n * - vários input no mesmo campo → um único fill\n * - input + Enter → fill + press\n * - focus/blur/mousemove/hover isolados são descartados (preservados apenas nos eventos brutos)\n * - scrolls consecutivos no mesmo alvo → um scroll\n * - navigate logo após click/Enter → vira `expectsNavigation` do passo causador\n */\nexport function normalizeActions(actions: readonly RecordedAction[]): NormalizedStep[] {\n const steps: NormalizedStep[] = [];\n const consumed = new Set<string>();\n\n for (let i = 0; i < actions.length; i++) {\n const a = actions[i];\n if (consumed.has(a.id)) continue;\n const base = (type: StepType, args?: Record<string, unknown>, src: string[] = [a.id]): NormalizedStep => ({\n type,\n timestamp: a.timestamp,\n url: a.url,\n selector: a.selector,\n selectorUnique: a.selectorUnique,\n selectorCandidates: a.selectorCandidates,\n element: a.element,\n coordinates: a.coordinates,\n viewport: a.viewport,\n args,\n sourceActionIds: src,\n });\n\n switch (a.type) {\n case \"click\": {\n // clique seguido de check no mesmo elemento (ou no seu input associado)\n const next = actions[i + 1];\n if (next && (next.type === \"check\") && next.timestamp - a.timestamp < 200) {\n consumed.add(next.id);\n const checked = next.payload?.checked !== false;\n steps.push({ ...base(checked ? \"check\" : \"uncheck\", { value: next.payload?.value }, [a.id, next.id]), selector: next.selector ?? a.selector, selectorCandidates: next.selectorCandidates ?? a.selectorCandidates, selectorUnique: next.selectorUnique ?? a.selectorUnique, element: next.element ?? a.element });\n break;\n }\n // click, click, dblclick\n const dbl = findDbl(actions, i);\n if (dbl) {\n for (let j = i; j <= dbl.index; j++) if (actions[j].selector === a.selector && (actions[j].type === \"click\" || actions[j].type === \"dblclick\")) consumed.add(actions[j].id);\n steps.push(base(\"dblclick\", { intervalMs: dbl.action.payload?.intervalMs }, collect(actions, i, dbl.index, a.selector)));\n break;\n }\n // cliques repetidos idênticos em sequência curta permanecem como cliques (intenção do usuário)\n steps.push(base(\"click\", { button: a.payload?.button, modifiers: a.payload?.modifiers }));\n break;\n }\n case \"dblclick\":\n steps.push(base(\"dblclick\", { intervalMs: a.payload?.intervalMs }));\n break;\n case \"check\":\n steps.push(base(a.payload?.checked === false ? \"uncheck\" : \"check\", { value: a.payload?.value }));\n break;\n case \"input\": {\n // último input do mesmo campo sem interrupção por outras ações\n let last = a;\n const src = [a.id];\n for (let j = i + 1; j < actions.length; j++) {\n const n = actions[j];\n if (n.type === \"input\" && n.selector === a.selector) {\n last = n;\n src.push(n.id);\n consumed.add(n.id);\n } else if (n.type === \"focus\" || n.type === \"blur\" || n.type === \"hover\" || n.type === \"mousemove\") continue;\n else break;\n }\n const p = last.payload ?? {};\n steps.push({ ...base(\"fill\", p.valueCaptured ? { value: p.value } : { valueRef: p.valueRef, valueCaptured: false, length: p.length }, src), timestamp: last.timestamp });\n break;\n }\n case \"keydown\": {\n const mods = (a.payload?.modifiers as string[] | undefined) ?? [];\n const key = a.payload?.key as string;\n if (!key) break;\n const held = mods.filter((m) => m !== key && (m !== \"Shift\" || key.length === 1));\n steps.push(base(\"press\", { key: [...held, key].join(\"+\"), code: a.payload?.code }));\n break;\n }\n case \"select\":\n steps.push(base(\"select\", { values: a.payload?.values, labels: a.payload?.labels }));\n break;\n case \"hover\":\n // hover só importa quando é seguido de clique em outro elemento dependente (menus). Mantém enter seguido de click.\n if (a.payload?.phase === \"enter\") {\n const n = actions.slice(i + 1).find((x) => x.type !== \"mousemove\" && x.type !== \"focus\" && x.type !== \"blur\");\n if (n && n.type === \"click\" && n.selector !== a.selector && n.timestamp - a.timestamp < 3000) steps.push(base(\"hover\"));\n }\n break;\n case \"drag\":\n steps.push(base(\"drag\", { from: a.payload?.from, to: a.payload?.to, target: a.payload?.target, trajectory: a.payload?.trajectory, durationMs: a.payload?.durationMs }));\n break;\n case \"scroll\": {\n let last = a;\n const src = [a.id];\n for (let j = i + 1; j < actions.length; j++) {\n const n = actions[j];\n if (n.type === \"scroll\" && n.selector === a.selector && n.payload?.target === a.payload?.target && n.timestamp - last.timestamp < 1500) {\n last = n;\n src.push(n.id);\n consumed.add(n.id);\n } else break;\n }\n steps.push({ ...base(\"scroll\", { from: a.payload?.from, to: last.payload?.to, target: a.payload?.target }, src) });\n break;\n }\n case \"navigate\": {\n const prev = steps[steps.length - 1];\n const to = a.payload?.to as string;\n // Navegação causada pela ação anterior: anexa como expectativa em vez de passo duplicado.\n if (prev && !prev.expectsNavigation && [\"click\", \"press\", \"dblclick\"].includes(prev.type) && a.timestamp - prev.timestamp < NAV_AFTER_ACTION_MS && a.payload?.kind !== \"history\") {\n prev.expectsNavigation = { to };\n prev.sourceActionIds = [...prev.sourceActionIds, a.id];\n } else {\n steps.push(base(\"navigate\", { to, from: a.payload?.from, kind: a.payload?.kind }));\n }\n break;\n }\n case \"reload\":\n steps.push(base(\"reload\", { url: a.payload?.url }));\n break;\n default:\n break; // focus, blur, mousemove\n }\n }\n\n // causedBy: passo seguinte a um clique cuja navegação já foi atribuída\n for (let i = 1; i < steps.length; i++) {\n const prev = steps[i - 1];\n if (prev.expectsNavigation) steps[i].causedByActionId = prev.sourceActionIds[0];\n }\n return steps;\n}\n\nfunction findDbl(actions: readonly RecordedAction[], i: number): { index: number; action: RecordedAction } | null {\n const a = actions[i];\n for (let j = i + 1; j < actions.length && j <= i + 3; j++) {\n const n = actions[j];\n if (n.timestamp - a.timestamp > CLICK_DEDUP_MS) break;\n if (n.type === \"dblclick\" && n.selector === a.selector) return { index: j, action: n };\n if (n.type !== \"click\" || n.selector !== a.selector) break;\n }\n return null;\n}\n\nfunction collect(actions: readonly RecordedAction[], from: number, to: number, selector?: string): string[] {\n const ids: string[] = [];\n for (let j = from; j <= to; j++) if (actions[j].selector === selector) ids.push(actions[j].id);\n return ids;\n}\n","import type { ActionType, ContextEventData, RecordedAction, SelectorCandidate } from \"../types/events\";\nimport { SDK_VERSION } from \"../types/events\";\nimport { normalizeActions, type NormalizedStep } from \"./ActionNormalizer\";\n\n/**\n * Contrato versionado entre o SDK e o futuro motor de automação (serviço externo).\n * O SDK NÃO executa Playwright. Uma reprodução bem-sucedida dos passos não equivale a aprovação do teste:\n * assertions continuam vinculadas aos casos de teste no painel.\n */\nexport const PLAYWRIGHT_CONTRACT_VERSION = \"1.0\";\nexport const PLAYWRIGHT_CONTRACT_KIND = \"offscript.playwright-recording\";\n\nexport interface PlaywrightStep {\n index: number;\n type: NormalizedStep[\"type\"];\n timestamp: number;\n /** Intervalo desde o passo anterior (ms), limitado a 30s. */\n waitBeforeMs: number;\n url: string;\n /** Melhor seletor (sintaxe Playwright) e alternativas em ordem de preferência. */\n selector?: string;\n selectorUnique?: boolean;\n selectorCandidates?: SelectorCandidate[];\n element?: RecordedAction[\"element\"];\n coordinates?: { x: number; y: number };\n viewport?: { width: number; height: number };\n /** Parâmetros do passo (valor permitido, tecla, destino...). Valores sensíveis chegam como `valueRef`. */\n args?: Record<string, unknown>;\n /** Navegação esperada após este passo. */\n expectsNavigation?: { to: string };\n /** Rastreabilidade para investigação: ações brutas que originaram o passo. */\n sourceActionIds: string[];\n causedByActionId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PlaywrightRecording {\n contractVersion: string;\n kind: typeof PLAYWRIGHT_CONTRACT_KIND;\n generatedAt: number;\n sdkVersion: string;\n initialConditions: {\n url?: string;\n viewport?: { width: number; height: number };\n userAgent?: string;\n language?: string;\n timezone?: string;\n deviceScaleFactor?: number;\n browser?: { name?: string; version?: string };\n };\n steps: PlaywrightStep[];\n stats: { rawActions: number; steps: number; merged: number };\n limitations: string[];\n /** Campo livre para extensões compatíveis. */\n extensions?: Record<string, unknown>;\n}\n\nexport const CONTRACT_LIMITATIONS = [\n \"Conteúdo de iframes cross-origin (ex.: seats.io) não é capturado; interações dentro deles não geram passos.\",\n \"Valores de campos não autorizados são substituídos por referências (valueRef) e não podem ser reproduzidos.\",\n \"O contrato descreve ações, não resultados esperados: assertions pertencem aos casos de teste.\",\n];\n\nexport interface BuildInput {\n actions: readonly RecordedAction[];\n contexts?: readonly ContextEventData[];\n extensions?: Record<string, unknown>;\n}\n\n/** Constrói o contrato a partir das ações gravadas. Pode ser usado no navegador ou no backend. */\nexport function buildPlaywrightContract(input: BuildInput): PlaywrightRecording {\n const ordered = [...input.actions].sort((a, b) => a.sequence - b.sequence);\n const steps = normalizeActions(ordered);\n const first = input.contexts?.[0];\n let prev = steps[0]?.timestamp ?? 0;\n const out: PlaywrightStep[] = steps.map((s, i) => {\n const wait = Math.min(30_000, Math.max(0, s.timestamp - prev));\n prev = s.timestamp;\n return {\n index: i,\n type: s.type,\n timestamp: s.timestamp,\n waitBeforeMs: i === 0 ? 0 : wait,\n url: s.url,\n selector: s.selector,\n selectorUnique: s.selectorUnique,\n selectorCandidates: s.selectorCandidates,\n element: s.element,\n coordinates: s.coordinates,\n viewport: s.viewport,\n args: s.args,\n expectsNavigation: s.expectsNavigation,\n sourceActionIds: s.sourceActionIds,\n causedByActionId: s.causedByActionId,\n metadata: s.metadata,\n };\n });\n return {\n contractVersion: PLAYWRIGHT_CONTRACT_VERSION,\n kind: PLAYWRIGHT_CONTRACT_KIND,\n generatedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n initialConditions: {\n url: ordered[0]?.url ?? first?.url,\n viewport: first?.viewport ?? ordered[0]?.viewport,\n userAgent: first?.userAgent,\n language: first?.language,\n timezone: first?.timezone,\n deviceScaleFactor: first?.devicePixelRatio,\n browser: first?.browser,\n },\n steps: out,\n stats: { rawActions: ordered.length, steps: out.length, merged: ordered.length - out.length },\n limitations: CONTRACT_LIMITATIONS,\n extensions: input.extensions,\n };\n}\n\nconst STEP_TYPES: ReadonlySet<string> = new Set([\"click\", \"dblclick\", \"fill\", \"press\", \"select\", \"check\", \"uncheck\", \"hover\", \"drag\", \"scroll\", \"navigate\", \"reload\"]);\n\n/** Validação estrutural do contrato (usada em testes e por consumidores). Retorna a lista de problemas. */\nexport function validatePlaywrightContract(c: unknown): string[] {\n const errors: string[] = [];\n const o = c as Partial<PlaywrightRecording> | null;\n if (!o || typeof o !== \"object\") return [\"contrato ausente\"];\n if (o.kind !== PLAYWRIGHT_CONTRACT_KIND) errors.push(\"kind inválido\");\n if (!o.contractVersion || !/^\\d+\\.\\d+$/.test(o.contractVersion)) errors.push(\"contractVersion inválida\");\n else if (o.contractVersion.split(\".\")[0] !== PLAYWRIGHT_CONTRACT_VERSION.split(\".\")[0]) errors.push(`versão major incompatível: ${o.contractVersion}`);\n if (!Array.isArray(o.steps)) return [...errors, \"steps ausente\"];\n let lastTs = -Infinity;\n o.steps.forEach((s, i) => {\n if (s.index !== i) errors.push(`steps[${i}].index inconsistente`);\n if (!STEP_TYPES.has(s.type)) errors.push(`steps[${i}].type desconhecido: ${s.type}`);\n if (typeof s.timestamp !== \"number\") errors.push(`steps[${i}].timestamp inválido`);\n else if (s.timestamp < lastTs) errors.push(`steps[${i}] fora de ordem`);\n else lastTs = s.timestamp;\n if (!s.sourceActionIds?.length) errors.push(`steps[${i}].sourceActionIds vazio`);\n const needsSelector = ![\"navigate\", \"reload\", \"scroll\"].includes(s.type) || (s.type === \"scroll\" && s.args?.target === \"element\");\n if (needsSelector && !s.selector) errors.push(`steps[${i}] (${s.type}) sem seletor`);\n if (s.type === \"navigate\" && !s.args?.to) errors.push(`steps[${i}] navigate sem destino`);\n });\n return errors;\n}\n\nexport type { ActionType };\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/types/events.ts
|
|
4
4
|
var SCHEMA_VERSION = "1.0";
|
|
5
|
-
var SDK_VERSION = "0.1.
|
|
5
|
+
var SDK_VERSION = "0.1.5";
|
|
6
6
|
var ACTION_SCHEMA_VERSION = "1.0";
|
|
7
7
|
|
|
8
8
|
// src/playwright/SelectorGenerator.ts
|
|
@@ -275,7 +275,8 @@ function normalizeActions(actions) {
|
|
|
275
275
|
const mods = a.payload?.modifiers ?? [];
|
|
276
276
|
const key = a.payload?.key;
|
|
277
277
|
if (!key) break;
|
|
278
|
-
|
|
278
|
+
const held = mods.filter((m) => m !== key && (m !== "Shift" || key.length === 1));
|
|
279
|
+
steps.push(base("press", { key: [...held, key].join("+"), code: a.payload?.code }));
|
|
279
280
|
break;
|
|
280
281
|
}
|
|
281
282
|
case "select":
|
|
@@ -382,7 +383,6 @@ function buildPlaywrightContract(input) {
|
|
|
382
383
|
kind: PLAYWRIGHT_CONTRACT_KIND,
|
|
383
384
|
generatedAt: Date.now(),
|
|
384
385
|
sdkVersion: SDK_VERSION,
|
|
385
|
-
session: input.session,
|
|
386
386
|
initialConditions: {
|
|
387
387
|
url: ordered[0]?.url ?? first?.url,
|
|
388
388
|
viewport: first?.viewport ?? ordered[0]?.viewport,
|
|
@@ -406,7 +406,6 @@ function validatePlaywrightContract(c) {
|
|
|
406
406
|
if (o.kind !== PLAYWRIGHT_CONTRACT_KIND) errors.push("kind inv\xE1lido");
|
|
407
407
|
if (!o.contractVersion || !/^\d+\.\d+$/.test(o.contractVersion)) errors.push("contractVersion inv\xE1lida");
|
|
408
408
|
else if (o.contractVersion.split(".")[0] !== PLAYWRIGHT_CONTRACT_VERSION.split(".")[0]) errors.push(`vers\xE3o major incompat\xEDvel: ${o.contractVersion}`);
|
|
409
|
-
for (const k of ["sessionId", "executionId", "testCaseId", "platformId"]) if (!o.session?.[k]) errors.push(`session.${k} ausente`);
|
|
410
409
|
if (!Array.isArray(o.steps)) return [...errors, "steps ausente"];
|
|
411
410
|
let lastTs = -Infinity;
|
|
412
411
|
o.steps.forEach((s, i) => {
|
|
@@ -438,5 +437,5 @@ exports.isStableId = isStableId;
|
|
|
438
437
|
exports.labelText = labelText;
|
|
439
438
|
exports.normalizeActions = normalizeActions;
|
|
440
439
|
exports.validatePlaywrightContract = validatePlaywrightContract;
|
|
441
|
-
//# sourceMappingURL=chunk-
|
|
442
|
-
//# sourceMappingURL=chunk-
|
|
440
|
+
//# sourceMappingURL=chunk-HPDLEAAL.cjs.map
|
|
441
|
+
//# sourceMappingURL=chunk-HPDLEAAL.cjs.map
|