"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecuteSendHttpRequestToolDefinition = exports.executeSendHttpRequestResponseSchema = exports.executeSendHttpRequestArgumentsSchema = void 0;
var zod_1 = require("zod");
var toolDefinition_js_1 = require("../toolDefinition.js");
var agentToolNames_js_1 = require("../shared/agentToolNames.js");
var schemas_js_1 = require("../shared/schemas.js");
var HTTP_METHODS = ['GET', 'DELETE', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'LINK', 'UNLINK'];
var RESPONSE_SOURCES = ['body', 'header', 'json', 'response', 'status'];
var refineSourceTarget = function (_a, ctx) {
    var source = _a.source, target = _a.target;
    var needsTarget = source === 'header' || source === 'json';
    var hasTarget = target !== undefined && target.trim() !== '';
    if (needsTarget && !hasTarget) {
        var example = source === 'header' ? 'a header name (e.g. "Content-Type")' : 'a JSON path (e.g. "data.users[0].id")';
        ctx.addIssue({
            code: 'custom',
            path: ['target'],
            message: "target is required when source is \"".concat(source, "\" \u2014 provide ").concat(example, "."),
        });
    }
    if (!needsTarget && hasTarget) {
        ctx.addIssue({
            code: 'custom',
            path: ['target'],
            message: "target must be omitted when source is \"".concat(source, "\" \u2014 only \"header\" and \"json\" sources use target."),
        });
    }
};
var httpHeaderSchema = zod_1.z.object({
    name: zod_1.z.string().meta({ description: 'Header name, e.g. "Content-Type" or "X-Custom-Header".' }),
    value: zod_1.z.string().meta({
        description: 'Header value. Supports {{@variable}} syntax, which is the preferred way to pass dynamic values (e.g. CSRF tokens captured in a previous step).',
    }),
});
// NOTE on schema shape: Gemini's FunctionDeclaration.parametersJsonSchema
// rejects `anyOf`/`oneOf` at ANY depth, not just the root. So this MUST stay a
// flat z.object — not a z.discriminatedUnion — even though it's nested inside
// httpRequestSchema. Per-branch field requirements (username+password when
// type='basic'; token when type='bearer') are enforced via .refine() (which
// Zod omits from the JSON Schema) and re-checked defensively in the client
// executor (mabl-cli/runtime/.../SendHttpRequestExecutor.ts).
var httpAuthorizationFlatObjectSchema = zod_1.z.object({
    type: zod_1.z.enum(['basic', 'bearer']).meta({
        description: "Auth type. 'basic' requires properties.username + properties.password. 'bearer' requires properties.token.",
    }),
    properties: zod_1.z
        .object({
        username: zod_1.z.string().optional().meta({
            description: "BASIC ONLY (required when type='basic'). HTTP Basic username. Prefer {{@variable}} refs over literals for any real credential.",
        }),
        password: zod_1.z.string().optional().meta({
            description: 'BASIC ONLY (required when type=\'basic\'). HTTP Basic password. You MUST prefer {{@variable}} refs (e.g. "{{@basicPassword}}") over literal values — saving a literal password into the test is a security leak.',
        }),
        token: zod_1.z.string().optional().meta({
            description: 'BEARER ONLY (required when type=\'bearer\'). Bearer token. You MUST prefer {{@variable}} refs (e.g. "{{@apiToken}}") over literal values — saving a literal token into the test is a security leak.',
        }),
    })
        .meta({
        description: "Auth-specific fields. For type='basic' provide username + password. For type='bearer' provide token.",
    }),
});
var httpAuthorizationSchema = httpAuthorizationFlatObjectSchema.refine(function (auth) {
    if (auth.type === 'basic') {
        return typeof auth.properties.username === 'string' && typeof auth.properties.password === 'string';
    }
    return typeof auth.properties.token === 'string';
}, {
    message: "When type='basic', properties.username and properties.password are required. When type='bearer', properties.token is required.",
});
var httpRequestSchema = zod_1.z.object({
    url: zod_1.z.string().meta({
        description: 'The URL to send the request to. Supports {{@variable}} syntax for dynamic pieces (base URL, path IDs, query params) — prefer variables over literals when the URL contains data captured or generated earlier in the test.',
    }),
    method: zod_1.z.enum(HTTP_METHODS).meta({
        description: 'HTTP method. Most API steps use GET, POST, PUT, PATCH, or DELETE.',
    }),
    headers: zod_1.z.array(httpHeaderSchema).optional().meta({
        description: 'Optional request headers. Use for "Content-Type", "Accept", or custom headers.',
    }),
    authorization: httpAuthorizationSchema.optional().meta({
        description: 'Optional authentication. Choose "basic" for username+password or "bearer" for a token. For real credentials always pass {{@variable}} refs in the properties rather than literal strings.',
    }),
    body: zod_1.z.string().optional().meta({
        description: 'Optional request body, typically a JSON string for POST/PUT/PATCH. Supports {{@variable}} syntax inside the body string.',
    }),
});
var sendHttpRequestOptionsSchema = zod_1.z.object({
    loadResponseCookies: zod_1.z.boolean().optional().meta({
        description: 'If true, cookies returned in the response are loaded into the browser session so subsequent browser steps use them. Leave unset (false) for plain API validation; set true only when the API call establishes browser auth for later steps.',
    }),
});
var sendHttpRequestAssertionSchema = zod_1.z
    .object({
    source: zod_1.z.enum(RESPONSE_SOURCES).meta({
        description: 'What to assert against. "status" = HTTP status code. "header" = a specific response header value (requires target). "json" = a value inside the JSON-parsed body at a JSON path (requires target, e.g. "data.users[0].id"). "body" = the raw response body as text. "response" = the full response object serialized (rarely needed).',
    }),
    target: zod_1.z.string().optional().meta({
        description: 'Required when source is "header" (provide the header name, e.g. "Content-Type") or "json" (provide a dotted JSON path, e.g. "data.users[0].id"). Omit for "status", "body", "response".',
    }),
    assertion: schemas_js_1.comparisonTypeEnum.meta({
        description: 'Comparison type. Typical choices: "equals" for exact status codes (e.g. status equals "200"), "contains" for substring checks on body/header values, "matches_regex" for patterns. "greater_than"/"less_than" for numeric comparisons.',
    }),
    value: zod_1.z.string().meta({
        description: 'Expected value, as a string. Numeric statuses like 200 should be passed as "200". Use {{@variable}} syntax to compare against a value captured earlier in the test.',
    }),
})
    .superRefine(refineSourceTarget);
var sendHttpRequestVariableSchema = zod_1.z
    .object({
    source: zod_1.z.enum(RESPONSE_SOURCES).meta({
        description: 'Where to extract the variable value from. Same enum as assertions: "status" (HTTP status code), "header" (requires target = header name), "json" (requires target = JSON path inside body), "body" (raw body text), "response" (full response object).',
    }),
    target: zod_1.z.string().optional().meta({
        description: 'Required when source is "header" or "json"; same semantics as the assertion target. Omit for "status", "body", "response".',
    }),
    name: zod_1.z
        .string()
        .regex(/^[A-Za-z_][A-Za-z0-9_]*$/)
        .meta({
        description: 'The variable name to create. Must be alphanumeric plus underscores (no spaces, no hyphens). Reference it in later steps as {{@name}}.',
    }),
})
    .superRefine(refineSourceTarget);
exports.executeSendHttpRequestArgumentsSchema = zod_1.z.object({
    request: httpRequestSchema.meta({
        description: 'The HTTP request to record as part of the test.',
    }),
    options: sendHttpRequestOptionsSchema.optional().meta({
        description: 'Optional advanced options. Omit when no advanced behavior is needed.',
    }),
    assertions: zod_1.z.array(sendHttpRequestAssertionSchema).optional().meta({
        description: 'Response assertions to verify at replay time. Example: assert status equals "200", or assert json path "data.users[0].id" contains "user-". Each assertion runs against the response of this same step.',
    }),
    variables: zod_1.z.array(sendHttpRequestVariableSchema).optional().meta({
        description: 'Variables to extract from the response for use in later steps. Example: source "json", target "data.token", name "authToken" — later steps can reference it as {{@authToken}}.',
    }),
});
exports.executeSendHttpRequestResponseSchema = zod_1.z.object({
    success: zod_1.z.boolean(),
    message: zod_1.z.string().optional(),
});
exports.ExecuteSendHttpRequestToolDefinition = (0, toolDefinition_js_1.defineTool)({
    name: agentToolNames_js_1.AgentToolNames.ExecuteSendHttpRequest,
    description: "Records and dispatches an HTTP API request step. Use this for REST/HTTP traffic alongside browser steps \u2014 calling an endpoint, asserting on the response, and optionally extracting response values into variables. Do NOT use it to drive the UI (forms, clicks, inputs); those have dedicated tools.\n\nAuthoring-time contract:\n- The request fires when the step is recorded so that captured response variables get populated for use by subsequent steps in the same session.\n- Side-effecting verbs (POST/PUT/PATCH/DELETE) hit real systems on each authoring iteration. Ask the user about test data and cleanup before authoring such a step.\n- Every {{@variable}} reference (URL, headers, body, auth) must already exist or the runtime fails with \"Cannot resolve variable\" before any network call. If a needed variable does not exist, call ".concat(agentToolNames_js_1.AgentToolNames.ExecuteAskForHelp, " \u2014 never fabricate one via ").concat(agentToolNames_js_1.AgentToolNames.ExecuteCreateOrSetVariable, ", especially for credentials.\n- The actual response is NOT surfaced back to you. Generate assertions from user intent and prefer high-confidence checks (e.g., status equals \"200\") over speculative deep-body assertions.\n\nCapabilities:\n- Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.\n- Auth: 'basic' (username/password) or 'bearer' (token). For real credentials always pass {{@variable}} refs \u2014 literal credentials in a saved test are a leak.\n- Body: string in JSON, URL-encoded, plain text, or XML. Set Content-Type explicitly to match.\n- Response assertions and variables share the same source enum: \"status\", \"json\", \"header\", \"body\", \"response\".\n\nFor body-format examples, base-URL conventions ({{@web.defaults.url}} vs {{@api.url}}), the default-Content-Type footgun, the headers-vs-authorization conflict, and full anti-patterns, fetch the api-steps skill."),
    argumentsSchema: exports.executeSendHttpRequestArgumentsSchema,
    responseSchema: exports.executeSendHttpRequestResponseSchema,
});
//# sourceMappingURL=ExecuteSendHttpRequestDefinition.js.map