@xera-ai/web 0.2.1 → 0.8.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/dist/index.js CHANGED
@@ -1,6 +1,21 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
+ // src/index.ts
5
+ import {
6
+ CREDIT_CARD_RE,
7
+ EMAIL_RE,
8
+ EMAIL_RE_G,
9
+ JWT_RE,
10
+ PHONE_RE,
11
+ PHONE_RE_G,
12
+ SENSITIVE_BODY_KEYS,
13
+ SENSITIVE_HEADERS,
14
+ scrubBodyJson as scrubBodyJson2,
15
+ scrubFreeText as scrubFreeText2,
16
+ scrubHeaders as scrubHeaders2
17
+ } from "@xera-ai/core";
18
+
4
19
  // src/adapter.ts
5
20
  import { join as join3 } from "path";
6
21
 
@@ -86,68 +101,8 @@ function parsePlaywrightReport(report, runId) {
86
101
  };
87
102
  }
88
103
 
89
- // src/trace-normalizer/scrub-rules.ts
90
- var SENSITIVE_HEADERS = [
91
- "authorization",
92
- "cookie",
93
- "set-cookie",
94
- "x-api-key",
95
- "x-auth-token",
96
- "x-csrf-token",
97
- "proxy-authorization"
98
- ];
99
- var SENSITIVE_BODY_KEYS = [
100
- /password/i,
101
- /passwd/i,
102
- /token/i,
103
- /secret/i,
104
- /api[-_]?key/i,
105
- /access[-_]?key/i,
106
- /private[-_]?key/i,
107
- /authorization/i,
108
- /credit[-_]?card/i,
109
- /card[-_]?number/i,
110
- /cvv/i
111
- ];
112
- var JWT_RE = /\beyJ[A-Za-z0-9_-]{7,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{5,}\b/;
113
- var CREDIT_CARD_RE = /\b(?:\d{4}[-\s]?){3}\d{4}\b/;
114
- var EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
115
- var PHONE_RE = /(?:\+?\d[\d\s().-]{6,}\d)/;
116
- var JWT_RE_G = new RegExp(JWT_RE.source, "g");
117
- var CREDIT_CARD_RE_G = new RegExp(CREDIT_CARD_RE.source, "g");
118
- var EMAIL_RE_G = new RegExp(EMAIL_RE.source, "g");
119
- var PHONE_RE_G = new RegExp(PHONE_RE.source, "g");
120
- var REDACTED = "[REDACTED]";
121
- function scrubHeaders(headers) {
122
- const out = {};
123
- for (const [k, v] of Object.entries(headers)) {
124
- out[k] = SENSITIVE_HEADERS.includes(k.toLowerCase()) ? REDACTED : v;
125
- }
126
- return out;
127
- }
128
- function scrubBodyJson(body) {
129
- if (Array.isArray(body))
130
- return body.map(scrubBodyJson);
131
- if (body && typeof body === "object") {
132
- const out = {};
133
- for (const [k, v] of Object.entries(body)) {
134
- if (SENSITIVE_BODY_KEYS.some((re) => re.test(k))) {
135
- out[k] = REDACTED;
136
- } else {
137
- out[k] = scrubBodyJson(v);
138
- }
139
- }
140
- return out;
141
- }
142
- if (typeof body === "string")
143
- return scrubFreeText(body);
144
- return body;
145
- }
146
- function scrubFreeText(s) {
147
- return s.replace(JWT_RE_G, REDACTED).replace(CREDIT_CARD_RE_G, REDACTED).replace(EMAIL_RE_G, REDACTED).replace(PHONE_RE_G, REDACTED);
148
- }
149
-
150
104
  // src/trace-normalizer/scrub.ts
105
+ import { scrubBodyJson, scrubFreeText, scrubHeaders } from "@xera-ai/core";
151
106
  function countScrubbed(before, after) {
152
107
  if (typeof before === "string" && typeof after === "string")
153
108
  return before !== after ? 1 : 0;
@@ -532,9 +487,9 @@ export {
532
487
  unzipTrace,
533
488
  typecheckTicket,
534
489
  stagePlaywrightState,
535
- scrubHeaders,
536
- scrubFreeText,
537
- scrubBodyJson,
490
+ scrubHeaders2 as scrubHeaders,
491
+ scrubFreeText2 as scrubFreeText,
492
+ scrubBodyJson2 as scrubBodyJson,
538
493
  scrub,
539
494
  scanSharedPoms,
540
495
  runPlaywright,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xera-ai/web",
3
- "version": "0.2.1",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -17,13 +17,14 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "bun build ./src/index.ts --outdir ./dist --target bun --external @playwright/test --external @xera-ai/core --external @cucumber/gherkin --external @cucumber/messages --external fflate",
20
- "typecheck": "tsc --noEmit"
20
+ "typecheck": "tsc --noEmit",
21
+ "prepublishOnly": "bun run build"
21
22
  },
22
23
  "dependencies": {
23
24
  "@cucumber/gherkin": "39.1.0",
24
25
  "@cucumber/messages": "32.3.1",
25
26
  "@playwright/test": "1.60.0",
26
- "@xera-ai/core": "^0.4.0",
27
+ "@xera-ai/core": "^0.8.0",
27
28
  "fflate": "0.8.3"
28
29
  }
29
30
  }
package/src/index.ts CHANGED
@@ -1,3 +1,16 @@
1
+ export {
2
+ CREDIT_CARD_RE,
3
+ EMAIL_RE,
4
+ EMAIL_RE_G,
5
+ JWT_RE,
6
+ PHONE_RE,
7
+ PHONE_RE_G,
8
+ SENSITIVE_BODY_KEYS,
9
+ SENSITIVE_HEADERS,
10
+ scrubBodyJson,
11
+ scrubFreeText,
12
+ scrubHeaders,
13
+ } from '@xera-ai/core';
1
14
  export * from './adapter';
2
15
  export * from './auth-setup/define';
3
16
  export * from './auth-setup/playwright-state';
@@ -13,5 +26,4 @@ export * from './generator/typecheck';
13
26
  export * from './trace-normalizer/normalize';
14
27
  export * from './trace-normalizer/parse';
15
28
  export * from './trace-normalizer/scrub';
16
- export * from './trace-normalizer/scrub-rules';
17
29
  export * from './trace-normalizer/unzip';
@@ -1,4 +1,4 @@
1
- import { scrubBodyJson, scrubFreeText, scrubHeaders } from './scrub-rules';
1
+ import { scrubBodyJson, scrubFreeText, scrubHeaders } from '@xera-ai/core';
2
2
 
3
3
  export interface NormalizedNetworkEntry {
4
4
  method: string;
package/dist/adapter.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import type { TestAdapter } from '@xera-ai/core/adapter';
2
- export declare const WebAdapter: TestAdapter;
@@ -1,15 +0,0 @@
1
- import type { Page } from '@playwright/test';
2
- export interface AuthRoleCreds {
3
- email: string;
4
- password: string;
5
- }
6
- export interface AuthSetupResult {
7
- /** Optional explicit expiry hint, ms since epoch. */
8
- expiresAt?: number;
9
- }
10
- export type AuthSetupFn = (page: Page, role: string, creds: AuthRoleCreds) => Promise<AuthSetupResult | void>;
11
- /**
12
- * Helper to type-narrow the user's auth setup function. Users import this in
13
- * `shared/auth-setup.ts`.
14
- */
15
- export declare function defineAuthSetup(fn: AuthSetupFn): AuthSetupFn;
@@ -1 +0,0 @@
1
- export declare function stagePlaywrightState(authDir: string, role: string): string;
@@ -1,11 +0,0 @@
1
- import type { Browser } from '@playwright/test';
2
- import type { AuthRoleCreds } from './define';
3
- export interface RunAuthSetupInput {
4
- role: string;
5
- creds: AuthRoleCreds;
6
- setupScriptPath: string;
7
- authDir: string;
8
- browser: Browser;
9
- now?: Date;
10
- }
11
- export declare function runAuthSetup(input: RunAuthSetupInput): Promise<void>;
@@ -1,18 +0,0 @@
1
- export interface SpawnResult {
2
- exitCode: number;
3
- }
4
- export type SpawnFn = (cmd: string, args: string[], env: NodeJS.ProcessEnv) => Promise<SpawnResult>;
5
- export interface RunPlaywrightInput {
6
- specPath: string;
7
- configPath: string;
8
- outputDir: string;
9
- grep?: string;
10
- env?: NodeJS.ProcessEnv;
11
- spawn?: SpawnFn;
12
- }
13
- export interface RunPlaywrightResult {
14
- outcome: 'PASS' | 'FAIL';
15
- rawReportPath: string;
16
- exitCode: number;
17
- }
18
- export declare function runPlaywright(input: RunPlaywrightInput): Promise<RunPlaywrightResult>;
@@ -1,7 +0,0 @@
1
- export interface PlaywrightArgsInput {
2
- specPath: string;
3
- outputDir: string;
4
- configPath: string;
5
- grep?: string;
6
- }
7
- export declare function buildPlaywrightArgs(input: PlaywrightArgsInput): string[];
@@ -1,8 +0,0 @@
1
- export interface GherkinValidateResult {
2
- ok: boolean;
3
- errors: Array<{
4
- line: number;
5
- message: string;
6
- }>;
7
- }
8
- export declare function validateGherkin(content: string): GherkinValidateResult;
@@ -1,8 +0,0 @@
1
- import { type SelectorWarning } from './selector-rules';
2
- export interface LintResult {
3
- ok: boolean;
4
- warnings: Array<SelectorWarning & {
5
- file: string;
6
- }>;
7
- }
8
- export declare function lintTicket(ticketDir: string): Promise<LintResult>;
@@ -1,5 +0,0 @@
1
- export interface SharedPom {
2
- className: string;
3
- absolutePath: string;
4
- }
5
- export declare function scanSharedPoms(repoRoot: string): SharedPom[];
@@ -1,6 +0,0 @@
1
- export interface PromoteInput {
2
- repoRoot: string;
3
- ticket: string;
4
- className: string;
5
- }
6
- export declare function promotePom(input: PromoteInput): Promise<void>;
@@ -1,9 +0,0 @@
1
- export interface SelectorWarning {
2
- rule: 'no-auto-classname' | 'prefer-role-over-css' | 'no-xpath';
3
- line: number;
4
- text: string;
5
- message: string;
6
- }
7
- export declare function lintSelectors(source: string): {
8
- warnings: SelectorWarning[];
9
- };
@@ -1,10 +0,0 @@
1
- export interface TypecheckResult {
2
- ok: boolean;
3
- errors: string[];
4
- }
5
- /**
6
- * Type-check the ticket's TypeScript files using the project's root tsconfig.
7
- * Errors are filtered to those whose path contains the ticket directory, so the
8
- * skill sees only the locally relevant ones.
9
- */
10
- export declare function typecheckTicket(ticketDir: string): Promise<TypecheckResult>;
package/dist/index.d.ts DELETED
@@ -1,17 +0,0 @@
1
- export * from './adapter';
2
- export * from './auth-setup/define';
3
- export * from './auth-setup/playwright-state';
4
- export * from './auth-setup/runner';
5
- export * from './executor';
6
- export * from './executor/playwright-args';
7
- export * from './generator/gherkin-validate';
8
- export * from './generator/lint';
9
- export * from './generator/pom-scan';
10
- export * from './generator/promote';
11
- export * from './generator/selector-rules';
12
- export * from './generator/typecheck';
13
- export * from './trace-normalizer/normalize';
14
- export * from './trace-normalizer/parse';
15
- export * from './trace-normalizer/scrub';
16
- export * from './trace-normalizer/scrub-rules';
17
- export * from './trace-normalizer/unzip';
@@ -1,6 +0,0 @@
1
- import { type NormalizedRun } from './scrub';
2
- export interface NormalizeRunInput {
3
- runId: string;
4
- runDir: string;
5
- }
6
- export declare function normalizeRun(input: NormalizeRunInput): Promise<NormalizedRun>;
@@ -1,36 +0,0 @@
1
- import type { NormalizedRun } from './scrub';
2
- interface PWAttachment {
3
- name: string;
4
- path?: string;
5
- contentType?: string;
6
- }
7
- interface PWResult {
8
- status: string;
9
- duration: number;
10
- error?: {
11
- message?: string;
12
- stack?: string;
13
- };
14
- attachments?: PWAttachment[];
15
- }
16
- interface PWTest {
17
- results: PWResult[];
18
- }
19
- interface PWSpec {
20
- title: string;
21
- ok: boolean;
22
- tests: PWTest[];
23
- }
24
- interface PWSuite {
25
- title: string;
26
- specs?: PWSpec[];
27
- suites?: PWSuite[];
28
- }
29
- interface PWReport {
30
- stats: {
31
- unexpected: number;
32
- };
33
- suites: PWSuite[];
34
- }
35
- export declare function parsePlaywrightReport(report: PWReport, runId: string): NormalizedRun;
36
- export {};
@@ -1,11 +0,0 @@
1
- export declare const SENSITIVE_HEADERS: readonly string[];
2
- export declare const SENSITIVE_BODY_KEYS: readonly RegExp[];
3
- export declare const JWT_RE: RegExp;
4
- export declare const CREDIT_CARD_RE: RegExp;
5
- export declare const EMAIL_RE: RegExp;
6
- export declare const PHONE_RE: RegExp;
7
- export declare const EMAIL_RE_G: RegExp;
8
- export declare const PHONE_RE_G: RegExp;
9
- export declare function scrubHeaders(headers: Record<string, string>): Record<string, string>;
10
- export declare function scrubBodyJson(body: unknown): unknown;
11
- export declare function scrubFreeText(s: string): string;
@@ -1,28 +0,0 @@
1
- export interface NormalizedNetworkEntry {
2
- method: string;
3
- url: string;
4
- status: number;
5
- requestHeaders?: Record<string, string>;
6
- requestBody?: unknown;
7
- responseHeaders?: Record<string, string>;
8
- responseBody?: unknown;
9
- }
10
- export interface NormalizedScenario {
11
- name: string;
12
- outcome: 'PASS' | 'FAIL' | 'SKIPPED';
13
- failure?: {
14
- step?: string;
15
- errorMessage?: string;
16
- domSnapshotAtFailure?: string;
17
- networkAtFailure?: NormalizedNetworkEntry[];
18
- consoleAtFailure?: string[];
19
- screenshotPath?: string;
20
- };
21
- }
22
- export interface NormalizedRun {
23
- runId: string;
24
- outcome: 'PASS' | 'FAIL';
25
- scenarios: NormalizedScenario[];
26
- scrubbed_fields_count: number;
27
- }
28
- export declare function scrub(run: NormalizedRun): NormalizedRun;
@@ -1,5 +0,0 @@
1
- export interface TraceEntries {
2
- /** Filename → text contents */
3
- files: Record<string, string>;
4
- }
5
- export declare function unzipTrace(tracePath: string): TraceEntries;
@@ -1,69 +0,0 @@
1
- export const SENSITIVE_HEADERS: readonly string[] = [
2
- 'authorization',
3
- 'cookie',
4
- 'set-cookie',
5
- 'x-api-key',
6
- 'x-auth-token',
7
- 'x-csrf-token',
8
- 'proxy-authorization',
9
- ];
10
-
11
- export const SENSITIVE_BODY_KEYS: readonly RegExp[] = [
12
- /password/i,
13
- /passwd/i,
14
- /token/i,
15
- /secret/i,
16
- /api[-_]?key/i,
17
- /access[-_]?key/i,
18
- /private[-_]?key/i,
19
- /authorization/i,
20
- /credit[-_]?card/i,
21
- /card[-_]?number/i,
22
- /cvv/i,
23
- ];
24
-
25
- export const JWT_RE = /\beyJ[A-Za-z0-9_-]{7,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{5,}\b/;
26
- export const CREDIT_CARD_RE = /\b(?:\d{4}[-\s]?){3}\d{4}\b/;
27
- export const EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
28
- // E.164-ish phone with optional + and separators. Conservative: require at least 7 digits.
29
- export const PHONE_RE = /(?:\+?\d[\d\s().-]{6,}\d)/;
30
-
31
- const JWT_RE_G = new RegExp(JWT_RE.source, 'g');
32
- const CREDIT_CARD_RE_G = new RegExp(CREDIT_CARD_RE.source, 'g');
33
- export const EMAIL_RE_G = new RegExp(EMAIL_RE.source, 'g');
34
- export const PHONE_RE_G = new RegExp(PHONE_RE.source, 'g');
35
-
36
- const REDACTED = '[REDACTED]';
37
-
38
- export function scrubHeaders(headers: Record<string, string>): Record<string, string> {
39
- const out: Record<string, string> = {};
40
- for (const [k, v] of Object.entries(headers)) {
41
- out[k] = SENSITIVE_HEADERS.includes(k.toLowerCase()) ? REDACTED : v;
42
- }
43
- return out;
44
- }
45
-
46
- export function scrubBodyJson(body: unknown): unknown {
47
- if (Array.isArray(body)) return body.map(scrubBodyJson);
48
- if (body && typeof body === 'object') {
49
- const out: Record<string, unknown> = {};
50
- for (const [k, v] of Object.entries(body)) {
51
- if (SENSITIVE_BODY_KEYS.some((re) => re.test(k))) {
52
- out[k] = REDACTED;
53
- } else {
54
- out[k] = scrubBodyJson(v);
55
- }
56
- }
57
- return out;
58
- }
59
- if (typeof body === 'string') return scrubFreeText(body);
60
- return body;
61
- }
62
-
63
- export function scrubFreeText(s: string): string {
64
- return s
65
- .replace(JWT_RE_G, REDACTED)
66
- .replace(CREDIT_CARD_RE_G, REDACTED)
67
- .replace(EMAIL_RE_G, REDACTED)
68
- .replace(PHONE_RE_G, REDACTED);
69
- }