diff --git a/apps/docs/content/docs/en/integrations/cloudflare.mdx b/apps/docs/content/docs/en/integrations/cloudflare.mdx index 1876af3dda0..4c9bc7fffdd 100644 --- a/apps/docs/content/docs/en/integrations/cloudflare.mdx +++ b/apps/docs/content/docs/en/integrations/cloudflare.mdx @@ -47,7 +47,7 @@ Lists all zones (domains) in the Cloudflare account. | `page` | number | No | Page number for pagination \(default: 1\) | | `per_page` | number | No | Number of zones per page \(default: 20, max: 50\) | | `accountId` | string | No | Filter zones by account ID | -| `order` | string | No | Sort field \(name, status, account.id, account.name\) | +| `order` | string | No | Sort field \(name, status, account.id, account.name, plan.id\) | | `direction` | string | No | Sort direction \(asc, desc\) | | `match` | string | No | Match logic for filters \(any, all\). Default: all | | `apiKey` | string | Yes | Cloudflare API Token | @@ -158,7 +158,6 @@ Adds a new zone (domain) to the Cloudflare account. | `name` | string | Yes | The domain name to add \(e.g., "example.com"\) | | `accountId` | string | Yes | The Cloudflare account ID | | `type` | string | No | Zone type: "full" \(Cloudflare manages DNS\), "partial" \(CNAME setup\), or "secondary" \(secondary DNS\) | -| `jump_start` | boolean | No | Automatically attempt to fetch existing DNS records when creating the zone | | `apiKey` | string | Yes | Cloudflare API Token | #### Output @@ -238,8 +237,8 @@ Lists DNS records for a specific zone. | `order` | string | No | Sort field \(type, name, content, ttl, proxied\) | | `proxied` | boolean | No | Filter by proxy status | | `search` | string | No | Free-text search across record name, content, and value | -| `tag` | string | No | Filter by tags \(comma-separated\) | -| `tag_match` | string | No | Tag filter match logic: any or all | +| `tag` | string | No | Filter by an exact tag name | +| `tag_match` | string | No | Tag filter match logic: any or all. Only affects results when combined with multiple tag filter conditions; has no effect with the single exact-match Tag Filter above. | | `commentFilter` | string | No | Filter records by comment content \(substring match\) | | `apiKey` | string | Yes | Cloudflare API Token | @@ -441,7 +440,7 @@ Lists SSL/TLS certificate packs for a zone. ### `cloudflare_get_zone_settings` -Gets all settings for a zone including SSL mode, minification, caching level, and security settings. +Gets all settings for a zone including SSL mode, caching level, and security settings. #### Input @@ -455,7 +454,7 @@ Gets all settings for a zone including SSL mode, minification, caching level, an | Parameter | Type | Description | | --------- | ---- | ----------- | | `settings` | array | List of zone settings | -| ↳ `id` | string | Setting identifier \(e.g., ssl, minify, cache_level, security_level, always_use_https\) | +| ↳ `id` | string | Setting identifier \(e.g., ssl, cache_level, security_level, always_use_https\) | | ↳ `value` | string | Setting value as a string. Simple values returned as-is \(e.g., "full", "on"\). Complex values are JSON-stringified \(e.g., \ | | ↳ `editable` | boolean | Whether the setting can be modified for the current zone plan | | ↳ `modified_on` | string | ISO 8601 timestamp when the setting was last modified | @@ -463,22 +462,22 @@ Gets all settings for a zone including SSL mode, minification, caching level, an ### `cloudflare_update_zone_setting` -Updates a specific zone setting such as SSL mode, security level, cache level, minification, or other configuration. +Updates a specific zone setting such as SSL mode, security level, cache level, or other configuration. #### Input | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `zoneId` | string | Yes | The zone ID to update settings for | -| `settingId` | string | Yes | Setting to update \(e.g., "ssl", "security_level", "cache_level", "minify", "always_use_https", "browser_cache_ttl", "http3", "min_tls_version", "ciphers"\) | -| `value` | string | Yes | New value for the setting as a string or JSON string for complex values \(e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \'\{"css":"on","html":"on","js":"on"\}\' for minify, \'\["ECDHE-RSA-AES128-GCM-SHA256"\]\' for ciphers\) | +| `settingId` | string | Yes | Setting to update \(e.g., "ssl", "security_level", "cache_level", "always_use_https", "browser_cache_ttl", "http3", "min_tls_version", "ciphers"\) | +| `value` | string | Yes | New value for the setting as a string or JSON string for complex values \(e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \'\["ECDHE-RSA-AES128-GCM-SHA256"\]\' for ciphers\) | | `apiKey` | string | Yes | Cloudflare API Token | #### Output | Parameter | Type | Description | | --------- | ---- | ----------- | -| `id` | string | Setting identifier \(e.g., ssl, minify, cache_level\) | +| `id` | string | Setting identifier \(e.g., ssl, cache_level, security_level\) | | `value` | string | Updated setting value as a string. Simple values returned as-is \(e.g., "full", "on"\). Complex values are JSON-stringified. | | `editable` | boolean | Whether the setting can be modified for the current zone plan | | `modified_on` | string | ISO 8601 timestamp when the setting was last modified | diff --git a/apps/sim/blocks/blocks/cloudflare.ts b/apps/sim/blocks/blocks/cloudflare.ts index db764d92d9f..aa8663f0590 100644 --- a/apps/sim/blocks/blocks/cloudflare.ts +++ b/apps/sim/blocks/blocks/cloudflare.ts @@ -95,6 +95,7 @@ export const CloudflareBlock: BlockConfig = { { label: 'Status', id: 'status' }, { label: 'Account ID', id: 'account.id' }, { label: 'Account Name', id: 'account.name' }, + { label: 'Plan ID', id: 'plan.id' }, ], value: () => '', condition: { field: 'operation', value: 'list_zones' }, @@ -151,24 +152,12 @@ export const CloudflareBlock: BlockConfig = { options: [ { label: 'Full (Cloudflare DNS)', id: 'full' }, { label: 'Partial (CNAME Setup)', id: 'partial' }, + { label: 'Secondary (Secondary DNS)', id: 'secondary' }, ], value: () => 'full', condition: { field: 'operation', value: 'create_zone' }, mode: 'advanced', }, - { - id: 'jump_start', - title: 'Auto-Import DNS', - type: 'dropdown', - options: [ - { label: 'No', id: 'false' }, - { label: 'Yes', id: 'true' }, - ], - value: () => 'false', - condition: { field: 'operation', value: 'create_zone' }, - mode: 'advanced', - }, - // Get Zone inputs { id: 'zoneId', @@ -299,7 +288,7 @@ export const CloudflareBlock: BlockConfig = { id: 'tag', title: 'Tag Filter', type: 'short-input', - placeholder: 'Comma-separated tags to filter by', + placeholder: 'Exact tag name to filter by', condition: { field: 'operation', value: 'list_dns_records' }, mode: 'advanced', }, @@ -623,8 +612,6 @@ export const CloudflareBlock: BlockConfig = { { label: 'Security Level', id: 'security_level' }, { label: 'Cache Level', id: 'cache_level' }, { label: 'Browser Cache TTL', id: 'browser_cache_ttl' }, - { label: 'Minification', id: 'minify' }, - { label: 'Auto Minify', id: 'auto_minify' }, { label: 'Rocket Loader', id: 'rocket_loader' }, { label: 'Email Obfuscation', id: 'email_obfuscation' }, { label: 'Hotlink Protection', id: 'hotlink_protection' }, @@ -655,7 +642,6 @@ Common settings and their valid values: - security_level: "off", "essentially_off", "low", "medium", "high", "under_attack" - cache_level: "aggressive", "basic", "simplified" - browser_cache_ttl: number in seconds (e.g., 14400 for 4 hours, 86400 for 1 day) -- minify: JSON object {"css":"on","html":"off","js":"on"} - rocket_loader: "on", "off" - email_obfuscation: "on", "off" - hotlink_protection: "on", "off" @@ -667,12 +653,11 @@ Common settings and their valid values: - min_tls_version: "1.0", "1.1", "1.2", "1.3" For simple string/boolean settings, return the plain value (e.g., "full", "on"). -For complex settings like minify, return the JSON string (e.g., {"css":"on","html":"on","js":"on"}). For numeric settings like browser_cache_ttl, return the number (e.g., 14400). Return ONLY the value - no explanations, no extra text.`, placeholder: - 'Describe the setting value (e.g., "enable strict SSL", "minify CSS and JS")...', + 'Describe the setting value (e.g., "enable strict SSL", "cache everything")...', }, }, @@ -953,9 +938,6 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, if (result.purge_everything === 'true') result.purge_everything = true else if (result.purge_everything === 'false') result.purge_everything = false - if (result.jump_start === 'true') result.jump_start = true - else if (result.jump_start === 'false') result.jump_start = false - if (result.type === '' && result.operation !== 'create_dns_record') { result.type = undefined } @@ -985,11 +967,7 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, apiKey: { type: 'string', description: 'Cloudflare API token' }, zoneId: { type: 'string', description: 'Zone ID' }, accountId: { type: 'string', description: 'Cloudflare account ID' }, - zoneType: { type: 'string', description: 'Zone type (full or partial)' }, - jump_start: { - type: 'boolean', - description: 'Automatically import DNS records when creating a zone', - }, + zoneType: { type: 'string', description: 'Zone type (full, partial, or secondary)' }, order: { type: 'string', description: 'Sort field for listing zones' }, direction: { type: 'string', description: 'Sort direction (asc, desc)' }, match: { type: 'string', description: 'Match logic for filters (any, all)' }, @@ -1002,7 +980,7 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, priority: { type: 'number', description: 'Record priority (MX/SRV)' }, comment: { type: 'string', description: 'Record comment' }, search: { type: 'string', description: 'Free-text search across record properties' }, - tag: { type: 'string', description: 'Comma-separated tags to filter by' }, + tag: { type: 'string', description: 'Filter by an exact tag name' }, tag_match: { type: 'string', description: 'Tag filter match logic (any, all)' }, commentFilter: { type: 'string', description: 'Filter records by comment content' }, settingId: { type: 'string', description: 'Zone setting ID' }, @@ -1192,5 +1170,19 @@ export const CloudflareBlockMeta = { content: '# Check SSL and Zone Settings\n\nVerify SSL/TLS posture and key security settings across zones.\n\n## Steps\n1. List the target zones.\n2. For each zone read SSL mode, certificate status/expiry, minimum TLS version, and security level.\n3. Compare against the desired baseline (e.g. Full Strict, TLS 1.2+).\n4. Flag expiring certs and any setting weaker than the baseline.\n\n## Output\nA per-zone table of SSL status, settings, and any drift that needs remediation.', }, + { + name: 'provision-new-zone', + description: + 'Onboard a new domain onto Cloudflare: create the zone, add starter DNS records, and return the nameservers to hand off for delegation.', + content: + '# Provision a New Cloudflare Zone\n\nStand up a new domain on Cloudflare so it can be pointed at Cloudflare nameservers.\n\n## Steps\n1. Create the zone for the domain under the target account.\n2. Add the initial DNS records the domain needs (A/AAAA for the apex, CNAME for www, MX/TXT for mail as required).\n3. Read back the assigned Cloudflare name servers from the created zone.\n4. Summarize the zone ID, initial records created, and the name servers the registrar needs to be updated to.\n\n## Output\nThe new zone ID, the records created, and the name servers to hand off for delegation.', + }, + { + name: 'setup-email-authentication-records', + description: + 'Add or update the SPF, DKIM, and DMARC TXT records a zone needs to authenticate outbound email and improve deliverability.', + content: + '# Set Up Email Authentication Records\n\nEmail providers (Google Workspace, Microsoft 365, transactional senders) require SPF, DKIM, and DMARC TXT records to authenticate mail and avoid it being marked as spam.\n\n## Steps\n1. Resolve the zone ID for the sending domain.\n2. List existing TXT records to check for conflicting or duplicate SPF/DMARC entries.\n3. Create or update the SPF TXT record (`v=spf1 ...`), the DKIM selector TXT record, and the DMARC TXT record (`_dmarc` name, `v=DMARC1; ...` policy) with the values the mail provider supplies.\n4. Confirm each record was created with the correct name, type, and content.\n\n## Output\nA confirmation of the SPF, DKIM, and DMARC records now in place, with their record IDs and TTLs.', + }, ], } as const satisfies BlockMeta diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index 449e5c883d8..7790433367d 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1,5 +1,5 @@ { - "updatedAt": "2026-07-02", + "updatedAt": "2026-07-06", "integrations": [ { "type": "onepassword", @@ -3063,11 +3063,11 @@ }, { "name": "Get Zone Settings", - "description": "Gets all settings for a zone including SSL mode, minification, caching level, and security settings." + "description": "Gets all settings for a zone including SSL mode, caching level, and security settings." }, { "name": "Update Zone Setting", - "description": "Updates a specific zone setting such as SSL mode, security level, cache level, minification, or other configuration." + "description": "Updates a specific zone setting such as SSL mode, security level, cache level, or other configuration." }, { "name": "DNS Analytics", diff --git a/apps/sim/tools/cloudflare/create_zone.ts b/apps/sim/tools/cloudflare/create_zone.ts index 81209328bdb..03fda6fb181 100644 --- a/apps/sim/tools/cloudflare/create_zone.ts +++ b/apps/sim/tools/cloudflare/create_zone.ts @@ -31,12 +31,6 @@ export const createZoneTool: ToolConfig { const url = new URL(`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records`) if (params.type) url.searchParams.append('type', params.type) - if (params.name) url.searchParams.append('name', params.name) - if (params.content) url.searchParams.append('content', params.content) + if (params.name) url.searchParams.append('name.exact', params.name) + if (params.content) url.searchParams.append('content.exact', params.content) if (params.page) url.searchParams.append('page', String(params.page)) if (params.per_page) url.searchParams.append('per_page', String(params.per_page)) if (params.direction) url.searchParams.append('direction', params.direction) @@ -119,7 +120,7 @@ export const listDnsRecordsTool: ToolConfig< if (params.order) url.searchParams.append('order', params.order) if (params.proxied !== undefined) url.searchParams.append('proxied', String(params.proxied)) if (params.search) url.searchParams.append('search', params.search) - if (params.tag) url.searchParams.append('tag', params.tag) + if (params.tag) url.searchParams.append('tag.exact', params.tag) if (params.tag_match) url.searchParams.append('tag_match', params.tag_match) if (params.commentFilter) url.searchParams.append('comment.contains', params.commentFilter) return url.toString() diff --git a/apps/sim/tools/cloudflare/list_zones.ts b/apps/sim/tools/cloudflare/list_zones.ts index ee165c69402..10bfe850b76 100644 --- a/apps/sim/tools/cloudflare/list_zones.ts +++ b/apps/sim/tools/cloudflare/list_zones.ts @@ -45,7 +45,7 @@ export const listZonesTool: ToolConfig { - try { - return { value: JSON.parse(params.value) } - } catch { + // A block reference can pass an already-structured array/object straight + // through despite the declared string param type — send it as-is rather + // than stringifying it (String([...]) comma-joins, String({...}) yields + // "[object Object]", neither of which is the JSON shape Cloudflare expects). + if (params.value !== null && typeof params.value === 'object') { return { value: params.value } } + + // Wand-generated values can also arrive as a non-string primitive + // (e.g. a number, or null/undefined) at runtime despite the declared + // param type — coerce null/undefined to '' rather than the literal + // "null"/"undefined" strings String() would otherwise produce. + const trimmed = (params.value == null ? '' : String(params.value)).trim() + + // browser_cache_ttl is the one setting whose value must be a number. + // Number('') is 0, not NaN, so an empty value must be rejected explicitly. + if (params.settingId === 'browser_cache_ttl') { + const numeric = trimmed === '' ? Number.NaN : Number(trimmed) + return { value: Number.isNaN(numeric) ? trimmed : numeric } + } + + // Only parse JSON object/array literals (e.g. ciphers). Scalar settings like + // min_tls_version ("1.2") or tls_1_3 ("on") must stay strings — a blind JSON.parse would + // silently coerce them to numbers/booleans and the Cloudflare API would reject the type. + if (trimmed.startsWith('{') || trimmed.startsWith('[')) { + try { + return { value: JSON.parse(trimmed) } + } catch { + return { value: trimmed } + } + } + return { value: trimmed } }, }, @@ -92,7 +119,7 @@ export const updateZoneSettingTool: ToolConfig< outputs: { id: { type: 'string', - description: 'Setting identifier (e.g., ssl, minify, cache_level)', + description: 'Setting identifier (e.g., ssl, cache_level, security_level)', }, value: { type: 'string',