@emesoft_company/playwright-core 2.1.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.
Files changed (92) hide show
  1. package/README.md +62 -0
  2. package/dist/api/index.cjs +248 -0
  3. package/dist/api/index.cjs.map +1 -0
  4. package/dist/api/index.d.cts +12 -0
  5. package/dist/api/index.d.ts +12 -0
  6. package/dist/api/index.js +245 -0
  7. package/dist/api/index.js.map +1 -0
  8. package/dist/api-client-C_StjpPX.d.ts +58 -0
  9. package/dist/api-client-CpXo_NOU.d.cts +58 -0
  10. package/dist/auth/index.cjs +310 -0
  11. package/dist/auth/index.cjs.map +1 -0
  12. package/dist/auth/index.d.cts +98 -0
  13. package/dist/auth/index.d.ts +98 -0
  14. package/dist/auth/index.js +304 -0
  15. package/dist/auth/index.js.map +1 -0
  16. package/dist/config/index.cjs +268 -0
  17. package/dist/config/index.cjs.map +1 -0
  18. package/dist/config/index.d.cts +105 -0
  19. package/dist/config/index.d.ts +105 -0
  20. package/dist/config/index.js +254 -0
  21. package/dist/config/index.js.map +1 -0
  22. package/dist/data/index.cjs +59 -0
  23. package/dist/data/index.cjs.map +1 -0
  24. package/dist/data/index.d.cts +25 -0
  25. package/dist/data/index.d.ts +25 -0
  26. package/dist/data/index.js +50 -0
  27. package/dist/data/index.js.map +1 -0
  28. package/dist/di/index.cjs +47 -0
  29. package/dist/di/index.cjs.map +1 -0
  30. package/dist/di/index.d.cts +19 -0
  31. package/dist/di/index.d.ts +19 -0
  32. package/dist/di/index.js +45 -0
  33. package/dist/di/index.js.map +1 -0
  34. package/dist/errors/index.cjs +90 -0
  35. package/dist/errors/index.cjs.map +1 -0
  36. package/dist/errors/index.d.cts +38 -0
  37. package/dist/errors/index.d.ts +38 -0
  38. package/dist/errors/index.js +83 -0
  39. package/dist/errors/index.js.map +1 -0
  40. package/dist/expect/index.cjs +36 -0
  41. package/dist/expect/index.cjs.map +1 -0
  42. package/dist/expect/index.d.cts +30 -0
  43. package/dist/expect/index.d.ts +30 -0
  44. package/dist/expect/index.js +34 -0
  45. package/dist/expect/index.js.map +1 -0
  46. package/dist/fixtures/index.cjs +660 -0
  47. package/dist/fixtures/index.cjs.map +1 -0
  48. package/dist/fixtures/index.d.cts +68 -0
  49. package/dist/fixtures/index.d.ts +68 -0
  50. package/dist/fixtures/index.js +651 -0
  51. package/dist/fixtures/index.js.map +1 -0
  52. package/dist/index.cjs +1322 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.cts +21 -0
  55. package/dist/index.d.ts +21 -0
  56. package/dist/index.js +1248 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/logging/index.cjs +32 -0
  59. package/dist/logging/index.cjs.map +1 -0
  60. package/dist/logging/index.d.cts +18 -0
  61. package/dist/logging/index.d.ts +18 -0
  62. package/dist/logging/index.js +25 -0
  63. package/dist/logging/index.js.map +1 -0
  64. package/dist/reporting/index.cjs +59 -0
  65. package/dist/reporting/index.cjs.map +1 -0
  66. package/dist/reporting/index.d.cts +63 -0
  67. package/dist/reporting/index.d.ts +63 -0
  68. package/dist/reporting/index.js +52 -0
  69. package/dist/reporting/index.js.map +1 -0
  70. package/dist/retry-XqnSC8YL.d.cts +27 -0
  71. package/dist/retry-XqnSC8YL.d.ts +27 -0
  72. package/dist/schema-y5w2hbT-.d.cts +292 -0
  73. package/dist/schema-y5w2hbT-.d.ts +292 -0
  74. package/dist/types-CbWnSYEK.d.cts +5 -0
  75. package/dist/types-CbWnSYEK.d.ts +5 -0
  76. package/dist/types-CopwwpSW.d.cts +8 -0
  77. package/dist/types-CopwwpSW.d.ts +8 -0
  78. package/dist/types-hInbkPXf.d.cts +59 -0
  79. package/dist/types-hInbkPXf.d.ts +59 -0
  80. package/dist/ui/index.cjs +366 -0
  81. package/dist/ui/index.cjs.map +1 -0
  82. package/dist/ui/index.d.cts +190 -0
  83. package/dist/ui/index.d.ts +190 -0
  84. package/dist/ui/index.js +348 -0
  85. package/dist/ui/index.js.map +1 -0
  86. package/dist/utils/index.cjs +72 -0
  87. package/dist/utils/index.cjs.map +1 -0
  88. package/dist/utils/index.d.cts +27 -0
  89. package/dist/utils/index.d.ts +27 -0
  90. package/dist/utils/index.js +66 -0
  91. package/dist/utils/index.js.map +1 -0
  92. package/package.json +133 -0
@@ -0,0 +1,98 @@
1
+ import { T as TokenProvider } from '../types-CopwwpSW.js';
2
+ import { Logger } from 'pino';
3
+ import { Page, BrowserContextOptions, chromium } from '@playwright/test';
4
+ import { A as AppConfig } from '../schema-y5w2hbT-.js';
5
+ import { D as DeepPartial } from '../types-CbWnSYEK.js';
6
+ import 'zod';
7
+
8
+ /** Token provider that always returns a fixed token. Useful for tests/local dev with a pre-issued token. */
9
+ declare class StaticTokenProvider implements TokenProvider {
10
+ private readonly token;
11
+ constructor(token: string);
12
+ getToken(): Promise<string>;
13
+ invalidate(): void;
14
+ }
15
+ /** No-op provider for endpoints that don't require authentication. */
16
+ declare class NullTokenProvider implements TokenProvider {
17
+ getToken(): Promise<string>;
18
+ invalidate(): void;
19
+ }
20
+ interface JwtTokenProviderOptions {
21
+ tokenUrl: string;
22
+ clientId?: string;
23
+ clientSecret?: string;
24
+ username?: string;
25
+ password?: string;
26
+ /** Seconds subtracted from the token's `expires_in` to refresh proactively. Default: 30. */
27
+ refreshSkewSeconds?: number;
28
+ logger?: Logger;
29
+ fetchImpl?: typeof fetch;
30
+ }
31
+ /**
32
+ * JWT/OAuth2 token provider supporting client-credentials or password grants.
33
+ * Caches the token in-memory and transparently refreshes it before expiry.
34
+ */
35
+ declare class JwtTokenProvider implements TokenProvider {
36
+ private readonly options;
37
+ private cached?;
38
+ private inFlight?;
39
+ constructor(options: JwtTokenProviderOptions);
40
+ getToken(): Promise<string>;
41
+ invalidate(): void;
42
+ private fetchToken;
43
+ }
44
+
45
+ type LoginFn = (page: Page, config: AppConfig) => Promise<void>;
46
+ interface RoleSetup {
47
+ /** Performs this role's login; storage state is captured right after it returns. */
48
+ login: LoginFn;
49
+ /** Defaults to `<auth.storageStateDir>/<role>.json`. */
50
+ storageStatePath?: string;
51
+ /** Per-role context options, falling back to the top-level `contextOptions`. */
52
+ contextOptions?: BrowserContextOptions;
53
+ }
54
+ interface GlobalSetupOptions {
55
+ /**
56
+ * Single-session login. Storage state goes to `auth.storageStatePath`.
57
+ * Mutually exclusive with `roles`.
58
+ */
59
+ login?: LoginFn;
60
+ /**
61
+ * Multi-role login — one storage state file per role, so tests can pick who they run as
62
+ * with `test.use({ storageState: roleStorageState("admin") })`.
63
+ */
64
+ roles?: Record<string, RoleSetup>;
65
+ configOverrides?: DeepPartial<AppConfig>;
66
+ /**
67
+ * Context options (e.g. `devices["Desktop Chrome"]`) to log in with. Pass the SAME options
68
+ * your test projects run with — some apps tie a session to fingerprint details like
69
+ * User-Agent, so logging in under different context options than the tests that reuse the
70
+ * session can silently invalidate it server-side.
71
+ */
72
+ contextOptions?: BrowserContextOptions;
73
+ /**
74
+ * Options for `chromium.launch()` — e.g. `{ headless: false }`. Defaults to Playwright's own
75
+ * default (headless). Some apps never finish loading/rendering in headless mode (confirmed
76
+ * for real against a staging target in `bec.e2e`); pass `headless: false` here instead of
77
+ * writing a custom `global-setup.ts` from scratch just to change this one thing.
78
+ */
79
+ launchOptions?: Parameters<typeof chromium.launch>[0];
80
+ }
81
+ /**
82
+ * Path of a role's storage state file. Use the same role names here as in
83
+ * `buildGlobalSetup({ roles })` so tests and setup agree:
84
+ *
85
+ * ```ts
86
+ * test.use({ storageState: roleStorageState("admin") });
87
+ * ```
88
+ */
89
+ declare function roleStorageState(role: string, storageStateDir?: string): string;
90
+ /**
91
+ * Builds a Playwright `globalSetup` function that logs in once and persists the resulting
92
+ * storage state, so per-test runs reuse an authenticated session instead of logging in for
93
+ * every test. Wire the returned function into `playwright.config.ts`'s `globalSetup` option.
94
+ * See `docs/EXTENDING.md`.
95
+ */
96
+ declare function buildGlobalSetup(options: GlobalSetupOptions): () => Promise<void>;
97
+
98
+ export { type GlobalSetupOptions, JwtTokenProvider, type JwtTokenProviderOptions, type LoginFn, NullTokenProvider, type RoleSetup, StaticTokenProvider, TokenProvider, buildGlobalSetup, roleStorageState };
@@ -0,0 +1,304 @@
1
+ import { mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { chromium } from '@playwright/test';
4
+ import { z } from 'zod';
5
+
6
+ // src/errors/app-error.ts
7
+ var AppError = class extends Error {
8
+ code;
9
+ context;
10
+ constructor(message, options) {
11
+ super(message, { cause: options.cause });
12
+ this.name = new.target.name;
13
+ this.code = options.code;
14
+ this.context = options.context;
15
+ Object.setPrototypeOf(this, new.target.prototype);
16
+ }
17
+ };
18
+ var ConfigValidationError = class extends AppError {
19
+ constructor(message, issues, context) {
20
+ super(message, { code: "CONFIG_VALIDATION_ERROR", context: { issues, ...context } });
21
+ }
22
+ };
23
+ var AuthError = class extends AppError {
24
+ constructor(message, options = {}) {
25
+ super(message, { code: "AUTH_ERROR", ...options });
26
+ }
27
+ };
28
+
29
+ // src/auth/token-provider.ts
30
+ var StaticTokenProvider = class {
31
+ constructor(token) {
32
+ this.token = token;
33
+ }
34
+ token;
35
+ async getToken() {
36
+ return this.token;
37
+ }
38
+ invalidate() {
39
+ }
40
+ };
41
+ var NullTokenProvider = class {
42
+ async getToken() {
43
+ return "";
44
+ }
45
+ invalidate() {
46
+ }
47
+ };
48
+ var JwtTokenProvider = class {
49
+ constructor(options) {
50
+ this.options = options;
51
+ }
52
+ options;
53
+ cached;
54
+ inFlight;
55
+ async getToken() {
56
+ if (this.cached && this.cached.expiresAt > Date.now()) {
57
+ return this.cached.token;
58
+ }
59
+ if (!this.inFlight) {
60
+ this.inFlight = this.fetchToken().finally(() => {
61
+ this.inFlight = void 0;
62
+ });
63
+ }
64
+ return this.inFlight;
65
+ }
66
+ invalidate() {
67
+ this.cached = void 0;
68
+ }
69
+ async fetchToken() {
70
+ const { tokenUrl, clientId, clientSecret, username, password, refreshSkewSeconds = 30, logger, fetchImpl = fetch } = this.options;
71
+ const body = new URLSearchParams();
72
+ if (username && password) {
73
+ body.set("grant_type", "password");
74
+ body.set("username", username);
75
+ body.set("password", password);
76
+ } else {
77
+ body.set("grant_type", "client_credentials");
78
+ }
79
+ if (clientId) body.set("client_id", clientId);
80
+ if (clientSecret) body.set("client_secret", clientSecret);
81
+ logger?.debug({ tokenUrl }, "fetching auth token");
82
+ let response;
83
+ try {
84
+ response = await fetchImpl(tokenUrl, {
85
+ method: "POST",
86
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
87
+ body
88
+ });
89
+ } catch (cause) {
90
+ throw new AuthError(`Failed to reach token endpoint ${tokenUrl}`, { cause });
91
+ }
92
+ if (!response.ok) {
93
+ const text = await response.text().catch(() => "");
94
+ throw new AuthError(`Token endpoint returned ${response.status}: ${text}`, {
95
+ context: { status: response.status, tokenUrl }
96
+ });
97
+ }
98
+ const data = await response.json();
99
+ if (!data.access_token) {
100
+ throw new AuthError("Token endpoint response missing access_token", { context: { tokenUrl } });
101
+ }
102
+ const expiresInSeconds = data.expires_in ?? 300;
103
+ this.cached = {
104
+ token: data.access_token,
105
+ expiresAt: Date.now() + Math.max(expiresInSeconds - refreshSkewSeconds, 0) * 1e3
106
+ };
107
+ return this.cached.token;
108
+ }
109
+ };
110
+
111
+ // src/utils/deep-merge.ts
112
+ function isPlainObject(value) {
113
+ return typeof value === "object" && value !== null && !Array.isArray(value);
114
+ }
115
+ function deepMerge(base, override) {
116
+ if (override === void 0) return base;
117
+ if (!isPlainObject(base) || !isPlainObject(override)) {
118
+ return override;
119
+ }
120
+ const result = { ...base };
121
+ for (const [key, value] of Object.entries(override)) {
122
+ if (value === void 0) continue;
123
+ const baseValue = base[key];
124
+ result[key] = isPlainObject(baseValue) && isPlainObject(value) ? deepMerge(baseValue, value) : value;
125
+ }
126
+ return result;
127
+ }
128
+ function pruneUndefined(value) {
129
+ if (Array.isArray(value)) return value.map(pruneUndefined);
130
+ if (isPlainObject(value)) {
131
+ const result = {};
132
+ for (const [key, val] of Object.entries(value)) {
133
+ if (val === void 0) continue;
134
+ const pruned = pruneUndefined(val);
135
+ if (isPlainObject(pruned) && Object.keys(pruned).length === 0) continue;
136
+ result[key] = pruned;
137
+ }
138
+ return result;
139
+ }
140
+ return value;
141
+ }
142
+ var EnvironmentSchema = z.string().min(1);
143
+ var TimeoutsSchema = z.object({
144
+ actionMs: z.number().int().positive().default(15e3),
145
+ navigationMs: z.number().int().positive().default(3e4),
146
+ testMs: z.number().int().positive().default(6e4),
147
+ /** Default budget for `waitForCondition` and other non-locator polling. */
148
+ waitMs: z.number().int().positive().default(3e4)
149
+ });
150
+ var AuthConfigSchema = z.object({
151
+ tokenUrl: z.string().url().optional(),
152
+ clientId: z.string().optional(),
153
+ clientSecret: z.string().optional(),
154
+ username: z.string().optional(),
155
+ password: z.string().optional(),
156
+ /** Single-session storage state file (see `buildGlobalSetup`). */
157
+ storageStatePath: z.string().optional(),
158
+ /** Directory used for per-role storage state files in multi-role setups. */
159
+ storageStateDir: z.string().default(".auth")
160
+ }).default({});
161
+ var ReportingConfigSchema = z.object({
162
+ allureEnabled: z.boolean().default(false),
163
+ resultsDir: z.string().default("allure-results"),
164
+ /** `{id}` is replaced with a test-case id — see `meta()` in `@emesoft_company/playwright-core/reporting`. */
165
+ testCaseUrlTemplate: z.string().optional()
166
+ }).default({});
167
+ var RetryConfigSchema = z.object({
168
+ retries: z.number().int().min(0).default(2),
169
+ minDelayMs: z.number().int().positive().default(200),
170
+ maxDelayMs: z.number().int().positive().default(5e3)
171
+ }).default({});
172
+ var DiagnosticsConfigSchema = z.object({
173
+ /** Collect browser console errors + failed requests and attach them to the report. */
174
+ enabled: z.boolean().default(true),
175
+ /** Fail the test if the page logged a console error. Off by default — many apps are noisy. */
176
+ failOnConsoleError: z.boolean().default(false),
177
+ /** Fail the test on an uncaught page exception. */
178
+ failOnPageError: z.boolean().default(false),
179
+ /** Console messages matching any of these substrings are ignored entirely. */
180
+ ignoreConsolePatterns: z.array(z.string()).default([])
181
+ }).default({});
182
+ var AppConfigSchema = z.object({
183
+ environment: EnvironmentSchema,
184
+ baseUrl: z.string().url(),
185
+ apiBaseUrl: z.string().url().optional(),
186
+ tenant: z.string().optional(),
187
+ timeouts: TimeoutsSchema.default({}),
188
+ auth: AuthConfigSchema,
189
+ reporting: ReportingConfigSchema,
190
+ retry: RetryConfigSchema,
191
+ diagnostics: DiagnosticsConfigSchema,
192
+ logLevel: z.enum(["fatal", "error", "warn", "info", "debug", "trace", "silent"]).default("info"),
193
+ custom: z.record(z.string(), z.unknown()).default({})
194
+ });
195
+
196
+ // src/config/loader.ts
197
+ function readEnvConfig(env) {
198
+ return {
199
+ environment: env.TEST_ENV ?? "dev",
200
+ baseUrl: env.BASE_URL,
201
+ apiBaseUrl: env.API_BASE_URL,
202
+ tenant: env.TENANT,
203
+ logLevel: env.LOG_LEVEL,
204
+ timeouts: {
205
+ actionMs: env.ACTION_TIMEOUT_MS ? Number(env.ACTION_TIMEOUT_MS) : void 0,
206
+ navigationMs: env.NAVIGATION_TIMEOUT_MS ? Number(env.NAVIGATION_TIMEOUT_MS) : void 0,
207
+ testMs: env.TEST_TIMEOUT_MS ? Number(env.TEST_TIMEOUT_MS) : void 0,
208
+ waitMs: env.WAIT_TIMEOUT_MS ? Number(env.WAIT_TIMEOUT_MS) : void 0
209
+ },
210
+ auth: {
211
+ tokenUrl: env.AUTH_TOKEN_URL,
212
+ clientId: env.AUTH_CLIENT_ID,
213
+ clientSecret: env.AUTH_CLIENT_SECRET,
214
+ username: env.AUTH_USERNAME,
215
+ password: env.AUTH_PASSWORD,
216
+ storageStatePath: env.AUTH_STORAGE_STATE_PATH,
217
+ storageStateDir: env.AUTH_STORAGE_STATE_DIR
218
+ },
219
+ reporting: {
220
+ allureEnabled: env.REPORT_ALLURE === "true",
221
+ resultsDir: env.ALLURE_RESULTS_DIR,
222
+ testCaseUrlTemplate: env.TEST_CASE_URL_TEMPLATE
223
+ },
224
+ retry: {
225
+ retries: env.RETRY_COUNT ? Number(env.RETRY_COUNT) : void 0,
226
+ minDelayMs: env.RETRY_MIN_DELAY_MS ? Number(env.RETRY_MIN_DELAY_MS) : void 0,
227
+ maxDelayMs: env.RETRY_MAX_DELAY_MS ? Number(env.RETRY_MAX_DELAY_MS) : void 0
228
+ },
229
+ diagnostics: {
230
+ enabled: env.DIAGNOSTICS === void 0 ? void 0 : env.DIAGNOSTICS !== "false",
231
+ failOnConsoleError: env.FAIL_ON_CONSOLE_ERROR === void 0 ? void 0 : env.FAIL_ON_CONSOLE_ERROR === "true",
232
+ failOnPageError: env.FAIL_ON_PAGE_ERROR === void 0 ? void 0 : env.FAIL_ON_PAGE_ERROR === "true"
233
+ }
234
+ };
235
+ }
236
+ function loadConfig(options = {}) {
237
+ const { env = process.env, overrides } = options;
238
+ const fromEnv = pruneUndefined(readEnvConfig(env));
239
+ const merged = deepMerge(fromEnv, overrides);
240
+ const result = AppConfigSchema.safeParse(merged);
241
+ if (!result.success) {
242
+ throw new ConfigValidationError(
243
+ `Invalid application config: ${result.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ")}`,
244
+ result.error.issues
245
+ );
246
+ }
247
+ return result.data;
248
+ }
249
+
250
+ // src/auth/global-setup.ts
251
+ function roleStorageState(role, storageStateDir = process.env.AUTH_STORAGE_STATE_DIR ?? ".auth") {
252
+ return join(storageStateDir, `${role}.json`);
253
+ }
254
+ function buildGlobalSetup(options) {
255
+ if (!options.login && !options.roles) {
256
+ throw new AppError("buildGlobalSetup requires either `login` or `roles`", {
257
+ code: "GLOBAL_SETUP_NO_LOGIN"
258
+ });
259
+ }
260
+ return async function globalSetup() {
261
+ const config = loadConfig({ overrides: options.configOverrides });
262
+ const sessions = resolveSessions(options, config);
263
+ const browser = await chromium.launch(options.launchOptions);
264
+ try {
265
+ for (const session of sessions) {
266
+ mkdirSync(dirname(session.storageStatePath), { recursive: true });
267
+ const context = await browser.newContext({
268
+ baseURL: config.baseUrl,
269
+ ...session.contextOptions ?? options.contextOptions
270
+ });
271
+ try {
272
+ const page = await context.newPage();
273
+ await session.login(page, config);
274
+ await context.storageState({ path: session.storageStatePath });
275
+ } finally {
276
+ await context.close();
277
+ }
278
+ }
279
+ } finally {
280
+ await browser.close();
281
+ }
282
+ };
283
+ }
284
+ function resolveSessions(options, config) {
285
+ if (options.roles) {
286
+ return Object.entries(options.roles).map(([role, setup]) => ({
287
+ login: setup.login,
288
+ storageStatePath: setup.storageStatePath ?? roleStorageState(role, config.auth.storageStateDir),
289
+ contextOptions: setup.contextOptions
290
+ }));
291
+ }
292
+ const storageStatePath = config.auth.storageStatePath;
293
+ if (!storageStatePath) {
294
+ throw new AppError(
295
+ "buildGlobalSetup requires `auth.storageStatePath` to be set (env AUTH_STORAGE_STATE_PATH or a config override) when using single-session `login`",
296
+ { code: "MISSING_STORAGE_STATE_PATH" }
297
+ );
298
+ }
299
+ return [{ login: options.login, storageStatePath }];
300
+ }
301
+
302
+ export { JwtTokenProvider, NullTokenProvider, StaticTokenProvider, buildGlobalSetup, roleStorageState };
303
+ //# sourceMappingURL=index.js.map
304
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors/app-error.ts","../../src/auth/token-provider.ts","../../src/utils/deep-merge.ts","../../src/config/schema.ts","../../src/config/loader.ts","../../src/auth/global-setup.ts"],"names":[],"mappings":";;;;;;AAWO,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EACzB,IAAA;AAAA,EACA,OAAA;AAAA,EAET,WAAA,CAAY,SAAiB,OAAA,EAA0B;AACrD,IAAA,KAAA,CAAM,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,CAAQ,OAAO,CAAA;AACvC,IAAA,IAAA,CAAK,OAAO,GAAA,CAAA,MAAA,CAAW,IAAA;AACvB,IAAA,IAAA,CAAK,OAAO,OAAA,CAAQ,IAAA;AACpB,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF,CAAA;AAEO,IAAM,qBAAA,GAAN,cAAoC,QAAA,CAAS;AAAA,EAClD,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAiB,OAAA,EAAmC;AAC/E,IAAA,KAAA,CAAM,OAAA,EAAS,EAAE,IAAA,EAAM,yBAAA,EAA2B,OAAA,EAAS,EAAE,MAAA,EAAQ,GAAG,OAAA,EAAQ,EAAG,CAAA;AAAA,EACrF;AACF,CAAA;AAkBO,IAAM,SAAA,GAAN,cAAwB,QAAA,CAAS;AAAA,EACtC,WAAA,CAAY,OAAA,EAAiB,OAAA,GAAyC,EAAC,EAAG;AACxE,IAAA,KAAA,CAAM,SAAS,EAAE,IAAA,EAAM,YAAA,EAAc,GAAG,SAAS,CAAA;AAAA,EACnD;AACF,CAAA;;;AC7CO,IAAM,sBAAN,MAAmD;AAAA,EACxD,YAA6B,KAAA,EAAe;AAAf,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA,EAAgB;AAAA,EAAhB,KAAA;AAAA,EAE7B,MAAM,QAAA,GAA4B;AAChC,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAAA,EAEA,UAAA,GAAmB;AAAA,EAEnB;AACF;AAGO,IAAM,oBAAN,MAAiD;AAAA,EACtD,MAAM,QAAA,GAA4B;AAChC,IAAA,OAAO,EAAA;AAAA,EACT;AAAA,EAEA,UAAA,GAAmB;AAAA,EAEnB;AACF;AAuBO,IAAM,mBAAN,MAAgD;AAAA,EAIrD,YAA6B,OAAA,EAAkC;AAAlC,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAAmC;AAAA,EAAnC,OAAA;AAAA,EAHrB,MAAA;AAAA,EACA,QAAA;AAAA,EAIR,MAAM,QAAA,GAA4B;AAChC,IAAA,IAAI,KAAK,MAAA,IAAU,IAAA,CAAK,OAAO,SAAA,GAAY,IAAA,CAAK,KAAI,EAAG;AACrD,MAAA,OAAO,KAAK,MAAA,CAAO,KAAA;AAAA,IACrB;AACA,IAAA,IAAI,CAAC,KAAK,QAAA,EAAU;AAClB,MAAA,IAAA,CAAK,QAAA,GAAW,IAAA,CAAK,UAAA,EAAW,CAAE,QAAQ,MAAM;AAC9C,QAAA,IAAA,CAAK,QAAA,GAAW,MAAA;AAAA,MAClB,CAAC,CAAA;AAAA,IACH;AACA,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA,EAEA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,MAAc,UAAA,GAA8B;AAC1C,IAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,YAAA,EAAc,QAAA,EAAU,QAAA,EAAU,kBAAA,GAAqB,EAAA,EAAI,MAAA,EAAQ,SAAA,GAAY,KAAA,EAAM,GAAI,IAAA,CAAK,OAAA;AAE1H,IAAA,MAAM,IAAA,GAAO,IAAI,eAAA,EAAgB;AACjC,IAAA,IAAI,YAAY,QAAA,EAAU;AACxB,MAAA,IAAA,CAAK,GAAA,CAAI,cAAc,UAAU,CAAA;AACjC,MAAA,IAAA,CAAK,GAAA,CAAI,YAAY,QAAQ,CAAA;AAC7B,MAAA,IAAA,CAAK,GAAA,CAAI,YAAY,QAAQ,CAAA;AAAA,IAC/B,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,GAAA,CAAI,cAAc,oBAAoB,CAAA;AAAA,IAC7C;AACA,IAAA,IAAI,QAAA,EAAU,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,QAAQ,CAAA;AAC5C,IAAA,IAAI,YAAA,EAAc,IAAA,CAAK,GAAA,CAAI,eAAA,EAAiB,YAAY,CAAA;AAExD,IAAA,MAAA,EAAQ,KAAA,CAAM,EAAE,QAAA,EAAS,EAAG,qBAAqB,CAAA;AAEjD,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAM,UAAU,QAAA,EAAU;AAAA,QACnC,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAoC;AAAA,QAC/D;AAAA,OACD,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,+BAAA,EAAkC,QAAQ,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA;AAAA,IAC7E;AAEA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,OAAO,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AACjD,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,wBAAA,EAA2B,SAAS,MAAM,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,EAAI;AAAA,QACzE,OAAA,EAAS,EAAE,MAAA,EAAQ,QAAA,CAAS,QAAQ,QAAA;AAAS,OAC9C,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,IAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACtB,MAAA,MAAM,IAAI,UAAU,8CAAA,EAAgD,EAAE,SAAS,EAAE,QAAA,IAAY,CAAA;AAAA,IAC/F;AAEA,IAAA,MAAM,gBAAA,GAAmB,KAAK,UAAA,IAAc,GAAA;AAC5C,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,OAAO,IAAA,CAAK,YAAA;AAAA,MACZ,SAAA,EAAW,KAAK,GAAA,EAAI,GAAI,KAAK,GAAA,CAAI,gBAAA,GAAmB,kBAAA,EAAoB,CAAC,CAAA,GAAI;AAAA,KAC/E;AACA,IAAA,OAAO,KAAK,MAAA,CAAO,KAAA;AAAA,EACrB;AACF;;;ACrHO,SAAS,cAAc,KAAA,EAAkD;AAC9E,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAOO,SAAS,SAAA,CAAa,MAAS,QAAA,EAAsB;AAC1D,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,IAAA;AACnC,EAAA,IAAI,CAAC,aAAA,CAAc,IAAI,KAAK,CAAC,aAAA,CAAc,QAAQ,CAAA,EAAG;AACpD,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,MAAM,MAAA,GAAkC,EAAE,GAAG,IAAA,EAAK;AAClD,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACnD,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,MAAM,SAAA,GAAa,KAAiC,GAAG,CAAA;AACvD,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,aAAA,CAAc,SAAS,CAAA,IAAK,aAAA,CAAc,KAAK,CAAA,GAAI,SAAA,CAAU,SAAA,EAAW,KAAK,CAAA,GAAI,KAAA;AAAA,EACjG;AACA,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,eAAe,KAAA,EAAyB;AACtD,EAAA,IAAI,MAAM,OAAA,CAAQ,KAAK,GAAG,OAAO,KAAA,CAAM,IAAI,cAAc,CAAA;AACzD,EAAA,IAAI,aAAA,CAAc,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,GAAG,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC9C,MAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,MAAA,MAAM,MAAA,GAAS,eAAe,GAAG,CAAA;AACjC,MAAA,IAAI,aAAA,CAAc,MAAM,CAAA,IAAK,MAAA,CAAO,KAAK,MAAM,CAAA,CAAE,WAAW,CAAA,EAAG;AAC/D,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AAAA,IAChB;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;ACzBO,IAAM,iBAAA,GAAoB,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAE1C,IAAM,cAAA,GAAiB,EAAE,MAAA,CAAO;AAAA,EACrC,QAAA,EAAU,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,IAAM,CAAA;AAAA,EACpD,YAAA,EAAc,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAM,CAAA;AAAA,EACxD,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAM,CAAA;AAAA;AAAA,EAElD,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAM;AACpD,CAAC,CAAA;AAEM,IAAM,gBAAA,GAAmB,EAC7B,MAAA,CAAO;AAAA,EACN,UAAU,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACpC,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAClC,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE9B,gBAAA,EAAkB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAEtC,eAAA,EAAiB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,OAAO;AAC7C,CAAC,CAAA,CACA,OAAA,CAAQ,EAAE,CAAA;AAEN,IAAM,qBAAA,GAAwB,EAClC,MAAA,CAAO;AAAA,EACN,aAAA,EAAe,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA,EACxC,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,gBAAgB,CAAA;AAAA;AAAA,EAE/C,mBAAA,EAAqB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAClC,CAAC,CAAA,CACA,OAAA,CAAQ,EAAE,CAAA;AAEN,IAAM,iBAAA,GAAoB,EAC9B,MAAA,CAAO;AAAA,EACN,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAAA,EAC1C,UAAA,EAAY,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAG,CAAA;AAAA,EACnD,UAAA,EAAY,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAK;AACvD,CAAC,CAAA,CACA,OAAA,CAAQ,EAAE,CAAA;AAEN,IAAM,uBAAA,GAA0B,EACpC,MAAA,CAAO;AAAA;AAAA,EAEN,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA,EAEjC,kBAAA,EAAoB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA;AAAA,EAE7C,eAAA,EAAiB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA;AAAA,EAE1C,qBAAA,EAAuB,EAAE,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE;AACvD,CAAC,CAAA,CACA,OAAA,CAAQ,EAAE,CAAA;AAON,IAAM,eAAA,GAAkB,EAAE,MAAA,CAAO;AAAA,EACtC,WAAA,EAAa,iBAAA;AAAA,EACb,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,EACxB,YAAY,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACtC,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC5B,QAAA,EAAU,cAAA,CAAe,OAAA,CAAQ,EAAE,CAAA;AAAA,EACnC,IAAA,EAAM,gBAAA;AAAA,EACN,SAAA,EAAW,qBAAA;AAAA,EACX,KAAA,EAAO,iBAAA;AAAA,EACP,WAAA,EAAa,uBAAA;AAAA,EACb,QAAA,EAAU,CAAA,CAAE,IAAA,CAAK,CAAC,SAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS,QAAQ,CAAC,CAAA,CAAE,QAAQ,MAAM,CAAA;AAAA,EAC/F,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAA,CAAE,MAAA,EAAO,EAAG,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAA,CAAQ,EAAE;AACtD,CAAC,CAAA;;;AC9ED,SAAS,cAAc,GAAA,EAAiD;AACtE,EAAA,OAAO;AAAA,IACL,WAAA,EAAa,IAAI,QAAA,IAAY,KAAA;AAAA,IAC7B,SAAS,GAAA,CAAI,QAAA;AAAA,IACb,YAAY,GAAA,CAAI,YAAA;AAAA,IAChB,QAAQ,GAAA,CAAI,MAAA;AAAA,IACZ,UAAU,GAAA,CAAI,SAAA;AAAA,IACd,QAAA,EAAU;AAAA,MACR,UAAU,GAAA,CAAI,iBAAA,GAAoB,MAAA,CAAO,GAAA,CAAI,iBAAiB,CAAA,GAAI,MAAA;AAAA,MAClE,cAAc,GAAA,CAAI,qBAAA,GAAwB,MAAA,CAAO,GAAA,CAAI,qBAAqB,CAAA,GAAI,MAAA;AAAA,MAC9E,QAAQ,GAAA,CAAI,eAAA,GAAkB,MAAA,CAAO,GAAA,CAAI,eAAe,CAAA,GAAI,MAAA;AAAA,MAC5D,QAAQ,GAAA,CAAI,eAAA,GAAkB,MAAA,CAAO,GAAA,CAAI,eAAe,CAAA,GAAI;AAAA,KAC9D;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,UAAU,GAAA,CAAI,cAAA;AAAA,MACd,UAAU,GAAA,CAAI,cAAA;AAAA,MACd,cAAc,GAAA,CAAI,kBAAA;AAAA,MAClB,UAAU,GAAA,CAAI,aAAA;AAAA,MACd,UAAU,GAAA,CAAI,aAAA;AAAA,MACd,kBAAkB,GAAA,CAAI,uBAAA;AAAA,MACtB,iBAAiB,GAAA,CAAI;AAAA,KACvB;AAAA,IACA,SAAA,EAAW;AAAA,MACT,aAAA,EAAe,IAAI,aAAA,KAAkB,MAAA;AAAA,MACrC,YAAY,GAAA,CAAI,kBAAA;AAAA,MAChB,qBAAqB,GAAA,CAAI;AAAA,KAC3B;AAAA,IACA,KAAA,EAAO;AAAA,MACL,SAAS,GAAA,CAAI,WAAA,GAAc,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA,GAAI,MAAA;AAAA,MACrD,YAAY,GAAA,CAAI,kBAAA,GAAqB,MAAA,CAAO,GAAA,CAAI,kBAAkB,CAAA,GAAI,MAAA;AAAA,MACtE,YAAY,GAAA,CAAI,kBAAA,GAAqB,MAAA,CAAO,GAAA,CAAI,kBAAkB,CAAA,GAAI;AAAA,KACxE;AAAA,IACA,WAAA,EAAa;AAAA,MACX,SAAS,GAAA,CAAI,WAAA,KAAgB,MAAA,GAAY,MAAA,GAAY,IAAI,WAAA,KAAgB,OAAA;AAAA,MACzE,oBAAoB,GAAA,CAAI,qBAAA,KAA0B,MAAA,GAAY,MAAA,GAAY,IAAI,qBAAA,KAA0B,MAAA;AAAA,MACxG,iBAAiB,GAAA,CAAI,kBAAA,KAAuB,MAAA,GAAY,MAAA,GAAY,IAAI,kBAAA,KAAuB;AAAA;AACjG,GACF;AACF;AA2BO,SAAS,UAAA,CAAW,OAAA,GAA6B,EAAC,EAAc;AACrE,EAAA,MAAM,EAAE,GAAA,GAAM,OAAA,CAAQ,GAAA,EAAK,WAAU,GAAI,OAAA;AAEzC,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,aAAA,CAAc,GAAG,CAAC,CAAA;AACjD,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,OAAA,EAAsB,SAAS,CAAA;AAExD,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,SAAA,CAAU,MAAM,CAAA;AAC/C,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,IAAI,qBAAA;AAAA,MACR,CAAA,4BAAA,EAA+B,OAAO,KAAA,CAAM,MAAA,CACzC,IAAI,CAAC,KAAA,KAAU,GAAG,KAAA,CAAM,IAAA,CAAK,KAAK,GAAG,CAAA,IAAK,QAAQ,CAAA,EAAA,EAAK,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA,CACtE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MACb,OAAO,KAAA,CAAM;AAAA,KACf;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,IAAA;AAChB;;;AC/BO,SAAS,iBACd,IAAA,EACA,eAAA,GAA0B,OAAA,CAAQ,GAAA,CAAI,0BAA0B,OAAA,EACxD;AACR,EAAA,OAAO,IAAA,CAAK,eAAA,EAAiB,CAAA,EAAG,IAAI,CAAA,KAAA,CAAO,CAAA;AAC7C;AAQO,SAAS,iBAAiB,OAAA,EAA6B;AAC5D,EAAA,IAAI,CAAC,OAAA,CAAQ,KAAA,IAAS,CAAC,QAAQ,KAAA,EAAO;AACpC,IAAA,MAAM,IAAI,SAAS,qDAAA,EAAuD;AAAA,MACxE,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,eAAe,WAAA,GAA6B;AACjD,IAAA,MAAM,SAAS,UAAA,CAAW,EAAE,SAAA,EAAW,OAAA,CAAQ,iBAAiB,CAAA;AAChE,IAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,OAAA,EAAS,MAAM,CAAA;AAEhD,IAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,MAAA,CAAO,QAAQ,aAAa,CAAA;AAC3D,IAAA,IAAI;AAGF,MAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,QAAA,SAAA,CAAU,QAAQ,OAAA,CAAQ,gBAAgB,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAChE,QAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA,CAAW;AAAA,UACvC,SAAS,MAAA,CAAO,OAAA;AAAA,UAChB,GAAI,OAAA,CAAQ,cAAA,IAAkB,OAAA,CAAQ;AAAA,SACvC,CAAA;AACD,QAAA,IAAI;AACF,UAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,OAAA,EAAQ;AACnC,UAAA,MAAM,OAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,MAAM,CAAA;AAChC,UAAA,MAAM,QAAQ,YAAA,CAAa,EAAE,IAAA,EAAM,OAAA,CAAQ,kBAAkB,CAAA;AAAA,QAC/D,CAAA,SAAE;AACA,UAAA,MAAM,QAAQ,KAAA,EAAM;AAAA,QACtB;AAAA,MACF;AAAA,IACF,CAAA,SAAE;AACA,MAAA,MAAM,QAAQ,KAAA,EAAM;AAAA,IACtB;AAAA,EACF,CAAA;AACF;AAQA,SAAS,eAAA,CAAgB,SAA6B,MAAA,EAAsC;AAC1F,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,IAAA,EAAM,KAAK,CAAA,MAAO;AAAA,MAC3D,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,kBAAkB,KAAA,CAAM,gBAAA,IAAoB,iBAAiB,IAAA,EAAM,MAAA,CAAO,KAAK,eAAe,CAAA;AAAA,MAC9F,gBAAgB,KAAA,CAAM;AAAA,KACxB,CAAE,CAAA;AAAA,EACJ;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAO,IAAA,CAAK,gBAAA;AACrC,EAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,IAAA,MAAM,IAAI,QAAA;AAAA,MACR,kJAAA;AAAA,MACA,EAAE,MAAM,4BAAA;AAA6B,KACvC;AAAA,EACF;AACA,EAAA,OAAO,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAkB,kBAAkB,CAAA;AAC/D","file":"index.js","sourcesContent":["export interface AppErrorOptions {\n code: string;\n cause?: unknown;\n context?: Record<string, unknown>;\n}\n\n/**\n * Base error class for the framework. Every error thrown by core carries a\n * machine-readable `code` and optional `context`, so callers can branch on\n * `error.code` instead of parsing messages.\n */\nexport class AppError extends Error {\n readonly code: string;\n readonly context?: Record<string, unknown>;\n\n constructor(message: string, options: AppErrorOptions) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code;\n this.context = options.context;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConfigValidationError extends AppError {\n constructor(message: string, issues: unknown, context?: Record<string, unknown>) {\n super(message, { code: \"CONFIG_VALIDATION_ERROR\", context: { issues, ...context } });\n }\n}\n\nexport class ApiError extends AppError {\n readonly status?: number;\n readonly method?: string;\n readonly url?: string;\n\n constructor(\n message: string,\n options: AppErrorOptions & { status?: number; method?: string; url?: string },\n ) {\n super(message, options);\n this.status = options.status;\n this.method = options.method;\n this.url = options.url;\n }\n}\n\nexport class AuthError extends AppError {\n constructor(message: string, options: Omit<AppErrorOptions, \"code\"> = {}) {\n super(message, { code: \"AUTH_ERROR\", ...options });\n }\n}\n\nexport class ConfigMissingError extends AppError {\n constructor(name: string) {\n super(`Required environment variable \"${name}\" is not set`, {\n code: \"ENV_VAR_MISSING\",\n context: { name },\n });\n }\n}\n","import { AuthError } from \"../errors/app-error.js\";\nimport type { Logger } from \"../logging/logger.js\";\nimport type { TokenProvider } from \"./types.js\";\n\n/** Token provider that always returns a fixed token. Useful for tests/local dev with a pre-issued token. */\nexport class StaticTokenProvider implements TokenProvider {\n constructor(private readonly token: string) {}\n\n async getToken(): Promise<string> {\n return this.token;\n }\n\n invalidate(): void {\n // no-op: nothing to invalidate for a static token\n }\n}\n\n/** No-op provider for endpoints that don't require authentication. */\nexport class NullTokenProvider implements TokenProvider {\n async getToken(): Promise<string> {\n return \"\";\n }\n\n invalidate(): void {\n // no-op\n }\n}\n\nexport interface JwtTokenProviderOptions {\n tokenUrl: string;\n clientId?: string;\n clientSecret?: string;\n username?: string;\n password?: string;\n /** Seconds subtracted from the token's `expires_in` to refresh proactively. Default: 30. */\n refreshSkewSeconds?: number;\n logger?: Logger;\n fetchImpl?: typeof fetch;\n}\n\ninterface CachedToken {\n token: string;\n expiresAt: number;\n}\n\n/**\n * JWT/OAuth2 token provider supporting client-credentials or password grants.\n * Caches the token in-memory and transparently refreshes it before expiry.\n */\nexport class JwtTokenProvider implements TokenProvider {\n private cached?: CachedToken;\n private inFlight?: Promise<string>;\n\n constructor(private readonly options: JwtTokenProviderOptions) {}\n\n async getToken(): Promise<string> {\n if (this.cached && this.cached.expiresAt > Date.now()) {\n return this.cached.token;\n }\n if (!this.inFlight) {\n this.inFlight = this.fetchToken().finally(() => {\n this.inFlight = undefined;\n });\n }\n return this.inFlight;\n }\n\n invalidate(): void {\n this.cached = undefined;\n }\n\n private async fetchToken(): Promise<string> {\n const { tokenUrl, clientId, clientSecret, username, password, refreshSkewSeconds = 30, logger, fetchImpl = fetch } = this.options;\n\n const body = new URLSearchParams();\n if (username && password) {\n body.set(\"grant_type\", \"password\");\n body.set(\"username\", username);\n body.set(\"password\", password);\n } else {\n body.set(\"grant_type\", \"client_credentials\");\n }\n if (clientId) body.set(\"client_id\", clientId);\n if (clientSecret) body.set(\"client_secret\", clientSecret);\n\n logger?.debug({ tokenUrl }, \"fetching auth token\");\n\n let response: Response;\n try {\n response = await fetchImpl(tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n } catch (cause) {\n throw new AuthError(`Failed to reach token endpoint ${tokenUrl}`, { cause });\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new AuthError(`Token endpoint returned ${response.status}: ${text}`, {\n context: { status: response.status, tokenUrl },\n });\n }\n\n const data = (await response.json()) as { access_token?: string; expires_in?: number };\n if (!data.access_token) {\n throw new AuthError(\"Token endpoint response missing access_token\", { context: { tokenUrl } });\n }\n\n const expiresInSeconds = data.expires_in ?? 300;\n this.cached = {\n token: data.access_token,\n expiresAt: Date.now() + Math.max(expiresInSeconds - refreshSkewSeconds, 0) * 1000,\n };\n return this.cached.token;\n }\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Recursively merges `override` onto `base`. Arrays and primitives replace wholesale;\n * only plain objects are merged key by key. `undefined` values in `override` are ignored,\n * so a partial object never accidentally erases a configured value.\n */\nexport function deepMerge<T>(base: T, override: unknown): T {\n if (override === undefined) return base;\n if (!isPlainObject(base) || !isPlainObject(override)) {\n return override as T;\n }\n const result: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue;\n const baseValue = (base as Record<string, unknown>)[key];\n result[key] = isPlainObject(baseValue) && isPlainObject(value) ? deepMerge(baseValue, value) : value;\n }\n return result as T;\n}\n\n/** Strips `undefined` values and empty nested objects, so zod defaults apply instead. */\nexport function pruneUndefined(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(pruneUndefined);\n if (isPlainObject(value)) {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n if (val === undefined) continue;\n const pruned = pruneUndefined(val);\n if (isPlainObject(pruned) && Object.keys(pruned).length === 0) continue;\n result[key] = pruned;\n }\n return result;\n }\n return value;\n}\n","import { z } from \"zod\";\n\n/** Environments seen most often across projects — autocompleted, but any string is accepted. */\nexport const KNOWN_ENVIRONMENTS = [\"local\", \"dev\", \"qa\", \"uat\", \"staging\", \"prod\"] as const;\n\n/**\n * Free-form on purpose: teams run `uat`, `qa`, `sit`, per-tenant envs and so on. The union\n * below keeps editor autocomplete for the common ones without rejecting anything else\n * (`(string & {})` is the TS idiom that preserves suggestions on an open string type).\n */\nexport type Environment = (typeof KNOWN_ENVIRONMENTS)[number] | (string & {});\n\nexport const EnvironmentSchema = z.string().min(1);\n\nexport const TimeoutsSchema = z.object({\n actionMs: z.number().int().positive().default(15_000),\n navigationMs: z.number().int().positive().default(30_000),\n testMs: z.number().int().positive().default(60_000),\n /** Default budget for `waitForCondition` and other non-locator polling. */\n waitMs: z.number().int().positive().default(30_000),\n});\n\nexport const AuthConfigSchema = z\n .object({\n tokenUrl: z.string().url().optional(),\n clientId: z.string().optional(),\n clientSecret: z.string().optional(),\n username: z.string().optional(),\n password: z.string().optional(),\n /** Single-session storage state file (see `buildGlobalSetup`). */\n storageStatePath: z.string().optional(),\n /** Directory used for per-role storage state files in multi-role setups. */\n storageStateDir: z.string().default(\".auth\"),\n })\n .default({});\n\nexport const ReportingConfigSchema = z\n .object({\n allureEnabled: z.boolean().default(false),\n resultsDir: z.string().default(\"allure-results\"),\n /** `{id}` is replaced with a test-case id — see `meta()` in `@emesoft_company/playwright-core/reporting`. */\n testCaseUrlTemplate: z.string().optional(),\n })\n .default({});\n\nexport const RetryConfigSchema = z\n .object({\n retries: z.number().int().min(0).default(2),\n minDelayMs: z.number().int().positive().default(200),\n maxDelayMs: z.number().int().positive().default(5_000),\n })\n .default({});\n\nexport const DiagnosticsConfigSchema = z\n .object({\n /** Collect browser console errors + failed requests and attach them to the report. */\n enabled: z.boolean().default(true),\n /** Fail the test if the page logged a console error. Off by default — many apps are noisy. */\n failOnConsoleError: z.boolean().default(false),\n /** Fail the test on an uncaught page exception. */\n failOnPageError: z.boolean().default(false),\n /** Console messages matching any of these substrings are ignored entirely. */\n ignoreConsolePatterns: z.array(z.string()).default([]),\n })\n .default({});\n\n/**\n * Base config schema shared by every project. Projects extend this via\n * `AppConfigSchema.extend({ ... })` or by nesting project-specific fields\n * under `custom` — core never hardcodes project business fields here.\n */\nexport const AppConfigSchema = z.object({\n environment: EnvironmentSchema,\n baseUrl: z.string().url(),\n apiBaseUrl: z.string().url().optional(),\n tenant: z.string().optional(),\n timeouts: TimeoutsSchema.default({}),\n auth: AuthConfigSchema,\n reporting: ReportingConfigSchema,\n retry: RetryConfigSchema,\n diagnostics: DiagnosticsConfigSchema,\n logLevel: z.enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\", \"silent\"]).default(\"info\"),\n custom: z.record(z.string(), z.unknown()).default({}),\n});\n\nexport type AppConfig = Omit<z.infer<typeof AppConfigSchema>, \"environment\"> & {\n environment: Environment;\n};\nexport type TimeoutsConfig = z.infer<typeof TimeoutsSchema>;\nexport type AuthConfig = z.infer<typeof AuthConfigSchema>;\nexport type ReportingConfig = z.infer<typeof ReportingConfigSchema>;\nexport type RetryConfig = z.infer<typeof RetryConfigSchema>;\nexport type DiagnosticsConfig = z.infer<typeof DiagnosticsConfigSchema>;\n","import { ConfigMissingError, ConfigValidationError } from \"../errors/app-error.js\";\nimport { deepMerge, pruneUndefined } from \"../utils/deep-merge.js\";\nimport { AppConfigSchema, type AppConfig } from \"./schema.js\";\nimport type { DeepPartial } from \"./types.js\";\n\nfunction readEnvConfig(env: NodeJS.ProcessEnv): Record<string, unknown> {\n return {\n environment: env.TEST_ENV ?? \"dev\",\n baseUrl: env.BASE_URL,\n apiBaseUrl: env.API_BASE_URL,\n tenant: env.TENANT,\n logLevel: env.LOG_LEVEL,\n timeouts: {\n actionMs: env.ACTION_TIMEOUT_MS ? Number(env.ACTION_TIMEOUT_MS) : undefined,\n navigationMs: env.NAVIGATION_TIMEOUT_MS ? Number(env.NAVIGATION_TIMEOUT_MS) : undefined,\n testMs: env.TEST_TIMEOUT_MS ? Number(env.TEST_TIMEOUT_MS) : undefined,\n waitMs: env.WAIT_TIMEOUT_MS ? Number(env.WAIT_TIMEOUT_MS) : undefined,\n },\n auth: {\n tokenUrl: env.AUTH_TOKEN_URL,\n clientId: env.AUTH_CLIENT_ID,\n clientSecret: env.AUTH_CLIENT_SECRET,\n username: env.AUTH_USERNAME,\n password: env.AUTH_PASSWORD,\n storageStatePath: env.AUTH_STORAGE_STATE_PATH,\n storageStateDir: env.AUTH_STORAGE_STATE_DIR,\n },\n reporting: {\n allureEnabled: env.REPORT_ALLURE === \"true\",\n resultsDir: env.ALLURE_RESULTS_DIR,\n testCaseUrlTemplate: env.TEST_CASE_URL_TEMPLATE,\n },\n retry: {\n retries: env.RETRY_COUNT ? Number(env.RETRY_COUNT) : undefined,\n minDelayMs: env.RETRY_MIN_DELAY_MS ? Number(env.RETRY_MIN_DELAY_MS) : undefined,\n maxDelayMs: env.RETRY_MAX_DELAY_MS ? Number(env.RETRY_MAX_DELAY_MS) : undefined,\n },\n diagnostics: {\n enabled: env.DIAGNOSTICS === undefined ? undefined : env.DIAGNOSTICS !== \"false\",\n failOnConsoleError: env.FAIL_ON_CONSOLE_ERROR === undefined ? undefined : env.FAIL_ON_CONSOLE_ERROR === \"true\",\n failOnPageError: env.FAIL_ON_PAGE_ERROR === undefined ? undefined : env.FAIL_ON_PAGE_ERROR === \"true\",\n },\n };\n}\n\n/**\n * Reads a required environment variable, failing immediately with a clear message instead of\n * letting an `undefined` surface as a confusing failure deep inside a test.\n */\nexport function requireEnv(name: string, env: NodeJS.ProcessEnv = process.env): string {\n const value = env[name];\n if (value === undefined || value === \"\") {\n throw new ConfigMissingError(name);\n }\n return value;\n}\n\nexport interface LoadConfigOptions {\n /** Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** Project-specific overrides (e.g. from a project's `config.override.ts`), merged on top of env-derived values. */\n overrides?: DeepPartial<AppConfig>;\n}\n\n/**\n * Loads and validates the application config for the current environment.\n * Resolution order: env-derived defaults -> project `overrides` -> zod validation.\n * Fails fast with `ConfigValidationError` when required fields (e.g. `baseUrl`) are missing/invalid,\n * instead of letting tests fail later with a confusing `undefined` somewhere downstream.\n */\nexport function loadConfig(options: LoadConfigOptions = {}): AppConfig {\n const { env = process.env, overrides } = options;\n\n const fromEnv = pruneUndefined(readEnvConfig(env)) as DeepPartial<AppConfig>;\n const merged = deepMerge(fromEnv as AppConfig, overrides);\n\n const result = AppConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new ConfigValidationError(\n `Invalid application config: ${result.error.issues\n .map((issue) => `${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"; \")}`,\n result.error.issues,\n );\n }\n return result.data;\n}\n","import { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { chromium, type BrowserContextOptions, type Page } from \"@playwright/test\";\nimport { loadConfig } from \"../config/loader.js\";\nimport type { AppConfig } from \"../config/schema.js\";\nimport type { DeepPartial } from \"../config/types.js\";\nimport { AppError } from \"../errors/app-error.js\";\n\nexport type LoginFn = (page: Page, config: AppConfig) => Promise<void>;\n\nexport interface RoleSetup {\n /** Performs this role's login; storage state is captured right after it returns. */\n login: LoginFn;\n /** Defaults to `<auth.storageStateDir>/<role>.json`. */\n storageStatePath?: string;\n /** Per-role context options, falling back to the top-level `contextOptions`. */\n contextOptions?: BrowserContextOptions;\n}\n\nexport interface GlobalSetupOptions {\n /**\n * Single-session login. Storage state goes to `auth.storageStatePath`.\n * Mutually exclusive with `roles`.\n */\n login?: LoginFn;\n /**\n * Multi-role login — one storage state file per role, so tests can pick who they run as\n * with `test.use({ storageState: roleStorageState(\"admin\") })`.\n */\n roles?: Record<string, RoleSetup>;\n configOverrides?: DeepPartial<AppConfig>;\n /**\n * Context options (e.g. `devices[\"Desktop Chrome\"]`) to log in with. Pass the SAME options\n * your test projects run with — some apps tie a session to fingerprint details like\n * User-Agent, so logging in under different context options than the tests that reuse the\n * session can silently invalidate it server-side.\n */\n contextOptions?: BrowserContextOptions;\n /**\n * Options for `chromium.launch()` — e.g. `{ headless: false }`. Defaults to Playwright's own\n * default (headless). Some apps never finish loading/rendering in headless mode (confirmed\n * for real against a staging target in `bec.e2e`); pass `headless: false` here instead of\n * writing a custom `global-setup.ts` from scratch just to change this one thing.\n */\n launchOptions?: Parameters<typeof chromium.launch>[0];\n}\n\n/**\n * Path of a role's storage state file. Use the same role names here as in\n * `buildGlobalSetup({ roles })` so tests and setup agree:\n *\n * ```ts\n * test.use({ storageState: roleStorageState(\"admin\") });\n * ```\n */\nexport function roleStorageState(\n role: string,\n storageStateDir: string = process.env.AUTH_STORAGE_STATE_DIR ?? \".auth\",\n): string {\n return join(storageStateDir, `${role}.json`);\n}\n\n/**\n * Builds a Playwright `globalSetup` function that logs in once and persists the resulting\n * storage state, so per-test runs reuse an authenticated session instead of logging in for\n * every test. Wire the returned function into `playwright.config.ts`'s `globalSetup` option.\n * See `docs/EXTENDING.md`.\n */\nexport function buildGlobalSetup(options: GlobalSetupOptions) {\n if (!options.login && !options.roles) {\n throw new AppError(\"buildGlobalSetup requires either `login` or `roles`\", {\n code: \"GLOBAL_SETUP_NO_LOGIN\",\n });\n }\n\n return async function globalSetup(): Promise<void> {\n const config = loadConfig({ overrides: options.configOverrides });\n const sessions = resolveSessions(options, config);\n\n const browser = await chromium.launch(options.launchOptions);\n try {\n // Sequential on purpose: parallel logins to the same app can trip rate limits or\n // invalidate each other's sessions on single-session-per-user backends.\n for (const session of sessions) {\n mkdirSync(dirname(session.storageStatePath), { recursive: true });\n const context = await browser.newContext({\n baseURL: config.baseUrl,\n ...(session.contextOptions ?? options.contextOptions),\n });\n try {\n const page = await context.newPage();\n await session.login(page, config);\n await context.storageState({ path: session.storageStatePath });\n } finally {\n await context.close();\n }\n }\n } finally {\n await browser.close();\n }\n };\n}\n\ninterface ResolvedSession {\n login: LoginFn;\n storageStatePath: string;\n contextOptions?: BrowserContextOptions;\n}\n\nfunction resolveSessions(options: GlobalSetupOptions, config: AppConfig): ResolvedSession[] {\n if (options.roles) {\n return Object.entries(options.roles).map(([role, setup]) => ({\n login: setup.login,\n storageStatePath: setup.storageStatePath ?? roleStorageState(role, config.auth.storageStateDir),\n contextOptions: setup.contextOptions,\n }));\n }\n\n const storageStatePath = config.auth.storageStatePath;\n if (!storageStatePath) {\n throw new AppError(\n \"buildGlobalSetup requires `auth.storageStatePath` to be set (env AUTH_STORAGE_STATE_PATH or a config override) when using single-session `login`\",\n { code: \"MISSING_STORAGE_STATE_PATH\" },\n );\n }\n return [{ login: options.login as LoginFn, storageStatePath }];\n}\n"]}