@midscene/test 1.12.4-beta-20260903111111.0 → 1.12.4

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 (40) hide show
  1. package/dist/es/android/index.mjs +50 -106
  2. package/dist/es/android/index.mjs.map +1 -1
  3. package/dist/es/cli/index.mjs +99 -149
  4. package/dist/es/cli/index.mjs.map +1 -1
  5. package/dist/es/harmony/index.mjs +119 -0
  6. package/dist/es/harmony/index.mjs.map +1 -0
  7. package/dist/es/index.mjs +36 -87
  8. package/dist/es/index.mjs.map +1 -1
  9. package/dist/es/ios/index.mjs +51 -101
  10. package/dist/es/ios/index.mjs.map +1 -1
  11. package/dist/es/midscene/index.mjs +37 -235
  12. package/dist/es/midscene/index.mjs.map +1 -1
  13. package/dist/es/playwright/index.mjs +14 -10
  14. package/dist/es/playwright/index.mjs.map +1 -1
  15. package/dist/es/test-cli.mjs +102 -150
  16. package/dist/es/test-cli.mjs.map +1 -1
  17. package/dist/lib/android/index.js +151 -178
  18. package/dist/lib/android/index.js.map +1 -1
  19. package/dist/lib/cli/index.js +99 -149
  20. package/dist/lib/cli/index.js.map +1 -1
  21. package/dist/lib/harmony/index.js +188 -0
  22. package/dist/lib/harmony/index.js.map +1 -0
  23. package/dist/lib/index.js +37 -100
  24. package/dist/lib/index.js.map +1 -1
  25. package/dist/lib/ios/index.js +152 -173
  26. package/dist/lib/ios/index.js.map +1 -1
  27. package/dist/lib/midscene/index.js +264 -412
  28. package/dist/lib/midscene/index.js.map +1 -1
  29. package/dist/lib/playwright/index.js +14 -10
  30. package/dist/lib/playwright/index.js.map +1 -1
  31. package/dist/lib/test-cli.js +102 -150
  32. package/dist/lib/test-cli.js.map +1 -1
  33. package/dist/types/android/index.d.ts +27 -101
  34. package/dist/types/cli/index.d.ts +9 -32
  35. package/dist/types/harmony/index.d.ts +124 -0
  36. package/dist/types/index.d.ts +18 -45
  37. package/dist/types/ios/index.d.ts +28 -107
  38. package/dist/types/midscene/index.d.ts +54 -153
  39. package/dist/types/playwright/index.d.ts +9 -63
  40. package/package.json +25 -6
@@ -1 +1 @@
1
- {"version":3,"file":"playwright/index.mjs","sources":["../../../src/errors.ts","../../../src/node/define-node.ts","../../../src/playwright/utils.ts","../../../src/playwright/clear-cookies.ts","../../../src/playwright/cookies.ts","../../../src/playwright/goto-url.ts","../../../src/playwright/viewport.ts","../../../src/playwright/index.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\nexport interface WorkflowErrorOptions {\n code?: string;\n details?: unknown;\n cause?: unknown;\n}\n\nexport class WorkflowError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, options: WorkflowErrorOptions = {}) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code ?? 'WORKFLOW_ERROR';\n this.details = options.details;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n ...(this.details === undefined ? {} : { details: this.details }),\n };\n }\n}\n\nexport class WorkflowParseError extends WorkflowError {\n constructor(message: string, details?: unknown, cause?: unknown) {\n super(message, { code: 'WORKFLOW_PARSE_ERROR', details, cause });\n }\n}\n\nexport class NodeDefinitionError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_DEFINITION_ERROR', details });\n }\n}\n\nexport class DuplicateNodeError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is already registered.`, {\n code: 'DUPLICATE_NODE',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeNotFoundError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is not registered.`, {\n code: 'NODE_NOT_FOUND',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeInputValidationError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_INPUT_VALIDATION_ERROR', details });\n }\n\n static fromZod(node: string, error: z.ZodError): NodeInputValidationError {\n const issues = error.issues.map((issue) => ({\n code: issue.code,\n path: issue.path.map(String).join('.'),\n message: issue.message,\n }));\n const firstIssue = issues[0];\n const path = firstIssue?.path || '<root>';\n const message = firstIssue?.message ?? 'invalid input';\n return new NodeInputValidationError(\n `Node \"${node}\" input validation failed at \"${path}\": ${message}`,\n { node, issues },\n );\n }\n}\n\nexport class StepTimeoutError extends WorkflowError {\n readonly timeoutMs: number;\n readonly node?: string;\n\n constructor(timeoutMs: number, node?: string) {\n super(\n node\n ? `Node \"${node}\" timed out after ${timeoutMs}ms.`\n : `Step timed out after ${timeoutMs}ms.`,\n {\n code: 'STEP_TIMEOUT',\n details: { timeoutMs, ...(node === undefined ? {} : { node }) },\n },\n );\n this.timeoutMs = timeoutMs;\n this.node = node;\n }\n}\n\nexport class NodeExecutionError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string, cause: unknown) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Node \"${node}\" failed: ${causeMessage}`, {\n code: 'NODE_EXECUTION_ERROR',\n details: { node },\n cause,\n });\n this.node = node;\n }\n}\n\nexport class WorkflowLifecycleError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'WORKFLOW_LIFECYCLE_ERROR', details });\n }\n}\n\nexport class ProjectSetupError extends WorkflowError {\n constructor(cause: unknown, details: { projectName: string }) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" setup failed: ${causeMessage}`, {\n code: 'PROJECT_SETUP_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class ProjectTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: { projectName: string; registrationIndex: number },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" teardown failed: ${causeMessage}`, {\n code: 'PROJECT_TEARDOWN_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class NodeScopeTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: {\n scope: 'case' | 'document';\n scopeId: string;\n node: string;\n registrationIndex: number;\n },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(\n `${details.scope === 'case' ? 'Case attempt' : 'Workflow document'} node teardown failed for \"${details.node}\": ${causeMessage}`,\n { code: 'NODE_SCOPE_TEARDOWN_ERROR', details, cause },\n );\n }\n}\n\nexport class FatalDeviceError extends WorkflowError {\n constructor(message: string, cause?: unknown) {\n super(message, { code: 'FATAL_DEVICE_ERROR', cause });\n }\n}\n\nexport const isFatalDeviceError = (error: unknown): boolean => {\n if (error instanceof FatalDeviceError) return true;\n if (error instanceof WorkflowError && error.code === 'FATAL_DEVICE_ERROR') {\n return true;\n }\n if (\n error instanceof Error &&\n /device offline|device not found|(?:adb|bdc|device) connection (?:was )?closed/i.test(\n error.message,\n )\n ) {\n return true;\n }\n return error instanceof Error && error.cause !== undefined\n ? isFatalDeviceError(error.cause)\n : false;\n};\n\nexport class CaseExecutionError extends WorkflowError {\n readonly result: import('./engine/types').CaseRunResult;\n\n constructor(result: import('./engine/types').CaseRunResult) {\n super(`Case \"${result.name}\" failed.`, {\n code: 'CASE_EXECUTION_FAILED',\n details: { caseId: result.caseId, runId: result.runId },\n });\n this.result = result;\n }\n}\n\nexport class WorkflowDocumentExecutionError extends WorkflowError {\n readonly result: import('./engine/types').WorkflowDocumentRunResult;\n\n constructor(result: import('./engine/types').WorkflowDocumentRunResult) {\n super(`Workflow document \"${result.sourcePath}\" failed.`, {\n code: 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n details: {\n documentId: result.documentId,\n documentRunId: result.documentRunId,\n },\n });\n this.result = result;\n }\n}\n\nexport function normalizeNodeExecutionError(\n error: unknown,\n node: string,\n): WorkflowError {\n return error instanceof WorkflowError\n ? error\n : new NodeExecutionError(node, error);\n}\n","import { z } from 'zod/v4';\nimport { NodeDefinitionError } from '../errors';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\nconst validateOptionalText = (\n value: unknown,\n field: 'title' | 'description',\n node: string,\n): void => {\n if (\n value !== undefined &&\n (typeof value !== 'string' || value.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${node}\" ${field} must be a non-empty string.`,\n { node, field },\n );\n }\n};\n\nconst validateInputSchema = (schema: unknown, node: string): void => {\n if (schema === undefined) return;\n if (!(schema instanceof z.ZodObject)) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must be a Zod object schema.`,\n { node, field: 'inputSchema' },\n );\n }\n if ('$' in schema.shape) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must not declare \"$\" as an input property.`,\n { node, field: 'inputSchema.$' },\n );\n }\n};\n\nconst validateDefinition = (options: {\n name: string;\n title?: unknown;\n description?: unknown;\n inputSchema?: unknown;\n execute: unknown;\n}): void => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError('Node definition must be an object.');\n }\n\n if (typeof options.name !== 'string' || options.name.trim().length === 0) {\n throw new NodeDefinitionError('Node name must be a non-empty string.');\n }\n\n validateOptionalText(options.title, 'title', options.name);\n validateOptionalText(options.description, 'description', options.name);\n validateInputSchema(options.inputSchema, options.name);\n\n if (typeof options.execute !== 'function') {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" must provide an execute function.`,\n { node: options.name },\n );\n }\n};\n\nexport function defineNode<\n TSchema extends NodeInputSchema,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n\nexport function defineNode<\n TInput = unknown,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n): NodeDefinition<TInput, TData, TContext>;\n\nexport function defineNode(\n options: DefineNodeOptions<any, any, any>,\n): NodeDefinition<any, any, any> {\n validateDefinition(options);\n return options;\n}\n","const SUPPORTED_WEB_PROTOCOLS = new Set(['http:', 'https:']);\n\nexport const throwIfAborted = (signal: AbortSignal, operation: string) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error(`${operation} aborted.`);\n }\n};\n\nexport const resolveWebUrl = (\n target: string,\n baseUrl: string | undefined,\n label: string,\n): string => {\n const trimmed = target.trim();\n if (!trimmed) throw new TypeError(`${label} must not be blank.`);\n\n let resolved: URL;\n try {\n resolved =\n baseUrl === undefined ? new URL(trimmed) : new URL(trimmed, baseUrl);\n } catch (error) {\n throw new TypeError(\n baseUrl === undefined\n ? `${label} must be an absolute URL when getBaseUrl() is not configured.`\n : `${label} is not a valid URL.`,\n { cause: error },\n );\n }\n if (!SUPPORTED_WEB_PROTOCOLS.has(resolved.protocol)) {\n throw new TypeError(\n `${label} does not support the ${resolved.protocol} protocol.`,\n );\n }\n return resolved.toString();\n};\n","import type { BrowserContext } from 'playwright';\nimport { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { throwIfAborted } from './utils';\n\ntype CookieClearOptions = NonNullable<\n Parameters<BrowserContext['clearCookies']>[0]\n>;\n\n/** Input schema for the Playwright clearCookies Node. */\nexport const clearCookiesInputSchema = z.strictObject({\n name: z.string().regex(/\\S/).optional().describe('Cookie name to clear.'),\n domain: z.string().regex(/\\S/).optional().describe('Cookie domain to clear.'),\n path: z.string().regex(/\\S/).optional().describe('Cookie path to clear.'),\n});\n\n/** Validated input accepted by the Playwright clearCookies Node. */\nexport type ClearCookiesNodeInput = z.infer<typeof clearCookiesInputSchema>;\n\nexport const createClearCookiesNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<\n typeof clearCookiesInputSchema,\n { filters: CookieClearOptions },\n TContext\n >({\n name: 'clearCookies',\n title: 'Clear browser cookies',\n description:\n 'Clear all cookies from the current Playwright BrowserContext, or only cookies matching name, domain, or path.',\n inputSchema: clearCookiesInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'clearCookies');\n const page = await options.getPage(ctx);\n const filters: CookieClearOptions = {\n ...(ctx.input.name === undefined ? {} : { name: ctx.input.name }),\n ...(ctx.input.domain === undefined ? {} : { domain: ctx.input.domain }),\n ...(ctx.input.path === undefined ? {} : { path: ctx.input.path }),\n };\n await page.context().clearCookies(filters);\n const filterNames = Object.keys(filters);\n return {\n summary:\n filterNames.length === 0\n ? 'Cleared all browser cookies'\n : `Cleared browser cookies matching ${filterNames.join(', ')}`,\n data: { filters },\n };\n },\n });\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type {\n CreatePlaywrightNodesOptions,\n PlaywrightCookie,\n PlaywrightNodeContext,\n} from './types';\nimport { resolveWebUrl, throwIfAborted } from './utils';\n\ntype CookieSourceReference =\n | { kind: 'env'; name: string }\n | { kind: 'profile'; name: string }\n | { kind: 'storage-state'; name: string };\n\ninterface ResolvedCookieSource {\n reference: CookieSourceReference;\n cookies: unknown;\n}\n\n/** Input schema for the Playwright setCookies Node. */\nexport const setCookiesInputSchema = z\n .strictObject({\n cookiesEnv: z\n .string()\n .regex(/^[A-Za-z_][A-Za-z0-9_]*$/)\n .optional()\n .describe(\n 'The environment variable containing a Cookie header, cookie array JSON, or Playwright storage-state JSON.',\n ),\n profile: z\n .string()\n .regex(/\\S/)\n .optional()\n .describe('A cookie profile resolved by getCookieProfile().'),\n storageStatePath: z\n .string()\n .regex(/\\S/)\n .optional()\n .describe('A path to a Playwright storage-state JSON file.'),\n url: z\n .string()\n .url()\n .optional()\n .describe(\n 'The HTTP(S) URL used to scope Cookie-header values or cookies without domain/path.',\n ),\n })\n .superRefine((input, ctx) => {\n const sourceCount = [\n input.cookiesEnv,\n input.profile,\n input.storageStatePath,\n ].filter((value) => value !== undefined).length;\n if (sourceCount !== 1) {\n ctx.addIssue({\n code: 'custom',\n message:\n 'exactly one of cookiesEnv, profile, and storageStatePath is required',\n });\n }\n });\n\n/** Validated input accepted by the Playwright setCookies Node. */\nexport type SetCookiesNodeInput = z.infer<typeof setCookiesInputSchema>;\n\n/** Secret-free metadata returned by the Playwright setCookies Node. */\nexport interface SetCookiesNodeResult {\n /** Kind of configured reference used to resolve the cookies. */\n source: CookieSourceReference['kind'];\n /** Environment variable, profile, or storage-state reference name. */\n sourceName: string;\n /** Number of cookies passed to the BrowserContext. */\n count: number;\n}\n\nconst toCookieSourceReference = (\n input: SetCookiesNodeInput,\n): CookieSourceReference => {\n if (input.cookiesEnv !== undefined) {\n return { kind: 'env', name: input.cookiesEnv };\n }\n if (input.profile !== undefined) {\n return { kind: 'profile', name: input.profile };\n }\n if (input.storageStatePath !== undefined) {\n return { kind: 'storage-state', name: input.storageStatePath };\n }\n throw new TypeError('setCookies requires one cookie source.');\n};\n\nconst parseCookieHeader = (raw: string, url: string | undefined) => {\n if (url === undefined) {\n throw new TypeError(\n 'setCookies.url is required when cookiesEnv contains a Cookie header.',\n );\n }\n const segments = raw\n .split(';')\n .map((segment) => segment.trim())\n .filter(Boolean);\n if (segments.length === 0) {\n throw new TypeError('setCookies Cookie header contains no cookies.');\n }\n return segments.map((segment) => {\n const separator = segment.indexOf('=');\n if (separator <= 0) {\n throw new TypeError(\n 'setCookies Cookie header contains an invalid name/value pair.',\n );\n }\n const name = segment.slice(0, separator).trim();\n const value = segment.slice(separator + 1).trim();\n if (!name) {\n throw new TypeError('setCookies Cookie header contains an empty name.');\n }\n return { name, value, url } satisfies PlaywrightCookie;\n });\n};\n\nconst parseCookieJson = (raw: string): unknown => {\n try {\n return JSON.parse(raw);\n } catch {\n throw new TypeError(\n 'setCookies source must contain valid JSON or a Cookie header.',\n );\n }\n};\n\nconst resolveCookieSource = async <TContext>(\n reference: CookieSourceReference,\n defaultUrl: string | undefined,\n ctx: PlaywrightNodeContext<TContext>,\n options: CreatePlaywrightNodesOptions<TContext>,\n): Promise<ResolvedCookieSource> => {\n switch (reference.kind) {\n case 'env': {\n let env: Readonly<Record<string, string | undefined>>;\n try {\n env = (await options.getEnv?.(ctx)) ?? process.env;\n } catch {\n throw new Error(\n `Failed to resolve cookie environment ${reference.name}; the original error was redacted because it may contain cookie values.`,\n );\n }\n const raw = env[reference.name];\n if (!raw?.trim()) {\n throw new Error(\n `Environment variable ${reference.name} is missing or blank.`,\n );\n }\n const trimmed = raw.trim();\n return {\n reference,\n cookies: /^[\\[{]/.test(trimmed)\n ? parseCookieJson(trimmed)\n : parseCookieHeader(trimmed, defaultUrl),\n };\n }\n case 'profile': {\n if (!options.getCookieProfile) {\n throw new Error(\n 'setCookies.profile requires createPlaywrightNodes({ getCookieProfile }).',\n );\n }\n try {\n return {\n reference,\n cookies: await options.getCookieProfile({\n profile: reference.name,\n context: ctx.context,\n signal: ctx.signal,\n }),\n };\n } catch {\n throw new Error(\n `Failed to resolve cookie profile ${reference.name}; the original error was redacted because it may contain cookie values.`,\n );\n }\n }\n case 'storage-state': {\n const path = options.resolveStorageStatePath\n ? await options.resolveStorageStatePath(reference.name, ctx)\n : resolve(process.cwd(), reference.name);\n return {\n reference,\n cookies: parseCookieJson(await readFile(path, 'utf8')),\n };\n }\n }\n};\n\nconst normalizeCookie = (\n candidate: unknown,\n defaultUrl: string | undefined,\n index: number,\n): PlaywrightCookie => {\n if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {\n throw new TypeError(\n `setCookies cookie at index ${index} must be an object.`,\n );\n }\n const cookie = candidate as Record<string, unknown>;\n if (typeof cookie.name !== 'string' || !cookie.name.trim()) {\n throw new TypeError(\n `setCookies cookie at index ${index} requires a non-blank name.`,\n );\n }\n if (typeof cookie.value !== 'string') {\n throw new TypeError(\n `setCookies cookie at index ${index} requires a string value.`,\n );\n }\n\n const normalized = { ...cookie } as unknown as PlaywrightCookie;\n const hasUrl = typeof cookie.url === 'string' && cookie.url.length > 0;\n const hasDomain =\n typeof cookie.domain === 'string' && cookie.domain.length > 0;\n if (!hasUrl && !hasDomain) {\n if (defaultUrl === undefined) {\n throw new TypeError(\n `setCookies cookie at index ${index} requires url or domain, or setCookies.url must be provided.`,\n );\n }\n normalized.url = defaultUrl;\n }\n if (hasDomain && typeof cookie.path !== 'string') {\n normalized.path = '/';\n }\n return normalized;\n};\n\nconst normalizeCookies = (\n source: unknown,\n defaultUrl: string | undefined,\n): PlaywrightCookie[] => {\n const candidates = Array.isArray(source)\n ? source\n : source &&\n typeof source === 'object' &&\n Array.isArray((source as { cookies?: unknown }).cookies)\n ? (source as { cookies: unknown[] }).cookies\n : undefined;\n if (!candidates) {\n throw new TypeError(\n 'setCookies JSON must be a cookie array or an object with a cookies array.',\n );\n }\n if (candidates.length === 0) {\n throw new TypeError('setCookies source contains no cookies.');\n }\n return candidates.map((cookie, index) =>\n normalizeCookie(cookie, defaultUrl, index),\n );\n};\n\nexport const createSetCookiesNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<typeof setCookiesInputSchema, SetCookiesNodeResult, TContext>({\n name: 'setCookies',\n title: 'Set browser cookies',\n description:\n 'Load cookies from an environment variable, configured profile, or Playwright storage-state file without persisting cookie values in workflow input or output.',\n inputSchema: setCookiesInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'setCookies');\n const page = await options.getPage(ctx);\n const defaultUrl =\n ctx.input.url === undefined\n ? undefined\n : resolveWebUrl(ctx.input.url, undefined, 'setCookies.url');\n const reference = toCookieSourceReference(ctx.input);\n const resolved = await resolveCookieSource(\n reference,\n defaultUrl,\n ctx,\n options,\n );\n const cookies = normalizeCookies(resolved.cookies, defaultUrl);\n\n throwIfAborted(ctx.signal, 'setCookies');\n try {\n await page.context().addCookies(cookies);\n } catch {\n throw new Error(\n `Failed to set ${cookies.length} browser cookie(s); the browser error was redacted because it may contain cookie values.`,\n );\n }\n\n const result: SetCookiesNodeResult = {\n source: resolved.reference.kind,\n sourceName: resolved.reference.name,\n count: cookies.length,\n };\n return {\n summary: `Set ${result.count} browser cookie(s) from ${result.source} source ${result.sourceName}`,\n data: result,\n };\n },\n });\n","import { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { resolveWebUrl, throwIfAborted } from './utils';\n\nconst DEFAULT_NAVIGATION_TIMEOUT_MS = 60_000;\nconst DEFAULT_WAIT_UNTIL = 'domcontentloaded' as const;\n\n/** Input schema for the Playwright gotoUrl Node. */\nexport const gotoUrlInputSchema = z\n .strictObject({\n prompt: z\n .string()\n .min(1)\n .optional()\n .describe('String shorthand for the URL to open.'),\n url: z\n .string()\n .min(1)\n .optional()\n .describe('An absolute HTTP(S) URL or a path relative to baseUrl.'),\n waitUntil: z\n .enum(['commit', 'domcontentloaded', 'load', 'networkidle'])\n .default(DEFAULT_WAIT_UNTIL)\n .describe('The Playwright navigation lifecycle event to wait for.'),\n timeoutMs: z\n .number()\n .positive()\n .default(DEFAULT_NAVIGATION_TIMEOUT_MS)\n .describe('The navigation timeout in milliseconds.'),\n })\n .superRefine((input, ctx) => {\n if ((input.prompt === undefined) === (input.url === undefined)) {\n ctx.addIssue({\n code: 'custom',\n message: 'exactly one of prompt and url is required',\n });\n }\n });\n\n/** Validated input accepted by the Playwright gotoUrl Node. */\nexport type GotoUrlNodeInput = z.infer<typeof gotoUrlInputSchema>;\n\n/** Structured navigation details returned by the Playwright gotoUrl Node. */\nexport interface GotoUrlNodeResult {\n /** Final Page URL after navigation and redirects. */\n url: string;\n /** Main-resource HTTP status, or null when Playwright returns no response. */\n status: number | null;\n /** Document title after navigation completes. */\n title: string;\n}\n\nexport const createGotoUrlNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<typeof gotoUrlInputSchema, GotoUrlNodeResult, TContext>({\n name: 'gotoUrl',\n title: 'Open a Web URL',\n description:\n 'Navigate the current Playwright Page to an absolute HTTP(S) URL or a path relative to the configured baseUrl.',\n inputSchema: gotoUrlInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'gotoUrl');\n const page = await options.getPage(ctx);\n const baseUrl = await options.getBaseUrl?.(ctx);\n const target = ctx.input.url ?? ctx.input.prompt;\n if (target === undefined) {\n throw new TypeError('gotoUrl requires a URL.');\n }\n const url = resolveWebUrl(target, baseUrl, 'gotoUrl.url');\n const response = await page.goto(url, {\n waitUntil: ctx.input.waitUntil,\n timeout: ctx.input.timeoutMs,\n });\n const status = response?.status() ?? null;\n const result = {\n url: page.url(),\n status,\n title: await page.title(),\n };\n return { summary: `Navigated to ${result.url}`, data: result };\n },\n });\n","import { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { throwIfAborted } from './utils';\n\n/** Input schema for the Playwright setViewportSize Node. */\nexport const setViewportSizeInputSchema = z.strictObject({\n width: z.number().int().positive().describe('Viewport width in CSS pixels.'),\n height: z\n .number()\n .int()\n .positive()\n .describe('Viewport height in CSS pixels.'),\n});\n\n/** Validated input accepted by the Playwright setViewportSize Node. */\nexport type SetViewportSizeNodeInput = z.infer<\n typeof setViewportSizeInputSchema\n>;\n\nexport const createSetViewportSizeNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<\n typeof setViewportSizeInputSchema,\n { width: number; height: number },\n TContext\n >({\n name: 'setViewportSize',\n title: 'Set the browser viewport size',\n description:\n 'Set the current Playwright Page viewport size in CSS pixels and return the effective size.',\n inputSchema: setViewportSizeInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'setViewportSize');\n const page = await options.getPage(ctx);\n await page.setViewportSize({\n width: ctx.input.width,\n height: ctx.input.height,\n });\n const viewport = page.viewportSize();\n if (!viewport) {\n throw new Error(\n 'Playwright did not report an effective viewport size.',\n );\n }\n return {\n summary: `Set viewport to ${viewport.width}x${viewport.height}`,\n data: viewport,\n };\n },\n });\n","import { NodeDefinitionError } from '../errors';\nimport type { NodeDefinition } from '../node/types';\nimport { createClearCookiesNode } from './clear-cookies';\nimport { createSetCookiesNode } from './cookies';\nimport { createGotoUrlNode } from './goto-url';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { createSetViewportSizeNode } from './viewport';\n\nexport { clearCookiesInputSchema } from './clear-cookies';\nexport type { ClearCookiesNodeInput } from './clear-cookies';\nexport { setCookiesInputSchema } from './cookies';\nexport type {\n SetCookiesNodeInput,\n SetCookiesNodeResult,\n} from './cookies';\nexport { gotoUrlInputSchema } from './goto-url';\nexport type { GotoUrlNodeInput, GotoUrlNodeResult } from './goto-url';\nexport type {\n CreatePlaywrightNodesOptions,\n PlaywrightCookieProfileContext,\n} from './types';\nexport { setViewportSizeInputSchema } from './viewport';\nexport type { SetViewportSizeNodeInput } from './viewport';\n\nconst requireOptions = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n) => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createPlaywrightNodes() options must be an object.',\n );\n }\n if (typeof options.getPage !== 'function') {\n throw new NodeDefinitionError(\n 'createPlaywrightNodes() requires getPage().',\n );\n }\n};\n\n/**\n * Create the P0 Playwright preset Nodes without assuming Project Context field\n * names. Cookie values must be resolved through configured references and are\n * never accepted as inline Node input.\n */\nexport function createPlaywrightNodes<TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n requireOptions(options);\n return [\n createGotoUrlNode(options),\n createSetCookiesNode(options),\n createClearCookiesNode(options),\n createSetViewportSizeNode(options),\n ];\n}\n"],"names":["WorkflowError","Error","undefined","message","options","NodeDefinitionError","details","validateOptionalText","value","field","node","validateInputSchema","schema","z","validateDefinition","defineNode","SUPPORTED_WEB_PROTOCOLS","Set","throwIfAborted","signal","operation","resolveWebUrl","target","baseUrl","label","trimmed","TypeError","resolved","URL","error","clearCookiesInputSchema","createClearCookiesNode","ctx","page","filters","filterNames","Object","setCookiesInputSchema","input","sourceCount","toCookieSourceReference","parseCookieHeader","raw","url","segments","segment","Boolean","separator","name","parseCookieJson","JSON","resolveCookieSource","reference","defaultUrl","env","process","path","resolve","readFile","normalizeCookie","candidate","index","Array","cookie","normalized","hasUrl","hasDomain","normalizeCookies","source","candidates","createSetCookiesNode","cookies","result","DEFAULT_NAVIGATION_TIMEOUT_MS","DEFAULT_WAIT_UNTIL","gotoUrlInputSchema","createGotoUrlNode","response","status","setViewportSizeInputSchema","createSetViewportSizeNode","viewport","requireOptions","createPlaywrightNodes"],"mappings":";;;;;;;;;;;;;AAQO,MAAMA,sBAAsBC;IAWjC,SAAkC;QAChC,OAAO;YACL,MAAM,IAAI,CAAC,IAAI;YACf,SAAS,IAAI,CAAC,OAAO;YACrB,MAAM,IAAI,CAAC,IAAI;YACf,GAAI,AAAiBC,WAAjB,IAAI,CAAC,OAAO,GAAiB,CAAC,IAAI;gBAAE,SAAS,IAAI,CAAC,OAAO;YAAC,CAAC;QACjE;IACF;IAdA,YAAYC,OAAe,EAAEC,UAAgC,CAAC,CAAC,CAAE;QAC/D,KAAK,CAACD,SAAS;YAAE,OAAOC,QAAQ,KAAK;QAAC,IAJxC,uBAAS,QAAT,SACA,uBAAS,WAAT;QAIE,IAAI,CAAC,IAAI,GAAG,WAAW,IAAI;QAC3B,IAAI,CAAC,IAAI,GAAGA,QAAQ,IAAI,IAAI;QAC5B,IAAI,CAAC,OAAO,GAAGA,QAAQ,OAAO;IAChC;AAUF;AAQO,MAAMC,4BAA4BL;IACvC,YAAYG,OAAe,EAAEG,OAAiB,CAAE;QAC9C,KAAK,CAACH,SAAS;YAAE,MAAM;YAAyBG;QAAQ;IAC1D;AACF;AC7BA,MAAMC,uBAAuB,CAC3BC,OACAC,OACAC;IAEA,IACEF,AAAUN,WAAVM,SACC,CAAiB,YAAjB,OAAOA,SAAsBA,AAAwB,MAAxBA,MAAM,IAAI,GAAG,MAAM,AAAK,GAEtD,MAAM,IAAIH,oBACR,CAAC,MAAM,EAAEK,KAAK,EAAE,EAAED,MAAM,4BAA4B,CAAC,EACrD;QAAEC;QAAMD;IAAM;AAGpB;AAEA,MAAME,sBAAsB,CAACC,QAAiBF;IAC5C,IAAIE,AAAWV,WAAXU,QAAsB;IAC1B,IAAI,CAAEA,CAAAA,kBAAkBC,EAAE,SAAQ,GAChC,MAAM,IAAIR,oBACR,CAAC,MAAM,EAAEK,KAAK,0CAA0C,CAAC,EACzD;QAAEA;QAAM,OAAO;IAAc;IAGjC,IAAI,OAAOE,OAAO,KAAK,EACrB,MAAM,IAAIP,oBACR,CAAC,MAAM,EAAEK,KAAK,wDAAwD,CAAC,EACvE;QAAEA;QAAM,OAAO;IAAgB;AAGrC;AAEA,MAAMI,qBAAqB,CAACV;IAO1B,IAAI,CAACA,WAAW,AAAmB,YAAnB,OAAOA,SACrB,MAAM,IAAIC,oBAAoB;IAGhC,IAAI,AAAwB,YAAxB,OAAOD,QAAQ,IAAI,IAAiBA,AAA+B,MAA/BA,QAAQ,IAAI,CAAC,IAAI,GAAG,MAAM,EAChE,MAAM,IAAIC,oBAAoB;IAGhCE,qBAAqBH,QAAQ,KAAK,EAAE,SAASA,QAAQ,IAAI;IACzDG,qBAAqBH,QAAQ,WAAW,EAAE,eAAeA,QAAQ,IAAI;IACrEO,oBAAoBP,QAAQ,WAAW,EAAEA,QAAQ,IAAI;IAErD,IAAI,AAA2B,cAA3B,OAAOA,QAAQ,OAAO,EACxB,MAAM,IAAIC,oBACR,CAAC,MAAM,EAAED,QAAQ,IAAI,CAAC,mCAAmC,CAAC,EAC1D;QAAE,MAAMA,QAAQ,IAAI;IAAC;AAG3B;AAkBO,SAASW,WACdX,OAAyC;IAEzCU,mBAAmBV;IACnB,OAAOA;AACT;AC1FA,MAAMY,0BAA0B,IAAIC,IAAI;IAAC;IAAS;CAAS;AAEpD,MAAMC,iBAAiB,CAACC,QAAqBC;IAClD,IAAID,OAAO,OAAO,EAChB,MAAMA,OAAO,MAAM,IAAI,IAAIlB,MAAM,GAAGmB,UAAU,SAAS,CAAC;AAE5D;AAEO,MAAMC,gBAAgB,CAC3BC,QACAC,SACAC;IAEA,MAAMC,UAAUH,OAAO,IAAI;IAC3B,IAAI,CAACG,SAAS,MAAM,IAAIC,UAAU,GAAGF,MAAM,mBAAmB,CAAC;IAE/D,IAAIG;IACJ,IAAI;QACFA,WACEJ,AAAYrB,WAAZqB,UAAwB,IAAIK,IAAIH,WAAW,IAAIG,IAAIH,SAASF;IAChE,EAAE,OAAOM,OAAO;QACd,MAAM,IAAIH,UACRH,AAAYrB,WAAZqB,UACI,GAAGC,MAAM,6DAA6D,CAAC,GACvE,GAAGA,MAAM,oBAAoB,CAAC,EAClC;YAAE,OAAOK;QAAM;IAEnB;IACA,IAAI,CAACb,wBAAwB,GAAG,CAACW,SAAS,QAAQ,GAChD,MAAM,IAAID,UACR,GAAGF,MAAM,sBAAsB,EAAEG,SAAS,QAAQ,CAAC,UAAU,CAAC;IAGlE,OAAOA,SAAS,QAAQ;AAC1B;ACtBO,MAAMG,0BAA0BjB,EAAE,YAAY,CAAC;IACpD,MAAMA,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;IACjD,QAAQA,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;IACnD,MAAMA,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;AACnD;AAKO,MAAMkB,yBAAyB,CACpC3B,UAEAW,WAIE;QACA,MAAM;QACN,OAAO;QACP,aACE;QACF,aAAae;QACb,MAAM,SAAQE,GAAG;YACfd,eAAec,IAAI,MAAM,EAAE;YAC3B,MAAMC,OAAO,MAAM7B,QAAQ,OAAO,CAAC4B;YACnC,MAAME,UAA8B;gBAClC,GAAIF,AAAmB9B,WAAnB8B,IAAI,KAAK,CAAC,IAAI,GAAiB,CAAC,IAAI;oBAAE,MAAMA,IAAI,KAAK,CAAC,IAAI;gBAAC,CAAC;gBAChE,GAAIA,AAAqB9B,WAArB8B,IAAI,KAAK,CAAC,MAAM,GAAiB,CAAC,IAAI;oBAAE,QAAQA,IAAI,KAAK,CAAC,MAAM;gBAAC,CAAC;gBACtE,GAAIA,AAAmB9B,WAAnB8B,IAAI,KAAK,CAAC,IAAI,GAAiB,CAAC,IAAI;oBAAE,MAAMA,IAAI,KAAK,CAAC,IAAI;gBAAC,CAAC;YAClE;YACA,MAAMC,KAAK,OAAO,GAAG,YAAY,CAACC;YAClC,MAAMC,cAAcC,OAAO,IAAI,CAACF;YAChC,OAAO;gBACL,SACEC,AAAuB,MAAvBA,YAAY,MAAM,GACd,gCACA,CAAC,iCAAiC,EAAEA,YAAY,IAAI,CAAC,OAAO;gBAClE,MAAM;oBAAED;gBAAQ;YAClB;QACF;IACF;AC7BK,MAAMG,wBAAwBxB,EAAAA,YACtB,CAAC;IACZ,YAAYA,EAAAA,MACH,GACN,KAAK,CAAC,4BACN,QAAQ,GACR,QAAQ,CACP;IAEJ,SAASA,EAAAA,MACA,GACN,KAAK,CAAC,MACN,QAAQ,GACR,QAAQ,CAAC;IACZ,kBAAkBA,EAAAA,MACT,GACN,KAAK,CAAC,MACN,QAAQ,GACR,QAAQ,CAAC;IACZ,KAAKA,EAAAA,MACI,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CACP;AAEN,GACC,WAAW,CAAC,CAACyB,OAAON;IACnB,MAAMO,cAAc;QAClBD,MAAM,UAAU;QAChBA,MAAM,OAAO;QACbA,MAAM,gBAAgB;KACvB,CAAC,MAAM,CAAC,CAAC9B,QAAUA,AAAUN,WAAVM,OAAqB,MAAM;IAC/C,IAAI+B,AAAgB,MAAhBA,aACFP,IAAI,QAAQ,CAAC;QACX,MAAM;QACN,SACE;IACJ;AAEJ;AAeF,MAAMQ,0BAA0B,CAC9BF;IAEA,IAAIA,AAAqBpC,WAArBoC,MAAM,UAAU,EAClB,OAAO;QAAE,MAAM;QAAO,MAAMA,MAAM,UAAU;IAAC;IAE/C,IAAIA,AAAkBpC,WAAlBoC,MAAM,OAAO,EACf,OAAO;QAAE,MAAM;QAAW,MAAMA,MAAM,OAAO;IAAC;IAEhD,IAAIA,AAA2BpC,WAA3BoC,MAAM,gBAAgB,EACxB,OAAO;QAAE,MAAM;QAAiB,MAAMA,MAAM,gBAAgB;IAAC;IAE/D,MAAM,IAAIZ,UAAU;AACtB;AAEA,MAAMe,oBAAoB,CAACC,KAAaC;IACtC,IAAIA,AAAQzC,WAARyC,KACF,MAAM,IAAIjB,UACR;IAGJ,MAAMkB,WAAWF,IACd,KAAK,CAAC,KACN,GAAG,CAAC,CAACG,UAAYA,QAAQ,IAAI,IAC7B,MAAM,CAACC;IACV,IAAIF,AAAoB,MAApBA,SAAS,MAAM,EACjB,MAAM,IAAIlB,UAAU;IAEtB,OAAOkB,SAAS,GAAG,CAAC,CAACC;QACnB,MAAME,YAAYF,QAAQ,OAAO,CAAC;QAClC,IAAIE,aAAa,GACf,MAAM,IAAIrB,UACR;QAGJ,MAAMsB,OAAOH,QAAQ,KAAK,CAAC,GAAGE,WAAW,IAAI;QAC7C,MAAMvC,QAAQqC,QAAQ,KAAK,CAACE,YAAY,GAAG,IAAI;QAC/C,IAAI,CAACC,MACH,MAAM,IAAItB,UAAU;QAEtB,OAAO;YAAEsB;YAAMxC;YAAOmC;QAAI;IAC5B;AACF;AAEA,MAAMM,kBAAkB,CAACP;IACvB,IAAI;QACF,OAAOQ,KAAK,KAAK,CAACR;IACpB,EAAE,OAAM;QACN,MAAM,IAAIhB,UACR;IAEJ;AACF;AAEA,MAAMyB,sBAAsB,OAC1BC,WACAC,YACArB,KACA5B;IAEA,OAAQgD,UAAU,IAAI;QACpB,KAAK;YAAO;gBACV,IAAIE;gBACJ,IAAI;oBACFA,MAAO,MAAMlD,QAAQ,MAAM,GAAG4B,QAASuB,QAAQ,GAAG;gBACpD,EAAE,OAAM;oBACN,MAAM,IAAItD,MACR,CAAC,qCAAqC,EAAEmD,UAAU,IAAI,CAAC,uEAAuE,CAAC;gBAEnI;gBACA,MAAMV,MAAMY,GAAG,CAACF,UAAU,IAAI,CAAC;gBAC/B,IAAI,CAACV,KAAK,QACR,MAAM,IAAIzC,MACR,CAAC,qBAAqB,EAAEmD,UAAU,IAAI,CAAC,qBAAqB,CAAC;gBAGjE,MAAM3B,UAAUiB,IAAI,IAAI;gBACxB,OAAO;oBACLU;oBACA,SAAS,SAAS,IAAI,CAAC3B,WACnBwB,gBAAgBxB,WAChBgB,kBAAkBhB,SAAS4B;gBACjC;YACF;QACA,KAAK;YACH,IAAI,CAACjD,QAAQ,gBAAgB,EAC3B,MAAM,IAAIH,MACR;YAGJ,IAAI;gBACF,OAAO;oBACLmD;oBACA,SAAS,MAAMhD,QAAQ,gBAAgB,CAAC;wBACtC,SAASgD,UAAU,IAAI;wBACvB,SAASpB,IAAI,OAAO;wBACpB,QAAQA,IAAI,MAAM;oBACpB;gBACF;YACF,EAAE,OAAM;gBACN,MAAM,IAAI/B,MACR,CAAC,iCAAiC,EAAEmD,UAAU,IAAI,CAAC,uEAAuE,CAAC;YAE/H;QAEF,KAAK;YAAiB;gBACpB,MAAMI,OAAOpD,QAAQ,uBAAuB,GACxC,MAAMA,QAAQ,uBAAuB,CAACgD,UAAU,IAAI,EAAEpB,OACtDyB,QAAQF,QAAQ,GAAG,IAAIH,UAAU,IAAI;gBACzC,OAAO;oBACLA;oBACA,SAASH,gBAAgB,MAAMS,SAASF,MAAM;gBAChD;YACF;IACF;AACF;AAEA,MAAMG,kBAAkB,CACtBC,WACAP,YACAQ;IAEA,IAAI,CAACD,aAAa,AAAqB,YAArB,OAAOA,aAA0BE,MAAM,OAAO,CAACF,YAC/D,MAAM,IAAIlC,UACR,CAAC,2BAA2B,EAAEmC,MAAM,mBAAmB,CAAC;IAG5D,MAAME,SAASH;IACf,IAAI,AAAuB,YAAvB,OAAOG,OAAO,IAAI,IAAiB,CAACA,OAAO,IAAI,CAAC,IAAI,IACtD,MAAM,IAAIrC,UACR,CAAC,2BAA2B,EAAEmC,MAAM,2BAA2B,CAAC;IAGpE,IAAI,AAAwB,YAAxB,OAAOE,OAAO,KAAK,EACrB,MAAM,IAAIrC,UACR,CAAC,2BAA2B,EAAEmC,MAAM,yBAAyB,CAAC;IAIlE,MAAMG,aAAa;QAAE,GAAGD,MAAM;IAAC;IAC/B,MAAME,SAAS,AAAsB,YAAtB,OAAOF,OAAO,GAAG,IAAiBA,OAAO,GAAG,CAAC,MAAM,GAAG;IACrE,MAAMG,YACJ,AAAyB,YAAzB,OAAOH,OAAO,MAAM,IAAiBA,OAAO,MAAM,CAAC,MAAM,GAAG;IAC9D,IAAI,CAACE,UAAU,CAACC,WAAW;QACzB,IAAIb,AAAenD,WAAfmD,YACF,MAAM,IAAI3B,UACR,CAAC,2BAA2B,EAAEmC,MAAM,4DAA4D,CAAC;QAGrGG,WAAW,GAAG,GAAGX;IACnB;IACA,IAAIa,aAAa,AAAuB,YAAvB,OAAOH,OAAO,IAAI,EACjCC,WAAW,IAAI,GAAG;IAEpB,OAAOA;AACT;AAEA,MAAMG,mBAAmB,CACvBC,QACAf;IAEA,MAAMgB,aAAaP,MAAM,OAAO,CAACM,UAC7BA,SACAA,UACE,AAAkB,YAAlB,OAAOA,UACPN,MAAM,OAAO,CAAEM,OAAiC,OAAO,IACtDA,OAAkC,OAAO,GAC1ClE;IACN,IAAI,CAACmE,YACH,MAAM,IAAI3C,UACR;IAGJ,IAAI2C,AAAsB,MAAtBA,WAAW,MAAM,EACnB,MAAM,IAAI3C,UAAU;IAEtB,OAAO2C,WAAW,GAAG,CAAC,CAACN,QAAQF,QAC7BF,gBAAgBI,QAAQV,YAAYQ;AAExC;AAEO,MAAMS,uBAAuB,CAClClE,UAEAW,WAAyE;QACvE,MAAM;QACN,OAAO;QACP,aACE;QACF,aAAasB;QACb,MAAM,SAAQL,GAAG;YACfd,eAAec,IAAI,MAAM,EAAE;YAC3B,MAAMC,OAAO,MAAM7B,QAAQ,OAAO,CAAC4B;YACnC,MAAMqB,aACJrB,AAAkB9B,WAAlB8B,IAAI,KAAK,CAAC,GAAG,GACT9B,SACAmB,cAAcW,IAAI,KAAK,CAAC,GAAG,EAAE9B,QAAW;YAC9C,MAAMkD,YAAYZ,wBAAwBR,IAAI,KAAK;YACnD,MAAML,WAAW,MAAMwB,oBACrBC,WACAC,YACArB,KACA5B;YAEF,MAAMmE,UAAUJ,iBAAiBxC,SAAS,OAAO,EAAE0B;YAEnDnC,eAAec,IAAI,MAAM,EAAE;YAC3B,IAAI;gBACF,MAAMC,KAAK,OAAO,GAAG,UAAU,CAACsC;YAClC,EAAE,OAAM;gBACN,MAAM,IAAItE,MACR,CAAC,cAAc,EAAEsE,QAAQ,MAAM,CAAC,wFAAwF,CAAC;YAE7H;YAEA,MAAMC,SAA+B;gBACnC,QAAQ7C,SAAS,SAAS,CAAC,IAAI;gBAC/B,YAAYA,SAAS,SAAS,CAAC,IAAI;gBACnC,OAAO4C,QAAQ,MAAM;YACvB;YACA,OAAO;gBACL,SAAS,CAAC,IAAI,EAAEC,OAAO,KAAK,CAAC,wBAAwB,EAAEA,OAAO,MAAM,CAAC,QAAQ,EAAEA,OAAO,UAAU,EAAE;gBAClG,MAAMA;YACR;QACF;IACF;ACzSF,MAAMC,gCAAgC;AACtC,MAAMC,qBAAqB;AAGpB,MAAMC,qBAAqB9D,EAAAA,YACnB,CAAC;IACZ,QAAQA,EAAAA,MACC,GACN,GAAG,CAAC,GACJ,QAAQ,GACR,QAAQ,CAAC;IACZ,KAAKA,EAAAA,MACI,GACN,GAAG,CAAC,GACJ,QAAQ,GACR,QAAQ,CAAC;IACZ,WAAWA,CAAC,CAADA,OACJ,CAAC;QAAC;QAAU;QAAoB;QAAQ;KAAc,EAC1D,OAAO,CAAC6D,oBACR,QAAQ,CAAC;IACZ,WAAW7D,EAAAA,MACF,GACN,QAAQ,GACR,OAAO,CAAC4D,+BACR,QAAQ,CAAC;AACd,GACC,WAAW,CAAC,CAACnC,OAAON;IACnB,IAAKM,AAAiBpC,WAAjBoC,MAAM,MAAM,KAAqBA,CAAAA,AAAcpC,WAAdoC,MAAM,GAAG,AAAa,GAC1DN,IAAI,QAAQ,CAAC;QACX,MAAM;QACN,SAAS;IACX;AAEJ;AAeK,MAAM4C,oBAAoB,CAC/BxE,UAEAW,WAAmE;QACjE,MAAM;QACN,OAAO;QACP,aACE;QACF,aAAa4D;QACb,MAAM,SAAQ3C,GAAG;YACfd,eAAec,IAAI,MAAM,EAAE;YAC3B,MAAMC,OAAO,MAAM7B,QAAQ,OAAO,CAAC4B;YACnC,MAAMT,UAAU,MAAMnB,QAAQ,UAAU,GAAG4B;YAC3C,MAAMV,SAASU,IAAI,KAAK,CAAC,GAAG,IAAIA,IAAI,KAAK,CAAC,MAAM;YAChD,IAAIV,AAAWpB,WAAXoB,QACF,MAAM,IAAII,UAAU;YAEtB,MAAMiB,MAAMtB,cAAcC,QAAQC,SAAS;YAC3C,MAAMsD,WAAW,MAAM5C,KAAK,IAAI,CAACU,KAAK;gBACpC,WAAWX,IAAI,KAAK,CAAC,SAAS;gBAC9B,SAASA,IAAI,KAAK,CAAC,SAAS;YAC9B;YACA,MAAM8C,SAASD,UAAU,YAAY;YACrC,MAAML,SAAS;gBACb,KAAKvC,KAAK,GAAG;gBACb6C;gBACA,OAAO,MAAM7C,KAAK,KAAK;YACzB;YACA,OAAO;gBAAE,SAAS,CAAC,aAAa,EAAEuC,OAAO,GAAG,EAAE;gBAAE,MAAMA;YAAO;QAC/D;IACF;AC7EK,MAAMO,6BAA6BlE,EAAE,YAAY,CAAC;IACvD,OAAOA,EAAE,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,QAAQA,EAAAA,MACC,GACN,GAAG,GACH,QAAQ,GACR,QAAQ,CAAC;AACd;AAOO,MAAMmE,4BAA4B,CACvC5E,UAEAW,WAIE;QACA,MAAM;QACN,OAAO;QACP,aACE;QACF,aAAagE;QACb,MAAM,SAAQ/C,GAAG;YACfd,eAAec,IAAI,MAAM,EAAE;YAC3B,MAAMC,OAAO,MAAM7B,QAAQ,OAAO,CAAC4B;YACnC,MAAMC,KAAK,eAAe,CAAC;gBACzB,OAAOD,IAAI,KAAK,CAAC,KAAK;gBACtB,QAAQA,IAAI,KAAK,CAAC,MAAM;YAC1B;YACA,MAAMiD,WAAWhD,KAAK,YAAY;YAClC,IAAI,CAACgD,UACH,MAAM,IAAIhF,MACR;YAGJ,OAAO;gBACL,SAAS,CAAC,gBAAgB,EAAEgF,SAAS,KAAK,CAAC,CAAC,EAAEA,SAAS,MAAM,EAAE;gBAC/D,MAAMA;YACR;QACF;IACF;AC5BF,MAAMC,iBAAiB,CACrB9E;IAEA,IAAI,CAACA,WAAW,AAAmB,YAAnB,OAAOA,SACrB,MAAM,IAAIC,oBACR;IAGJ,IAAI,AAA2B,cAA3B,OAAOD,QAAQ,OAAO,EACxB,MAAM,IAAIC,oBACR;AAGN;AAOO,SAAS8E,sBACd/E,OAA+C;IAE/C8E,eAAe9E;IACf,OAAO;QACLwE,kBAAkBxE;QAClBkE,qBAAqBlE;QACrB2B,uBAAuB3B;QACvB4E,0BAA0B5E;KAC3B;AACH"}
1
+ {"version":3,"file":"playwright/index.mjs","sources":["../../../src/errors.ts","../../../src/node/define-node.ts","../../../src/playwright/utils.ts","../../../src/playwright/clear-cookies.ts","../../../src/playwright/cookies.ts","../../../src/playwright/goto-url.ts","../../../src/playwright/viewport.ts","../../../src/playwright/index.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\nexport interface WorkflowErrorOptions {\n code?: string;\n details?: unknown;\n cause?: unknown;\n}\n\nexport class WorkflowError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, options: WorkflowErrorOptions = {}) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code ?? 'WORKFLOW_ERROR';\n this.details = options.details;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n ...(this.details === undefined ? {} : { details: this.details }),\n };\n }\n}\n\nexport class WorkflowParseError extends WorkflowError {\n constructor(message: string, details?: unknown, cause?: unknown) {\n super(message, { code: 'WORKFLOW_PARSE_ERROR', details, cause });\n }\n}\n\nexport class NodeDefinitionError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_DEFINITION_ERROR', details });\n }\n}\n\nexport class DuplicateNodeError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is already registered.`, {\n code: 'DUPLICATE_NODE',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeNotFoundError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is not registered.`, {\n code: 'NODE_NOT_FOUND',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeInputValidationError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_INPUT_VALIDATION_ERROR', details });\n }\n\n static fromZod(node: string, error: z.ZodError): NodeInputValidationError {\n const issues = error.issues.map((issue) => ({\n code: issue.code,\n path: issue.path.map(String).join('.'),\n message: issue.message,\n }));\n const firstIssue = issues[0];\n const path = firstIssue?.path || '<root>';\n const message = firstIssue?.message ?? 'invalid input';\n return new NodeInputValidationError(\n `Node \"${node}\" input validation failed at \"${path}\": ${message}`,\n { node, issues },\n );\n }\n}\n\nexport class StepTimeoutError extends WorkflowError {\n readonly timeoutMs: number;\n readonly node?: string;\n\n constructor(timeoutMs: number, node?: string) {\n super(\n node\n ? `Node \"${node}\" timed out after ${timeoutMs}ms.`\n : `Step timed out after ${timeoutMs}ms.`,\n {\n code: 'STEP_TIMEOUT',\n details: { timeoutMs, ...(node === undefined ? {} : { node }) },\n },\n );\n this.timeoutMs = timeoutMs;\n this.node = node;\n }\n}\n\nexport class NodeExecutionError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string, cause: unknown) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Node \"${node}\" failed: ${causeMessage}`, {\n code: 'NODE_EXECUTION_ERROR',\n details: { node },\n cause,\n });\n this.node = node;\n }\n}\n\nexport class WorkflowLifecycleError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'WORKFLOW_LIFECYCLE_ERROR', details });\n }\n}\n\nexport class ProjectSetupError extends WorkflowError {\n constructor(cause: unknown, details: { projectName: string }) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" setup failed: ${causeMessage}`, {\n code: 'PROJECT_SETUP_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class ProjectTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: { projectName: string; registrationIndex: number },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" teardown failed: ${causeMessage}`, {\n code: 'PROJECT_TEARDOWN_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class NodeScopeTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: {\n scope: 'case' | 'document';\n scopeId: string;\n node: string;\n registrationIndex: number;\n },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(\n `${details.scope === 'case' ? 'Case attempt' : 'Workflow document'} node teardown failed for \"${details.node}\": ${causeMessage}`,\n { code: 'NODE_SCOPE_TEARDOWN_ERROR', details, cause },\n );\n }\n}\n\nexport class FatalDeviceError extends WorkflowError {\n constructor(message: string, cause?: unknown) {\n super(message, { code: 'FATAL_DEVICE_ERROR', cause });\n }\n}\n\nexport const isFatalDeviceError = (error: unknown): boolean => {\n if (error instanceof FatalDeviceError) return true;\n if (error instanceof WorkflowError && error.code === 'FATAL_DEVICE_ERROR') {\n return true;\n }\n if (\n error instanceof Error &&\n /device offline|device not found|(?:adb|bdc|device) connection (?:was )?closed/i.test(\n error.message,\n )\n ) {\n return true;\n }\n return error instanceof Error && error.cause !== undefined\n ? isFatalDeviceError(error.cause)\n : false;\n};\n\nexport class CaseExecutionError extends WorkflowError {\n readonly result: import('./engine/types').CaseRunResult;\n\n constructor(result: import('./engine/types').CaseRunResult) {\n super(`Case \"${result.name}\" failed.`, {\n code: 'CASE_EXECUTION_FAILED',\n details: { caseId: result.caseId, runId: result.runId },\n });\n this.result = result;\n }\n}\n\nexport class WorkflowDocumentExecutionError extends WorkflowError {\n readonly result: import('./engine/types').WorkflowDocumentRunResult;\n\n constructor(result: import('./engine/types').WorkflowDocumentRunResult) {\n super(`Workflow document \"${result.sourcePath}\" failed.`, {\n code: 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n details: {\n documentId: result.documentId,\n documentRunId: result.documentRunId,\n },\n });\n this.result = result;\n }\n}\n\nexport function normalizeNodeExecutionError(\n error: unknown,\n node: string,\n): WorkflowError {\n return error instanceof WorkflowError\n ? error\n : new NodeExecutionError(node, error);\n}\n","import { z } from 'zod/v4';\nimport { NodeDefinitionError } from '../errors';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\nconst validateOptionalText = (\n value: unknown,\n field: 'title' | 'description',\n node: string,\n): void => {\n if (\n value !== undefined &&\n (typeof value !== 'string' || value.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${node}\" ${field} must be a non-empty string.`,\n { node, field },\n );\n }\n};\n\nconst validateInputSchema = (schema: unknown, node: string): void => {\n if (schema === undefined) return;\n if (!(schema instanceof z.ZodObject)) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must be a Zod object schema.`,\n { node, field: 'inputSchema' },\n );\n }\n if ('$' in schema.shape) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must not declare \"$\" as an input property.`,\n { node, field: 'inputSchema.$' },\n );\n }\n};\n\nconst validateDefinition = (options: {\n name: string;\n title?: unknown;\n description?: unknown;\n stringInputKey?: unknown;\n inputSchema?: unknown;\n execute: unknown;\n}): void => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError('Node definition must be an object.');\n }\n\n if (typeof options.name !== 'string' || options.name.trim().length === 0) {\n throw new NodeDefinitionError('Node name must be a non-empty string.');\n }\n\n validateOptionalText(options.title, 'title', options.name);\n validateOptionalText(options.description, 'description', options.name);\n if (\n options.stringInputKey !== undefined &&\n options.stringInputKey !== false &&\n (typeof options.stringInputKey !== 'string' ||\n options.stringInputKey.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must be a non-empty string or false.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n validateInputSchema(options.inputSchema, options.name);\n\n if (\n typeof options.stringInputKey === 'string' &&\n options.inputSchema instanceof z.ZodObject &&\n !(options.stringInputKey in options.inputSchema.shape)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must reference a field in inputSchema.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n\n if (typeof options.execute !== 'function') {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" must provide an execute function.`,\n { node: options.name },\n );\n }\n};\n\nexport function defineNode<\n TSchema extends NodeInputSchema,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n\nexport function defineNode<\n TInput = unknown,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n): NodeDefinition<TInput, TData, TContext>;\n\nexport function defineNode(\n options: DefineNodeOptions<any, any, any>,\n): NodeDefinition<any, any, any> {\n validateDefinition(options);\n return options;\n}\n","const SUPPORTED_WEB_PROTOCOLS = new Set(['http:', 'https:']);\n\nexport const throwIfAborted = (signal: AbortSignal, operation: string) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error(`${operation} aborted.`);\n }\n};\n\nexport const resolveWebUrl = (\n target: string,\n baseUrl: string | undefined,\n label: string,\n): string => {\n const trimmed = target.trim();\n if (!trimmed) throw new TypeError(`${label} must not be blank.`);\n\n let resolved: URL;\n try {\n resolved =\n baseUrl === undefined ? new URL(trimmed) : new URL(trimmed, baseUrl);\n } catch (error) {\n throw new TypeError(\n baseUrl === undefined\n ? `${label} must be an absolute URL when getBaseUrl() is not configured.`\n : `${label} is not a valid URL.`,\n { cause: error },\n );\n }\n if (!SUPPORTED_WEB_PROTOCOLS.has(resolved.protocol)) {\n throw new TypeError(\n `${label} does not support the ${resolved.protocol} protocol.`,\n );\n }\n return resolved.toString();\n};\n","import type { BrowserContext } from 'playwright';\nimport { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { throwIfAborted } from './utils';\n\ntype CookieClearOptions = NonNullable<\n Parameters<BrowserContext['clearCookies']>[0]\n>;\n\n/** Input schema for the Playwright clearCookies Node. */\nexport const clearCookiesInputSchema = z.strictObject({\n name: z.string().regex(/\\S/).optional().describe('Cookie name to clear.'),\n domain: z.string().regex(/\\S/).optional().describe('Cookie domain to clear.'),\n path: z.string().regex(/\\S/).optional().describe('Cookie path to clear.'),\n});\n\n/** Validated input accepted by the Playwright clearCookies Node. */\nexport type ClearCookiesNodeInput = z.infer<typeof clearCookiesInputSchema>;\n\nexport const createClearCookiesNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<\n typeof clearCookiesInputSchema,\n { filters: CookieClearOptions },\n TContext\n >({\n name: 'clearCookies',\n title: 'Clear browser cookies',\n description:\n 'Clear all cookies from the current Playwright BrowserContext, or only cookies matching name, domain, or path.',\n stringInputKey: false,\n inputSchema: clearCookiesInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'clearCookies');\n const page = await options.getPage(ctx);\n const filters: CookieClearOptions = {\n ...(ctx.input.name === undefined ? {} : { name: ctx.input.name }),\n ...(ctx.input.domain === undefined ? {} : { domain: ctx.input.domain }),\n ...(ctx.input.path === undefined ? {} : { path: ctx.input.path }),\n };\n await page.context().clearCookies(filters);\n const filterNames = Object.keys(filters);\n return {\n summary:\n filterNames.length === 0\n ? 'Cleared all browser cookies'\n : `Cleared browser cookies matching ${filterNames.join(', ')}`,\n data: { filters },\n };\n },\n });\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type {\n CreatePlaywrightNodesOptions,\n PlaywrightCookie,\n PlaywrightNodeContext,\n} from './types';\nimport { resolveWebUrl, throwIfAborted } from './utils';\n\ntype CookieSourceReference =\n | { kind: 'env'; name: string }\n | { kind: 'profile'; name: string }\n | { kind: 'storage-state'; name: string };\n\ninterface ResolvedCookieSource {\n reference: CookieSourceReference;\n cookies: unknown;\n}\n\n/** Input schema for the Playwright setCookies Node. */\nexport const setCookiesInputSchema = z\n .strictObject({\n cookiesEnv: z\n .string()\n .regex(/^[A-Za-z_][A-Za-z0-9_]*$/)\n .optional()\n .describe(\n 'The environment variable containing a Cookie header, cookie array JSON, or Playwright storage-state JSON.',\n ),\n profile: z\n .string()\n .regex(/\\S/)\n .optional()\n .describe('A cookie profile resolved by getCookieProfile().'),\n storageStatePath: z\n .string()\n .regex(/\\S/)\n .optional()\n .describe('A path to a Playwright storage-state JSON file.'),\n url: z\n .string()\n .url()\n .optional()\n .describe(\n 'The HTTP(S) URL used to scope Cookie-header values or cookies without domain/path.',\n ),\n })\n .superRefine((input, ctx) => {\n const sourceCount = [\n input.cookiesEnv,\n input.profile,\n input.storageStatePath,\n ].filter((value) => value !== undefined).length;\n if (sourceCount !== 1) {\n ctx.addIssue({\n code: 'custom',\n message:\n 'exactly one of cookiesEnv, profile, and storageStatePath is required',\n });\n }\n });\n\n/** Validated input accepted by the Playwright setCookies Node. */\nexport type SetCookiesNodeInput = z.infer<typeof setCookiesInputSchema>;\n\n/** Secret-free metadata returned by the Playwright setCookies Node. */\nexport interface SetCookiesNodeResult {\n /** Kind of configured reference used to resolve the cookies. */\n source: CookieSourceReference['kind'];\n /** Environment variable, profile, or storage-state reference name. */\n sourceName: string;\n /** Number of cookies passed to the BrowserContext. */\n count: number;\n}\n\nconst toCookieSourceReference = (\n input: SetCookiesNodeInput,\n): CookieSourceReference => {\n if (input.cookiesEnv !== undefined) {\n return { kind: 'env', name: input.cookiesEnv };\n }\n if (input.profile !== undefined) {\n return { kind: 'profile', name: input.profile };\n }\n if (input.storageStatePath !== undefined) {\n return { kind: 'storage-state', name: input.storageStatePath };\n }\n throw new TypeError('setCookies requires one cookie source.');\n};\n\nconst parseCookieHeader = (raw: string, url: string | undefined) => {\n if (url === undefined) {\n throw new TypeError(\n 'setCookies.url is required when cookiesEnv contains a Cookie header.',\n );\n }\n const segments = raw\n .split(';')\n .map((segment) => segment.trim())\n .filter(Boolean);\n if (segments.length === 0) {\n throw new TypeError('setCookies Cookie header contains no cookies.');\n }\n return segments.map((segment) => {\n const separator = segment.indexOf('=');\n if (separator <= 0) {\n throw new TypeError(\n 'setCookies Cookie header contains an invalid name/value pair.',\n );\n }\n const name = segment.slice(0, separator).trim();\n const value = segment.slice(separator + 1).trim();\n if (!name) {\n throw new TypeError('setCookies Cookie header contains an empty name.');\n }\n return { name, value, url } satisfies PlaywrightCookie;\n });\n};\n\nconst parseCookieJson = (raw: string): unknown => {\n try {\n return JSON.parse(raw);\n } catch {\n throw new TypeError(\n 'setCookies source must contain valid JSON or a Cookie header.',\n );\n }\n};\n\nconst resolveCookieSource = async <TContext>(\n reference: CookieSourceReference,\n defaultUrl: string | undefined,\n ctx: PlaywrightNodeContext<TContext>,\n options: CreatePlaywrightNodesOptions<TContext>,\n): Promise<ResolvedCookieSource> => {\n switch (reference.kind) {\n case 'env': {\n let env: Readonly<Record<string, string | undefined>>;\n try {\n env = (await options.getEnv?.(ctx)) ?? process.env;\n } catch {\n throw new Error(\n `Failed to resolve cookie environment ${reference.name}; the original error was redacted because it may contain cookie values.`,\n );\n }\n const raw = env[reference.name];\n if (!raw?.trim()) {\n throw new Error(\n `Environment variable ${reference.name} is missing or blank.`,\n );\n }\n const trimmed = raw.trim();\n return {\n reference,\n cookies: /^[\\[{]/.test(trimmed)\n ? parseCookieJson(trimmed)\n : parseCookieHeader(trimmed, defaultUrl),\n };\n }\n case 'profile': {\n if (!options.getCookieProfile) {\n throw new Error(\n 'setCookies.profile requires createPlaywrightNodes({ getCookieProfile }).',\n );\n }\n try {\n return {\n reference,\n cookies: await options.getCookieProfile({\n profile: reference.name,\n context: ctx.context,\n signal: ctx.signal,\n }),\n };\n } catch {\n throw new Error(\n `Failed to resolve cookie profile ${reference.name}; the original error was redacted because it may contain cookie values.`,\n );\n }\n }\n case 'storage-state': {\n const path = options.resolveStorageStatePath\n ? await options.resolveStorageStatePath(reference.name, ctx)\n : resolve(process.cwd(), reference.name);\n return {\n reference,\n cookies: parseCookieJson(await readFile(path, 'utf8')),\n };\n }\n }\n};\n\nconst normalizeCookie = (\n candidate: unknown,\n defaultUrl: string | undefined,\n index: number,\n): PlaywrightCookie => {\n if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {\n throw new TypeError(\n `setCookies cookie at index ${index} must be an object.`,\n );\n }\n const cookie = candidate as Record<string, unknown>;\n if (typeof cookie.name !== 'string' || !cookie.name.trim()) {\n throw new TypeError(\n `setCookies cookie at index ${index} requires a non-blank name.`,\n );\n }\n if (typeof cookie.value !== 'string') {\n throw new TypeError(\n `setCookies cookie at index ${index} requires a string value.`,\n );\n }\n\n const normalized = { ...cookie } as unknown as PlaywrightCookie;\n const hasUrl = typeof cookie.url === 'string' && cookie.url.length > 0;\n const hasDomain =\n typeof cookie.domain === 'string' && cookie.domain.length > 0;\n if (!hasUrl && !hasDomain) {\n if (defaultUrl === undefined) {\n throw new TypeError(\n `setCookies cookie at index ${index} requires url or domain, or setCookies.url must be provided.`,\n );\n }\n normalized.url = defaultUrl;\n }\n if (hasDomain && typeof cookie.path !== 'string') {\n normalized.path = '/';\n }\n return normalized;\n};\n\nconst normalizeCookies = (\n source: unknown,\n defaultUrl: string | undefined,\n): PlaywrightCookie[] => {\n const candidates = Array.isArray(source)\n ? source\n : source &&\n typeof source === 'object' &&\n Array.isArray((source as { cookies?: unknown }).cookies)\n ? (source as { cookies: unknown[] }).cookies\n : undefined;\n if (!candidates) {\n throw new TypeError(\n 'setCookies JSON must be a cookie array or an object with a cookies array.',\n );\n }\n if (candidates.length === 0) {\n throw new TypeError('setCookies source contains no cookies.');\n }\n return candidates.map((cookie, index) =>\n normalizeCookie(cookie, defaultUrl, index),\n );\n};\n\nexport const createSetCookiesNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<typeof setCookiesInputSchema, SetCookiesNodeResult, TContext>({\n name: 'setCookies',\n title: 'Set browser cookies',\n description:\n 'Load cookies from an environment variable, configured profile, or Playwright storage-state file without persisting cookie values in workflow input or output.',\n stringInputKey: false,\n inputSchema: setCookiesInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'setCookies');\n const page = await options.getPage(ctx);\n const defaultUrl =\n ctx.input.url === undefined\n ? undefined\n : resolveWebUrl(ctx.input.url, undefined, 'setCookies.url');\n const reference = toCookieSourceReference(ctx.input);\n const resolved = await resolveCookieSource(\n reference,\n defaultUrl,\n ctx,\n options,\n );\n const cookies = normalizeCookies(resolved.cookies, defaultUrl);\n\n throwIfAborted(ctx.signal, 'setCookies');\n try {\n await page.context().addCookies(cookies);\n } catch {\n throw new Error(\n `Failed to set ${cookies.length} browser cookie(s); the browser error was redacted because it may contain cookie values.`,\n );\n }\n\n const result: SetCookiesNodeResult = {\n source: resolved.reference.kind,\n sourceName: resolved.reference.name,\n count: cookies.length,\n };\n return {\n summary: `Set ${result.count} browser cookie(s) from ${result.source} source ${result.sourceName}`,\n data: result,\n };\n },\n });\n","import { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { resolveWebUrl, throwIfAborted } from './utils';\n\nconst DEFAULT_NAVIGATION_TIMEOUT_MS = 60_000;\nconst DEFAULT_WAIT_UNTIL = 'domcontentloaded' as const;\n\n/** Input schema for the Playwright gotoUrl Node. */\nexport const gotoUrlInputSchema = z.strictObject({\n url: z\n .string()\n .min(1)\n .describe('An absolute HTTP(S) URL or a path relative to baseUrl.'),\n waitUntil: z\n .enum(['commit', 'domcontentloaded', 'load', 'networkidle'])\n .default(DEFAULT_WAIT_UNTIL)\n .describe('The Playwright navigation lifecycle event to wait for.'),\n timeoutMs: z\n .number()\n .positive()\n .default(DEFAULT_NAVIGATION_TIMEOUT_MS)\n .describe('The navigation timeout in milliseconds.'),\n});\n\n/** Validated input accepted by the Playwright gotoUrl Node. */\nexport type GotoUrlNodeInput = z.infer<typeof gotoUrlInputSchema>;\n\n/** Structured navigation details returned by the Playwright gotoUrl Node. */\nexport interface GotoUrlNodeResult {\n /** Final Page URL after navigation and redirects. */\n url: string;\n /** Main-resource HTTP status, or null when Playwright returns no response. */\n status: number | null;\n /** Document title after navigation completes. */\n title: string;\n}\n\nexport const createGotoUrlNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<typeof gotoUrlInputSchema, GotoUrlNodeResult, TContext>({\n name: 'gotoUrl',\n title: 'Open a Web URL',\n description:\n 'Navigate the current Playwright Page to an absolute HTTP(S) URL or a path relative to the configured baseUrl.',\n stringInputKey: 'url',\n inputSchema: gotoUrlInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'gotoUrl');\n const page = await options.getPage(ctx);\n const baseUrl = await options.getBaseUrl?.(ctx);\n const url = resolveWebUrl(ctx.input.url, baseUrl, 'gotoUrl.url');\n const response = await page.goto(url, {\n waitUntil: ctx.input.waitUntil,\n timeout: ctx.input.timeoutMs,\n });\n const status = response?.status() ?? null;\n const result = {\n url: page.url(),\n status,\n title: await page.title(),\n };\n return { summary: `Navigated to ${result.url}`, data: result };\n },\n });\n","import { z } from 'zod/v4';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { throwIfAborted } from './utils';\n\n/** Input schema for the Playwright setViewportSize Node. */\nexport const setViewportSizeInputSchema = z.strictObject({\n width: z.number().int().positive().describe('Viewport width in CSS pixels.'),\n height: z\n .number()\n .int()\n .positive()\n .describe('Viewport height in CSS pixels.'),\n});\n\n/** Validated input accepted by the Playwright setViewportSize Node. */\nexport type SetViewportSizeNodeInput = z.infer<\n typeof setViewportSizeInputSchema\n>;\n\nexport const createSetViewportSizeNode = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): NodeDefinition<any, any, TContext> =>\n defineNode<\n typeof setViewportSizeInputSchema,\n { width: number; height: number },\n TContext\n >({\n name: 'setViewportSize',\n title: 'Set the browser viewport size',\n description:\n 'Set the current Playwright Page viewport size in CSS pixels and return the effective size.',\n stringInputKey: false,\n inputSchema: setViewportSizeInputSchema,\n async execute(ctx) {\n throwIfAborted(ctx.signal, 'setViewportSize');\n const page = await options.getPage(ctx);\n await page.setViewportSize({\n width: ctx.input.width,\n height: ctx.input.height,\n });\n const viewport = page.viewportSize();\n if (!viewport) {\n throw new Error(\n 'Playwright did not report an effective viewport size.',\n );\n }\n return {\n summary: `Set viewport to ${viewport.width}x${viewport.height}`,\n data: viewport,\n };\n },\n });\n","import { NodeDefinitionError } from '../errors';\nimport type { NodeDefinition } from '../node/types';\nimport { createClearCookiesNode } from './clear-cookies';\nimport { createSetCookiesNode } from './cookies';\nimport { createGotoUrlNode } from './goto-url';\nimport type { CreatePlaywrightNodesOptions } from './types';\nimport { createSetViewportSizeNode } from './viewport';\n\nexport { clearCookiesInputSchema } from './clear-cookies';\nexport type { ClearCookiesNodeInput } from './clear-cookies';\nexport { setCookiesInputSchema } from './cookies';\nexport type {\n SetCookiesNodeInput,\n SetCookiesNodeResult,\n} from './cookies';\nexport { gotoUrlInputSchema } from './goto-url';\nexport type { GotoUrlNodeInput, GotoUrlNodeResult } from './goto-url';\nexport type {\n CreatePlaywrightNodesOptions,\n PlaywrightCookieProfileContext,\n} from './types';\nexport { setViewportSizeInputSchema } from './viewport';\nexport type { SetViewportSizeNodeInput } from './viewport';\n\nconst requireOptions = <TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n) => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createPlaywrightNodes() options must be an object.',\n );\n }\n if (typeof options.getPage !== 'function') {\n throw new NodeDefinitionError(\n 'createPlaywrightNodes() requires getPage().',\n );\n }\n};\n\n/**\n * Create the P0 Playwright preset Nodes without assuming Project Context field\n * names. Cookie values must be resolved through configured references and are\n * never accepted as inline Node input.\n */\nexport function createPlaywrightNodes<TContext>(\n options: CreatePlaywrightNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n requireOptions(options);\n return [\n createGotoUrlNode(options),\n createSetCookiesNode(options),\n createClearCookiesNode(options),\n createSetViewportSizeNode(options),\n ];\n}\n"],"names":["WorkflowError","Error","undefined","message","options","NodeDefinitionError","details","validateOptionalText","value","field","node","validateInputSchema","schema","z","validateDefinition","defineNode","SUPPORTED_WEB_PROTOCOLS","Set","throwIfAborted","signal","operation","resolveWebUrl","target","baseUrl","label","trimmed","TypeError","resolved","URL","error","clearCookiesInputSchema","createClearCookiesNode","ctx","page","filters","filterNames","Object","setCookiesInputSchema","input","sourceCount","toCookieSourceReference","parseCookieHeader","raw","url","segments","segment","Boolean","separator","name","parseCookieJson","JSON","resolveCookieSource","reference","defaultUrl","env","process","path","resolve","readFile","normalizeCookie","candidate","index","Array","cookie","normalized","hasUrl","hasDomain","normalizeCookies","source","candidates","createSetCookiesNode","cookies","result","DEFAULT_NAVIGATION_TIMEOUT_MS","DEFAULT_WAIT_UNTIL","gotoUrlInputSchema","createGotoUrlNode","response","status","setViewportSizeInputSchema","createSetViewportSizeNode","viewport","requireOptions","createPlaywrightNodes"],"mappings":"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"}
@@ -22,7 +22,7 @@ workflow:
22
22
  continue-on-error: false
23
23
  \`\`\`
24
24
 
25
- A string step value is shorthand for \`{ prompt: value }\`. Whether that input is valid depends on the node input schema.`;
25
+ A Node may map a string step value to one declared input field. Each Node section states whether it supports this shorthand and names the target field.`;
26
26
  const sortJsonValue = (value)=>{
27
27
  if (Array.isArray(value)) return value.map(sortJsonValue);
28
28
  if ('object' != typeof value || null === value) return value;
@@ -70,6 +70,8 @@ const renderNode = (node, warnings)=>{
70
70
  warnings.push(`node "${node.name}" has no description`);
71
71
  sections.push("> Description not declared. Do not infer this node's behavior.");
72
72
  }
73
+ if (false === node.stringInputKey || void 0 === node.stringInputKey) sections.push('**String shorthand:** Not supported by this Node.');
74
+ else sections.push(`**String shorthand:** Maps to \`{ ${node.stringInputKey}: value }\`.`);
73
75
  sections.push('### Input Schema');
74
76
  if (node.inputSchema) sections.push(`\`\`\`json\n${JSON.stringify(toJsonSchema(node), null, 2)}\n\`\`\``);
75
77
  else {
@@ -292,7 +294,15 @@ const validateDefinition = (options)=>{
292
294
  if ('string' != typeof options.name || 0 === options.name.trim().length) throw new NodeDefinitionError('Node name must be a non-empty string.');
293
295
  validateOptionalText(options.title, 'title', options.name);
294
296
  validateOptionalText(options.description, "description", options.name);
297
+ if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
298
+ node: options.name,
299
+ field: 'stringInputKey'
300
+ });
295
301
  validateInputSchema(options.inputSchema, options.name);
302
+ if ('string' == typeof options.stringInputKey && options.inputSchema instanceof z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
303
+ node: options.name,
304
+ field: 'stringInputKey'
305
+ });
296
306
  if ('function' != typeof options.execute) throw new NodeDefinitionError(`Node "${options.name}" must provide an execute function.`, {
297
307
  node: options.name
298
308
  });
@@ -453,10 +463,11 @@ const platforms = new Set([
453
463
  'web',
454
464
  'android',
455
465
  'ios',
466
+ 'harmony',
456
467
  'computer'
457
468
  ]);
458
469
  const validatePlatform = (value, label)=>{
459
- if ('string' != typeof value || !platforms.has(value)) throw new TypeError(`Midscene config ${label} must be one of web, android, ios, computer.`);
470
+ if ('string' != typeof value || !platforms.has(value)) throw new TypeError(`Midscene config ${label} must be one of web, android, ios, harmony, computer.`);
460
471
  return value;
461
472
  };
462
473
  const validateProjectSetup = (value, projectPlatform, label)=>{
@@ -747,88 +758,6 @@ const createProjectRuntime = (options)=>{
747
758
  }
748
759
  };
749
760
  };
750
- const supportedMetaKeys = new Set([
751
- 'timeout',
752
- 'continue-on-error'
753
- ]);
754
- function isMapping(value) {
755
- return 'object' == typeof value && null !== value && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || null === Object.getPrototypeOf(value));
756
- }
757
- function formatStep(index) {
758
- return `step ${index + 1}`;
759
- }
760
- function normalizeMeta(value, index) {
761
- if (void 0 === value) return {
762
- continueOnError: false
763
- };
764
- if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} "$" must be a mapping.`, {
765
- index
766
- });
767
- for (const key of Object.keys(value))if (!supportedMetaKeys.has(key)) throw new WorkflowParseError(`${formatStep(index)} has unsupported engine metadata "${key}".`, {
768
- index,
769
- key
770
- });
771
- const timeout = value.timeout;
772
- if (void 0 !== timeout && ('number' != typeof timeout || !Number.isFinite(timeout) || timeout <= 0)) throw new WorkflowParseError(`${formatStep(index)} "$.timeout" must be a positive number of milliseconds.`, {
773
- index,
774
- timeout
775
- });
776
- const continueOnError = value['continue-on-error'];
777
- if (void 0 !== continueOnError && 'boolean' != typeof continueOnError) throw new WorkflowParseError(`${formatStep(index)} "$.continue-on-error" must be a boolean.`, {
778
- index,
779
- continueOnError
780
- });
781
- return {
782
- ...void 0 === timeout ? {} : {
783
- timeoutMs: timeout
784
- },
785
- continueOnError: continueOnError ?? false
786
- };
787
- }
788
- function validateCommonNodeInput(input, index) {
789
- if (void 0 !== input.prompt && 'string' != typeof input.prompt) throw new WorkflowParseError(`${formatStep(index)} "prompt" must be a string.`, {
790
- index,
791
- prompt: input.prompt
792
- });
793
- }
794
- function normalizeStep(value, index = 0) {
795
- if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} must be a mapping.`, {
796
- index
797
- });
798
- const entries = Object.entries(value);
799
- if (1 !== entries.length) throw new WorkflowParseError(`${formatStep(index)} must contain exactly one node.`, {
800
- index,
801
- nodes: Object.keys(value)
802
- });
803
- const [node, rawValue] = entries[0];
804
- if (0 === node.trim().length) throw new WorkflowParseError(`${formatStep(index)} node name must not be empty.`, {
805
- index
806
- });
807
- if ('string' == typeof rawValue) return {
808
- node,
809
- input: {
810
- prompt: rawValue
811
- },
812
- meta: {
813
- continueOnError: false
814
- }
815
- };
816
- if (!isMapping(rawValue)) throw new WorkflowParseError(`${formatStep(index)} value must be a string shorthand or a mapping.`, {
817
- index,
818
- node
819
- });
820
- const { $: rawMeta, ...input } = rawValue;
821
- validateCommonNodeInput(input, index);
822
- return {
823
- node,
824
- input,
825
- meta: normalizeMeta(rawMeta, index)
826
- };
827
- }
828
- function normalizeSteps(steps) {
829
- if (!Array.isArray(steps)) throw new WorkflowParseError('Steps must be an array.');
830
- return steps.map((step, index)=>normalizeStep(step, index));
831
- }
832
761
  const assertJsonSerializable = (value, label, node)=>{
833
762
  const visit = (candidate, path, seen)=>{
834
763
  if (null === candidate || 'string' == typeof candidate || 'boolean' == typeof candidate) return;
@@ -851,45 +780,6 @@ const assertJsonSerializable = (value, label, node)=>{
851
780
  throw new NodeExecutionError(node, error);
852
781
  }
853
782
  };
854
- const cloneAndFreezeJson = (value)=>{
855
- if (Array.isArray(value)) return Object.freeze(value.map(cloneAndFreezeJson));
856
- if ('object' == typeof value && null !== value) return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, child])=>[
857
- key,
858
- cloneAndFreezeJson(child)
859
- ])));
860
- return value;
861
- };
862
- const toHistoryEntry = (result, scope)=>{
863
- assertJsonSerializable(result.input, 'input', result.node);
864
- if (result.output?.data !== void 0) assertJsonSerializable(result.output.data, 'output.data', result.node);
865
- return Object.freeze({
866
- scope,
867
- phase: result.phase,
868
- stepIndex: result.stepIndex,
869
- node: result.node,
870
- input: cloneAndFreezeJson(result.input),
871
- ...'string' == typeof result.input?.prompt ? {
872
- intent: result.input.prompt
873
- } : {},
874
- status: 'success' === result.status ? 'passed' : 'failed',
875
- ...result.output?.summary === void 0 ? {} : {
876
- summary: result.output.summary
877
- },
878
- ...result.output?.data === void 0 ? {} : {
879
- data: cloneAndFreezeJson(result.output.data)
880
- },
881
- ...result.error ? {
882
- error: Object.freeze({
883
- name: result.error.name,
884
- message: result.error.message
885
- })
886
- } : {}
887
- });
888
- };
889
- const createHistory = (prefix, results, scope)=>Object.freeze([
890
- ...prefix,
891
- ...results.map((result)=>toHistoryEntry(result, scope))
892
- ]);
893
783
  function validateNodeOutput(output, node) {
894
784
  if (void 0 === output) return;
895
785
  if ('object' != typeof output || null === output || Array.isArray(output)) throw new NodeExecutionError(node, new TypeError('Node output must be an object or undefined.'));
@@ -911,7 +801,6 @@ function createStepResultBase(step, startedAt, phase, stepIndex) {
911
801
  };
912
802
  }
913
803
  async function executeNode(step, execute, phase, stepIndex, options) {
914
- validateCommonNodeInput(step.input, stepIndex);
915
804
  const startedAt = new Date();
916
805
  const abortController = new AbortController();
917
806
  const parentSignal = options.parentSignal;
@@ -995,7 +884,6 @@ async function executeStep(step, node, target, context, execution = {}) {
995
884
  $: step.meta,
996
885
  signal,
997
886
  context,
998
- history: execution.history ?? Object.freeze([]),
999
887
  onTeardown: (teardown)=>{
1000
888
  if (!execution.onTeardown) throw new NodeExecutionError(step.node, new Error('The current execution scope cannot register teardown.'));
1001
889
  execution.onTeardown(step.node, teardown);
@@ -1032,7 +920,6 @@ function createDocumentRuntime(document, options) {
1032
920
  const startedAt = new Date();
1033
921
  const beforeAll = [];
1034
922
  const afterAll = [];
1035
- const completedNodes = [];
1036
923
  const nodes = {
1037
924
  beforeAll: document.lifecycle.beforeAll.map((step)=>options.resolveNode(step.node)),
1038
925
  afterAll: document.lifecycle.afterAll.map((step)=>options.resolveNode(step.node))
@@ -1063,7 +950,7 @@ function createDocumentRuntime(document, options) {
1063
950
  projectId: document.projectId,
1064
951
  projectName: project.name,
1065
952
  sourcePath: document.sourcePath,
1066
- status: completedNodes.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
953
+ status: beforeAll.some((step)=>'failed' === step.status) || afterAll.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
1067
954
  startedAt: startedAt.toISOString(),
1068
955
  endedAt: endedAt.toISOString(),
1069
956
  durationMs: Math.max(0, endedAt.getTime() - startedAt.getTime()),
@@ -1092,10 +979,7 @@ function createDocumentRuntime(document, options) {
1092
979
  projectName: project.name,
1093
980
  sourcePath: document.sourcePath,
1094
981
  phase,
1095
- stepIndex,
1096
- completedNodes: Object.freeze([
1097
- ...completedNodes
1098
- ])
982
+ stepIndex
1099
983
  };
1100
984
  const stepInfo = {
1101
985
  scope: 'document',
@@ -1108,7 +992,6 @@ function createDocumentRuntime(document, options) {
1108
992
  scope: 'document',
1109
993
  document: documentContext
1110
994
  }, context, {
1111
- history: createHistory([], completedNodes, 'document'),
1112
995
  signal: executionSignal,
1113
996
  defaultTimeoutMs: options.defaultTimeoutMs,
1114
997
  onTeardown (node, teardown) {
@@ -1131,7 +1014,6 @@ function createDocumentRuntime(document, options) {
1131
1014
  });
1132
1015
  await options.onStepResult?.(stepInfo, result);
1133
1016
  results.push(result);
1134
- completedNodes.push(result);
1135
1017
  if ('failed' === result.status && !result.continuedAfterError) break;
1136
1018
  }
1137
1019
  };
@@ -1139,9 +1021,6 @@ function createDocumentRuntime(document, options) {
1139
1021
  get context () {
1140
1022
  return context;
1141
1023
  },
1142
- get history () {
1143
- return createHistory([], completedNodes, 'document');
1144
- },
1145
1024
  get canRunCases () {
1146
1025
  return started && !signal.aborted && !beforeAll.some((step)=>'failed' === step.status);
1147
1026
  },
@@ -1201,7 +1080,6 @@ async function runCollectedCase(collectedCase, options) {
1201
1080
  const beforeEach = [];
1202
1081
  const steps = [];
1203
1082
  const afterEach = [];
1204
- const completedNodes = [];
1205
1083
  const teardownStack = [];
1206
1084
  let acceptingTeardowns = true;
1207
1085
  const onTeardown = (node, teardown)=>{
@@ -1230,13 +1108,7 @@ async function runCollectedCase(collectedCase, options) {
1230
1108
  sourcePath: collectedCase.sourcePath,
1231
1109
  caseIndex: collectedCase.caseIndex,
1232
1110
  phase,
1233
- stepIndex,
1234
- completedSteps: Object.freeze([
1235
- ...steps
1236
- ]),
1237
- completedNodes: Object.freeze([
1238
- ...completedNodes
1239
- ])
1111
+ stepIndex
1240
1112
  };
1241
1113
  const stepInfo = {
1242
1114
  scope: 'case',
@@ -1249,14 +1121,12 @@ async function runCollectedCase(collectedCase, options) {
1249
1121
  scope: 'case',
1250
1122
  case: caseContext
1251
1123
  }, options.context, {
1252
- history: createHistory(options.documentHistory ?? [], completedNodes, 'case'),
1253
1124
  signal,
1254
1125
  defaultTimeoutMs: options.defaultTimeoutMs,
1255
1126
  onTeardown
1256
1127
  });
1257
1128
  await options.onStepResult?.(stepInfo, result);
1258
1129
  results.push(result);
1259
- completedNodes.push(result);
1260
1130
  if ('failed' === result.status && !result.continuedAfterError) break;
1261
1131
  }
1262
1132
  };
@@ -1296,7 +1166,7 @@ async function runCollectedCase(collectedCase, options) {
1296
1166
  name: collectedCase.definition.name,
1297
1167
  sourcePath: collectedCase.sourcePath,
1298
1168
  caseIndex: collectedCase.caseIndex,
1299
- status: completedNodes.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
1169
+ status: beforeEach.some((step)=>'failed' === step.status) || steps.some((step)=>'failed' === step.status) || afterEach.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
1300
1170
  beforeEach,
1301
1171
  steps,
1302
1172
  afterEach,
@@ -1366,7 +1236,6 @@ async function runWorkflowDocument(document, options) {
1366
1236
  context: runtime.context,
1367
1237
  projectName,
1368
1238
  attemptIndex,
1369
- documentHistory: runtime.history,
1370
1239
  signal: options.signal,
1371
1240
  defaultTimeoutMs: options.defaultTimeoutMs,
1372
1241
  onStepStart: options.onStepStart,
@@ -1412,6 +1281,89 @@ async function runWorkflowDocument(document, options) {
1412
1281
  cases
1413
1282
  };
1414
1283
  }
1284
+ const supportedMetaKeys = new Set([
1285
+ 'timeout',
1286
+ 'continue-on-error'
1287
+ ]);
1288
+ function isMapping(value) {
1289
+ return 'object' == typeof value && null !== value && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || null === Object.getPrototypeOf(value));
1290
+ }
1291
+ function formatStep(index) {
1292
+ return `step ${index + 1}`;
1293
+ }
1294
+ function normalizeMeta(value, index) {
1295
+ if (void 0 === value) return {
1296
+ continueOnError: false
1297
+ };
1298
+ if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} "$" must be a mapping.`, {
1299
+ index
1300
+ });
1301
+ for (const key of Object.keys(value))if (!supportedMetaKeys.has(key)) throw new WorkflowParseError(`${formatStep(index)} has unsupported engine metadata "${key}".`, {
1302
+ index,
1303
+ key
1304
+ });
1305
+ const timeout = value.timeout;
1306
+ if (void 0 !== timeout && ('number' != typeof timeout || !Number.isFinite(timeout) || timeout <= 0)) throw new WorkflowParseError(`${formatStep(index)} "$.timeout" must be a positive number of milliseconds.`, {
1307
+ index,
1308
+ timeout
1309
+ });
1310
+ const continueOnError = value['continue-on-error'];
1311
+ if (void 0 !== continueOnError && 'boolean' != typeof continueOnError) throw new WorkflowParseError(`${formatStep(index)} "$.continue-on-error" must be a boolean.`, {
1312
+ index,
1313
+ continueOnError
1314
+ });
1315
+ return {
1316
+ ...void 0 === timeout ? {} : {
1317
+ timeoutMs: timeout
1318
+ },
1319
+ continueOnError: continueOnError ?? false
1320
+ };
1321
+ }
1322
+ function normalizeStep(value, index = 0, resolveNode) {
1323
+ if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} must be a mapping.`, {
1324
+ index
1325
+ });
1326
+ const entries = Object.entries(value);
1327
+ if (1 !== entries.length) throw new WorkflowParseError(`${formatStep(index)} must contain exactly one node.`, {
1328
+ index,
1329
+ nodes: Object.keys(value)
1330
+ });
1331
+ const [node, rawValue] = entries[0];
1332
+ if (0 === node.trim().length) throw new WorkflowParseError(`${formatStep(index)} node name must not be empty.`, {
1333
+ index
1334
+ });
1335
+ if ('string' == typeof rawValue) {
1336
+ const resolvedNode = resolveNode?.(node);
1337
+ const stringInputKey = resolvedNode ? resolvedNode.stringInputKey : 'prompt';
1338
+ if (false === stringInputKey || void 0 === stringInputKey) throw new WorkflowParseError(`${formatStep(index)} node "${node}" does not accept string shorthand.`, {
1339
+ index,
1340
+ node
1341
+ });
1342
+ return {
1343
+ node,
1344
+ input: {
1345
+ [stringInputKey]: rawValue
1346
+ },
1347
+ meta: {
1348
+ continueOnError: false
1349
+ }
1350
+ };
1351
+ }
1352
+ if (!isMapping(rawValue)) throw new WorkflowParseError(`${formatStep(index)} value must be a string shorthand or a mapping.`, {
1353
+ index,
1354
+ node
1355
+ });
1356
+ const { $: rawMeta, ...input } = rawValue;
1357
+ return {
1358
+ node,
1359
+ input,
1360
+ meta: normalizeMeta(rawMeta, index)
1361
+ };
1362
+ }
1363
+ function normalizeSteps(steps, resolveNode) {
1364
+ if (!Array.isArray(steps)) throw new WorkflowParseError('Steps must be an array.');
1365
+ return steps.map((step, index)=>normalizeStep(step, index, resolveNode));
1366
+ }
1415
1367
  const interpolationExpression = /\$\{\{([A-Za-z_][A-Za-z0-9_]*)\}\}|\$\{([^{}]+)\}/g;
1416
1368
  const exactEnvExpression = /^\$\{\{([A-Za-z_][A-Za-z0-9_]*)\}\}$/;
1417
1369
  const exactProjectExpression = /^\$\{([^{}]+)\}$/;
@@ -1515,7 +1467,7 @@ function collectWorkflowDocument(source, options) {
1515
1467
  if (!Array.isArray(value)) throw new WorkflowParseError(`Workflow document ${phase} must be an array.`, {
1516
1468
  phase
1517
1469
  });
1518
- return normalizeSteps(value).map((normalized, stepIndex)=>{
1470
+ return normalizeSteps(value, options.resolveNode).map((normalized, stepIndex)=>{
1519
1471
  const resolved = options.resolveNode(normalized.node);
1520
1472
  if (!resolved) throw new WorkflowParseError(`Workflow document ${phase} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
1521
1473
  phase,
@@ -1551,7 +1503,7 @@ function collectWorkflowDocument(source, options) {
1551
1503
  if (!Array.isArray(tags) || tags.some((tag)=>'string' != typeof tag || 0 === tag.trim().length)) throw new WorkflowParseError(`Case ${caseIndex + 1} tags must be an array of non-empty strings.`, {
1552
1504
  caseIndex
1553
1505
  });
1554
- const steps = normalizeSteps(definition.steps).map((normalized, stepIndex)=>{
1506
+ const steps = normalizeSteps(definition.steps, options.resolveNode).map((normalized, stepIndex)=>{
1555
1507
  if (!options.resolveNode(normalized.node)) throw new WorkflowParseError(`Case ${caseIndex + 1} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
1556
1508
  caseIndex,
1557
1509
  stepIndex,