alchemy 0.59.1 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/alchemy.js +1 -1
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +15 -0
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.js +2 -1
- package/lib/apply.js.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +1 -1
- package/lib/cloudflare/index.d.ts +2 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +2 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/rule.d.ts +462 -0
- package/lib/cloudflare/rule.d.ts.map +1 -0
- package/lib/cloudflare/rule.js +2 -0
- package/lib/cloudflare/rule.js.map +1 -0
- package/lib/cloudflare/ruleset.d.ts +169 -0
- package/lib/cloudflare/ruleset.d.ts.map +1 -0
- package/lib/cloudflare/ruleset.js +118 -0
- package/lib/cloudflare/ruleset.js.map +1 -0
- package/lib/cloudflare/wrangler.json.d.ts +3 -0
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +3 -0
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/cloudflare/zone-bot-management.d.ts +85 -0
- package/lib/cloudflare/zone-bot-management.d.ts.map +1 -0
- package/lib/cloudflare/zone-bot-management.js +39 -0
- package/lib/cloudflare/zone-bot-management.js.map +1 -0
- package/lib/cloudflare/zone.d.ts +6 -1
- package/lib/cloudflare/zone.d.ts.map +1 -1
- package/lib/cloudflare/zone.js +3 -0
- package/lib/cloudflare/zone.js.map +1 -1
- package/lib/state/instrumented-state-store.d.ts.map +1 -1
- package/lib/state/instrumented-state-store.js +14 -5
- package/lib/state/instrumented-state-store.js.map +1 -1
- package/package.json +1 -1
- package/src/alchemy.ts +17 -0
- package/src/apply.ts +2 -1
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/index.ts +2 -0
- package/src/cloudflare/rule.ts +531 -0
- package/src/cloudflare/ruleset.ts +257 -0
- package/src/cloudflare/wrangler.json.ts +10 -0
- package/src/cloudflare/zone-bot-management.ts +147 -0
- package/src/cloudflare/zone.ts +18 -1
- package/src/state/instrumented-state-store.ts +17 -9
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { Context } from "../context.ts";
|
|
2
|
+
import { Resource } from "../resource.ts";
|
|
3
|
+
import { handleApiError } from "./api-error.ts";
|
|
4
|
+
import {
|
|
5
|
+
createCloudflareApi,
|
|
6
|
+
type CloudflareApi,
|
|
7
|
+
type CloudflareApiOptions,
|
|
8
|
+
} from "./api.ts";
|
|
9
|
+
import type { Kind, Rule, RulePhase } from "./rule.ts";
|
|
10
|
+
import { findZoneForHostname, type Zone } from "./zone.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Properties for creating or updating a Ruleset
|
|
14
|
+
*/
|
|
15
|
+
export interface RulesetProps<Phase extends RulePhase>
|
|
16
|
+
extends Partial<CloudflareApiOptions> {
|
|
17
|
+
/**
|
|
18
|
+
* The zone to apply the ruleset to
|
|
19
|
+
*/
|
|
20
|
+
zone: string | Zone;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The phase of the ruleset
|
|
24
|
+
* @default "http_ratelimit"
|
|
25
|
+
*/
|
|
26
|
+
phase: Phase;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Rules to apply to the ruleset
|
|
30
|
+
*/
|
|
31
|
+
rules: Array<Rule>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Human-readable name for the ruleset
|
|
35
|
+
*/
|
|
36
|
+
name?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Description of the ruleset
|
|
40
|
+
*/
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Output returned after Ruleset creation/update
|
|
46
|
+
*/
|
|
47
|
+
export interface Ruleset<Phase extends RulePhase>
|
|
48
|
+
extends Resource<"cloudflare::Ruleset"> {
|
|
49
|
+
/**
|
|
50
|
+
* The ID of the ruleset
|
|
51
|
+
*/
|
|
52
|
+
id: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The zone ID
|
|
56
|
+
*/
|
|
57
|
+
zoneId: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The phase of the ruleset
|
|
61
|
+
*/
|
|
62
|
+
phase: Phase;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Human-readable name of the ruleset
|
|
66
|
+
*/
|
|
67
|
+
name: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Description of the ruleset
|
|
71
|
+
*/
|
|
72
|
+
description?: string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The rules in the ruleset
|
|
76
|
+
*/
|
|
77
|
+
rules: Array<Rule>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* ISO datetime the ruleset was last updated
|
|
81
|
+
*/
|
|
82
|
+
lastUpdated: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Version string of the ruleset
|
|
86
|
+
*/
|
|
87
|
+
version: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Cloudflare Ruleset manages rules within a specific phase's entrypoint ruleset.
|
|
92
|
+
* This resource allows you to configure rules for various phases like rate limiting,
|
|
93
|
+
* firewall, transforms, and more.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* // Create a rate limiting ruleset
|
|
97
|
+
* const rateLimits = await Ruleset("api-rate-limits", {
|
|
98
|
+
* zone: "example.com",
|
|
99
|
+
* phase: "http_ratelimit",
|
|
100
|
+
* rules: [
|
|
101
|
+
* {
|
|
102
|
+
* description: "API rate limit",
|
|
103
|
+
* expression: "(http.request.uri.path wildcard r\"/api/*\")",
|
|
104
|
+
* action: "block",
|
|
105
|
+
* ratelimit: {
|
|
106
|
+
* characteristics: ["ip.src"],
|
|
107
|
+
* period: 60,
|
|
108
|
+
* requests_per_period: 100,
|
|
109
|
+
* mitigation_timeout: 600
|
|
110
|
+
* }
|
|
111
|
+
* }
|
|
112
|
+
* ]
|
|
113
|
+
* });
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* // Create a custom firewall ruleset
|
|
117
|
+
* const firewall = await Ruleset("custom-firewall", {
|
|
118
|
+
* zone: myZone,
|
|
119
|
+
* phase: "http_request_firewall_custom",
|
|
120
|
+
* rules: [
|
|
121
|
+
* {
|
|
122
|
+
* description: "Block bad IPs",
|
|
123
|
+
* expression: "ip.src in {1.2.3.4 1.2.3.5}",
|
|
124
|
+
* action: "block"
|
|
125
|
+
* },
|
|
126
|
+
* {
|
|
127
|
+
* description: "Challenge suspicious requests",
|
|
128
|
+
* expression: "cf.threat_score > 50",
|
|
129
|
+
* action: "challenge"
|
|
130
|
+
* }
|
|
131
|
+
* ]
|
|
132
|
+
* });
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Create a transform ruleset for request headers
|
|
136
|
+
* const transforms = await Ruleset("header-transforms", {
|
|
137
|
+
* zone: "example.com",
|
|
138
|
+
* phase: "http_request_transform",
|
|
139
|
+
* rules: [
|
|
140
|
+
* {
|
|
141
|
+
* description: "Add custom header",
|
|
142
|
+
* expression: "true",
|
|
143
|
+
* action: "rewrite",
|
|
144
|
+
* action_parameters: {
|
|
145
|
+
* headers: {
|
|
146
|
+
* "X-Custom-Header": { value: "my-value" }
|
|
147
|
+
* }
|
|
148
|
+
* }
|
|
149
|
+
* }
|
|
150
|
+
* ]
|
|
151
|
+
* });
|
|
152
|
+
*/
|
|
153
|
+
export const Ruleset = Resource("cloudflare::Ruleset", async function <
|
|
154
|
+
Phase extends RulePhase,
|
|
155
|
+
>(this: Context<Ruleset<Phase>>, _id: string, props: RulesetProps<Phase>): Promise<
|
|
156
|
+
Ruleset<Phase>
|
|
157
|
+
> {
|
|
158
|
+
const api = await createCloudflareApi(props);
|
|
159
|
+
|
|
160
|
+
// Default phase to http_ratelimit if not specified
|
|
161
|
+
const phase = props.phase || "http_ratelimit";
|
|
162
|
+
|
|
163
|
+
// Get zone ID from zone name
|
|
164
|
+
const zoneId =
|
|
165
|
+
typeof props.zone === "string"
|
|
166
|
+
? (await findZoneForHostname(api, props.zone)).zoneId
|
|
167
|
+
: props.zone.id;
|
|
168
|
+
|
|
169
|
+
if (this.phase === "delete") {
|
|
170
|
+
// Overwrite entire entrypoint with empty rules
|
|
171
|
+
await updateRuleset(api, zoneId, phase, { rules: [] });
|
|
172
|
+
return this.destroy();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Overwrite entire entrypoint with only the provided rules
|
|
176
|
+
const result = await updateRuleset(api, zoneId, phase, {
|
|
177
|
+
rules: props.rules,
|
|
178
|
+
...(props.name && { name: props.name }),
|
|
179
|
+
...(props.description && { description: props.description }),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Transform response back to our format
|
|
183
|
+
return this({
|
|
184
|
+
id: result.id,
|
|
185
|
+
zoneId,
|
|
186
|
+
phase: props.phase,
|
|
187
|
+
name: result.name || props.name || `${phase} ruleset`,
|
|
188
|
+
description: result.description || props.description,
|
|
189
|
+
rules: (result.rules as Array<Rule> | undefined) ?? [],
|
|
190
|
+
lastUpdated: result.last_updated,
|
|
191
|
+
version: result.version,
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
interface CloudflareApiRuleset {
|
|
196
|
+
/** Unique ID of the ruleset (versioned under the hood). */
|
|
197
|
+
id: string;
|
|
198
|
+
/** ISO datetime last updated. */
|
|
199
|
+
last_updated: string; // date-time
|
|
200
|
+
/** Version string of the ruleset. */
|
|
201
|
+
version: string;
|
|
202
|
+
/** Kind of ruleset. */
|
|
203
|
+
kind: Kind;
|
|
204
|
+
/** Human-readable name. */
|
|
205
|
+
name: string; // minLength: 1
|
|
206
|
+
/** Phase this ruleset runs in. */
|
|
207
|
+
phase: RulePhase;
|
|
208
|
+
/** Optional description. */
|
|
209
|
+
description?: string;
|
|
210
|
+
/** The list of rules in the ruleset. */
|
|
211
|
+
rules?: Rule[]; // or (RulesetRule[]) if you prefer loose typing
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Update a ruleset for a specific zone and phase
|
|
216
|
+
* Ensures consistent error handling on non-2xx responses
|
|
217
|
+
*/
|
|
218
|
+
export async function updateRuleset(
|
|
219
|
+
api: CloudflareApi,
|
|
220
|
+
zoneId: string,
|
|
221
|
+
/** Phase of the ruleset */
|
|
222
|
+
phase: RulePhase,
|
|
223
|
+
body: {
|
|
224
|
+
/** Human-readable name of the ruleset */
|
|
225
|
+
name?: string; // minLength: 1
|
|
226
|
+
/** Informative description of the ruleset */
|
|
227
|
+
description?: string;
|
|
228
|
+
/** Kind of the ruleset (managed, custom, root, etc.) */
|
|
229
|
+
kind?: Kind;
|
|
230
|
+
/** The list of rules in the ruleset */
|
|
231
|
+
rules: Array<Rule>;
|
|
232
|
+
},
|
|
233
|
+
): Promise<CloudflareApiRuleset> {
|
|
234
|
+
const response = await api.put(
|
|
235
|
+
`/zones/${zoneId}/rulesets/phases/${phase}/entrypoint`,
|
|
236
|
+
body,
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
await handleApiError(response, "updating", "ruleset", `${zoneId}/${phase}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const data = (await response.json()) as { result: CloudflareApiRuleset };
|
|
244
|
+
return data.result;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function getRuleset(
|
|
248
|
+
api: CloudflareApi,
|
|
249
|
+
zoneId: string,
|
|
250
|
+
phase: RulePhase,
|
|
251
|
+
): Promise<CloudflareApiRuleset> {
|
|
252
|
+
const response = await api.get(
|
|
253
|
+
`/zones/${zoneId}/rulesets/phases/${phase}/entrypoint`,
|
|
254
|
+
);
|
|
255
|
+
const data = (await response.json()) as { result: CloudflareApiRuleset };
|
|
256
|
+
return data.result;
|
|
257
|
+
}
|
|
@@ -163,6 +163,9 @@ export const WranglerJson = Resource(
|
|
|
163
163
|
? {
|
|
164
164
|
directory: toAbsolute(props.assets.directory),
|
|
165
165
|
binding: props.assets.binding,
|
|
166
|
+
not_found_handling: props.worker.assets?.not_found_handling,
|
|
167
|
+
html_handling: props.worker.assets?.html_handling,
|
|
168
|
+
run_worker_first: props.worker.assets?.run_worker_first,
|
|
166
169
|
}
|
|
167
170
|
: undefined,
|
|
168
171
|
placement: worker.placement,
|
|
@@ -417,6 +420,13 @@ export interface WranglerJsonSpec {
|
|
|
417
420
|
assets?: {
|
|
418
421
|
directory: string;
|
|
419
422
|
binding: string;
|
|
423
|
+
not_found_handling?: "none" | "404-page" | "single-page-application";
|
|
424
|
+
html_handling?:
|
|
425
|
+
| "auto-trailing-slash"
|
|
426
|
+
| "drop-trailing-slash"
|
|
427
|
+
| "force-trailing-slash"
|
|
428
|
+
| "none";
|
|
429
|
+
run_worker_first?: boolean | string[];
|
|
420
430
|
};
|
|
421
431
|
|
|
422
432
|
/**
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { CloudflareApi } from "./api.ts";
|
|
2
|
+
|
|
3
|
+
export type BotManagement =
|
|
4
|
+
| BotFightModeConfiguration
|
|
5
|
+
| SuperBotFightModeDefinitelyConfiguration
|
|
6
|
+
| SuperBotFightModeLikelyConfiguration
|
|
7
|
+
| SubscriptionConfiguration;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Bot Management configuration types
|
|
11
|
+
* See Cloudflare API: https://developers.cloudflare.com/api/resources/bot_management/methods/update/
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Action to apply to traffic classified by Super Bot Fight Mode.
|
|
15
|
+
* Maps to Cloudflare API values for SBFM: sbfm_* fields.
|
|
16
|
+
*/
|
|
17
|
+
export type SbfmAction = "allow" | "block" | "challenge";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Bot Fight Mode plan configuration.
|
|
21
|
+
* Maps to Cloudflare API: fight_mode, ai_bots_protection, crawler_protection,
|
|
22
|
+
* enable_js, is_robots_txt_managed, optimize_wordpress, suppress_session_score
|
|
23
|
+
*/
|
|
24
|
+
export interface BotFightModeConfiguration {
|
|
25
|
+
/** Enable or disable Bot Fight Mode (fight_mode) */
|
|
26
|
+
fightMode?: boolean;
|
|
27
|
+
/** Configure AI bot protection behavior (ai_bots_protection): "block" or "none" */
|
|
28
|
+
aiBotsProtection?: "block" | "none";
|
|
29
|
+
/** Enable or disable crawler protection (crawler_protection): "enabled" or "disabled" */
|
|
30
|
+
crawlerProtection?: "enabled" | "disabled";
|
|
31
|
+
/** Require JavaScript challenges for suspicious traffic (enable_js) */
|
|
32
|
+
enableJs?: boolean;
|
|
33
|
+
/** Manage robots.txt via Cloudflare (is_robots_txt_managed) */
|
|
34
|
+
isRobotsTxtManaged?: boolean;
|
|
35
|
+
/** Optimize protections for WordPress (optimize_wordpress) */
|
|
36
|
+
optimizeWordpress?: boolean;
|
|
37
|
+
/** Suppress session score collection (suppress_session_score) */
|
|
38
|
+
suppressSessionScore?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Super Bot Fight Mode Likely plan configuration.
|
|
43
|
+
* Maps to Cloudflare API: sbfm_likely_automated, sbfm_verified_bots,
|
|
44
|
+
* sbfm_static_resource_protection, optimize_wordpress, suppress_session_score, fight_mode
|
|
45
|
+
*/
|
|
46
|
+
export interface SuperBotFightModeLikelyConfiguration {
|
|
47
|
+
/** Action for likely automated traffic (sbfm_likely_automated) */
|
|
48
|
+
sbfmLikelyAutomated?: SbfmAction;
|
|
49
|
+
/** Handling for verified bots (sbfm_verified_bots): "allow" or "challenge" */
|
|
50
|
+
sbfmVerifiedBots?: "allow" | "challenge";
|
|
51
|
+
/** Protect static resources from automated requests (sbfm_static_resource_protection) */
|
|
52
|
+
sbfmStaticResourceProtection?: boolean;
|
|
53
|
+
/** Optimize protections for WordPress (optimize_wordpress) */
|
|
54
|
+
optimizeWordpress?: boolean;
|
|
55
|
+
/** Suppress session score collection (suppress_session_score) */
|
|
56
|
+
suppressSessionScore?: boolean;
|
|
57
|
+
/** Enable or disable legacy Bot Fight Mode setting if applicable (fight_mode) */
|
|
58
|
+
fightMode?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Super Bot Fight Mode Definitely plan configuration.
|
|
63
|
+
* Maps to Cloudflare API: sbfm_definitely_automated, sbfm_verified_bots,
|
|
64
|
+
* sbfm_static_resource_protection, optimize_wordpress, suppress_session_score, fight_mode
|
|
65
|
+
*/
|
|
66
|
+
export interface SuperBotFightModeDefinitelyConfiguration {
|
|
67
|
+
/** Action for definitely automated traffic (sbfm_definitely_automated) */
|
|
68
|
+
sbfmDefinitelyAutomated?: SbfmAction;
|
|
69
|
+
/** Handling for verified bots (sbfm_verified_bots): "allow" or "challenge" */
|
|
70
|
+
sbfmVerifiedBots?: "allow" | "challenge";
|
|
71
|
+
/** Protect static resources from automated requests (sbfm_static_resource_protection) */
|
|
72
|
+
sbfmStaticResourceProtection?: boolean;
|
|
73
|
+
/** Optimize protections for WordPress (optimize_wordpress) */
|
|
74
|
+
optimizeWordpress?: boolean;
|
|
75
|
+
/** Suppress session score collection (suppress_session_score) */
|
|
76
|
+
suppressSessionScore?: boolean;
|
|
77
|
+
/** Enable or disable legacy Bot Fight Mode setting if applicable (fight_mode) */
|
|
78
|
+
fightMode?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Bot Management for Enterprise subscription configuration.
|
|
83
|
+
* Extends base Bot Fight Mode options, adds model auto-update control.
|
|
84
|
+
* Maps to Cloudflare API: auto_update_model
|
|
85
|
+
*/
|
|
86
|
+
export interface SubscriptionConfiguration extends BotFightModeConfiguration {
|
|
87
|
+
/** Automatically update Bot Management model (auto_update_model) */
|
|
88
|
+
autoUpdateModel?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Helper function to update Bot Management configuration for a zone
|
|
93
|
+
* Maps high-level options to Cloudflare API fields
|
|
94
|
+
*/
|
|
95
|
+
export async function updateBotManagement(
|
|
96
|
+
api: CloudflareApi,
|
|
97
|
+
zoneId: string,
|
|
98
|
+
botManagement: BotManagement | undefined,
|
|
99
|
+
oldBotManagement: BotManagement | undefined,
|
|
100
|
+
): Promise<void> {
|
|
101
|
+
const payload = createUpdateBotManagementPayload(botManagement);
|
|
102
|
+
const oldPayload = createUpdateBotManagementPayload(oldBotManagement);
|
|
103
|
+
if (JSON.stringify(payload) === JSON.stringify(oldPayload)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const response = await api.put(`/zones/${zoneId}/bot_management`, payload);
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const body = await response.text();
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Failed to update bot management settings: ${response.status} ${response.statusText}\n${body}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const createUpdateBotManagementPayload = (props: BotManagement | undefined) =>
|
|
116
|
+
props === undefined
|
|
117
|
+
? {}
|
|
118
|
+
: {
|
|
119
|
+
fight_mode: (props as BotFightModeConfiguration).fightMode,
|
|
120
|
+
ai_bots_protection: (props as BotFightModeConfiguration)
|
|
121
|
+
.aiBotsProtection,
|
|
122
|
+
crawler_protection: (props as BotFightModeConfiguration)
|
|
123
|
+
.crawlerProtection,
|
|
124
|
+
enable_js: (props as BotFightModeConfiguration).enableJs,
|
|
125
|
+
is_robots_txt_managed: (props as BotFightModeConfiguration)
|
|
126
|
+
.isRobotsTxtManaged,
|
|
127
|
+
auto_update_model: (props as SubscriptionConfiguration).autoUpdateModel,
|
|
128
|
+
optimize_wordpress: (props as BotFightModeConfiguration)
|
|
129
|
+
.optimizeWordpress,
|
|
130
|
+
suppress_session_score: (props as BotFightModeConfiguration)
|
|
131
|
+
.suppressSessionScore,
|
|
132
|
+
sbfm_likely_automated: (props as SuperBotFightModeLikelyConfiguration)
|
|
133
|
+
.sbfmLikelyAutomated,
|
|
134
|
+
sbfm_definitely_automated: (
|
|
135
|
+
props as SuperBotFightModeDefinitelyConfiguration
|
|
136
|
+
).sbfmDefinitelyAutomated,
|
|
137
|
+
sbfm_verified_bots: (
|
|
138
|
+
props as
|
|
139
|
+
| SuperBotFightModeLikelyConfiguration
|
|
140
|
+
| SuperBotFightModeDefinitelyConfiguration
|
|
141
|
+
).sbfmVerifiedBots,
|
|
142
|
+
sbfm_static_resource_protection: (
|
|
143
|
+
props as
|
|
144
|
+
| SuperBotFightModeLikelyConfiguration
|
|
145
|
+
| SuperBotFightModeDefinitelyConfiguration
|
|
146
|
+
).sbfmStaticResourceProtection,
|
|
147
|
+
};
|
package/src/cloudflare/zone.ts
CHANGED
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
type CloudflareApi,
|
|
8
8
|
type CloudflareApiOptions,
|
|
9
9
|
} from "./api.ts";
|
|
10
|
+
import {
|
|
11
|
+
updateBotManagement,
|
|
12
|
+
type BotManagement,
|
|
13
|
+
} from "./zone-bot-management.ts";
|
|
10
14
|
import type {
|
|
11
15
|
AlwaysUseHTTPSValue,
|
|
12
16
|
AutomaticHTTPSRewritesValue,
|
|
@@ -167,6 +171,11 @@ export interface ZoneProps extends CloudflareApiOptions {
|
|
|
167
171
|
*/
|
|
168
172
|
minTlsVersion?: MinTLSVersionValue;
|
|
169
173
|
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Cloudflare Bot Management settings
|
|
177
|
+
*/
|
|
178
|
+
botManagement?: BotManagement;
|
|
170
179
|
}
|
|
171
180
|
|
|
172
181
|
/**
|
|
@@ -314,7 +323,7 @@ export interface Zone extends Resource<"cloudflare::Zone">, ZoneData {}
|
|
|
314
323
|
export const Zone = Resource(
|
|
315
324
|
"cloudflare::Zone",
|
|
316
325
|
async function (
|
|
317
|
-
this: Context<Zone>,
|
|
326
|
+
this: Context<Zone, ZoneProps>,
|
|
318
327
|
_id: string,
|
|
319
328
|
props: ZoneProps,
|
|
320
329
|
): Promise<Zone> {
|
|
@@ -408,6 +417,14 @@ export const Zone = Resource(
|
|
|
408
417
|
// https://github.com/sam-goodwin/alchemy/issues/681
|
|
409
418
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
410
419
|
|
|
420
|
+
// Update Bot Management configuration if provided
|
|
421
|
+
await updateBotManagement(
|
|
422
|
+
api,
|
|
423
|
+
zoneData.id,
|
|
424
|
+
props.botManagement,
|
|
425
|
+
this.props?.botManagement,
|
|
426
|
+
);
|
|
427
|
+
|
|
411
428
|
return this({
|
|
412
429
|
id: zoneData.id,
|
|
413
430
|
name: zoneData.name,
|
|
@@ -24,16 +24,24 @@ export class InstrumentedStateStore<T extends StateStore>
|
|
|
24
24
|
): Promise<T> {
|
|
25
25
|
const start = performance.now();
|
|
26
26
|
let error: unknown;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
try {
|
|
28
|
+
return await fn();
|
|
29
|
+
} catch (err) {
|
|
30
|
+
error = err;
|
|
31
|
+
throw err;
|
|
32
|
+
} finally {
|
|
33
|
+
this.telemetryClient.record({
|
|
34
|
+
event,
|
|
35
|
+
stateStoreClass: this.stateStoreClass,
|
|
36
|
+
elapsed: performance.now() - start,
|
|
37
|
+
error:
|
|
38
|
+
error instanceof Error
|
|
39
|
+
? error
|
|
40
|
+
: error
|
|
41
|
+
? new Error(String(error))
|
|
42
|
+
: undefined,
|
|
36
43
|
});
|
|
44
|
+
}
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
async init() {
|