alchemy 0.70.1 → 0.71.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 +13 -15
- package/bin/commands/init.ts +0 -10
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +2 -0
- package/lib/apply.js.map +1 -1
- package/lib/clickhouse/organization.d.ts +1 -1
- package/lib/clickhouse/organization.js +2 -2
- package/lib/clickhouse/organization.js.map +1 -1
- package/lib/clickhouse/service.d.ts +28 -18
- package/lib/clickhouse/service.d.ts.map +1 -1
- package/lib/clickhouse/service.js +61 -9
- package/lib/clickhouse/service.js.map +1 -1
- package/lib/cloudflare/account-api-token.js +1 -1
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +12 -2
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +3 -2
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +6 -0
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +5 -3
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bun-spa/bun-spa.d.ts +6 -1
- package/lib/cloudflare/bun-spa/bun-spa.d.ts.map +1 -1
- package/lib/cloudflare/bun-spa/bun-spa.js +29 -9
- package/lib/cloudflare/bun-spa/bun-spa.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/d1-database.d.ts +1 -1
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +1 -1
- package/lib/cloudflare/d1-database.js.map +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/logpush-job.d.ts +349 -0
- package/lib/cloudflare/logpush-job.d.ts.map +1 -0
- package/lib/cloudflare/logpush-job.js +277 -0
- package/lib/cloudflare/logpush-job.js.map +1 -0
- package/lib/cloudflare/miniflare/build-worker-options.d.ts +1 -0
- package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.js +16 -6
- package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.js +2 -0
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
- package/lib/cloudflare/permission-groups.d.ts +1489 -26
- package/lib/cloudflare/permission-groups.d.ts.map +1 -1
- package/lib/cloudflare/permission-groups.js +1787 -6
- package/lib/cloudflare/permission-groups.js.map +1 -1
- package/lib/cloudflare/queue-consumer.js +2 -2
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/worker-loader.d.ts +9 -0
- package/lib/cloudflare/worker-loader.d.ts.map +1 -0
- package/lib/cloudflare/worker-loader.js +6 -0
- package/lib/cloudflare/worker-loader.js.map +1 -0
- package/lib/cloudflare/worker-metadata.d.ts +14 -2
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +10 -1
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-stub.d.ts +3 -1
- package/lib/cloudflare/worker-stub.d.ts.map +1 -1
- package/lib/cloudflare/worker-stub.js +19 -7
- package/lib/cloudflare/worker-stub.js.map +1 -1
- package/lib/cloudflare/worker-subdomain.js +1 -1
- package/lib/cloudflare/worker.d.ts +74 -10
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +23 -7
- package/lib/cloudflare/worker.js.map +1 -1
- 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 +9 -0
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/github/comment.d.ts.map +1 -1
- package/lib/github/comment.js +14 -7
- package/lib/github/comment.js.map +1 -1
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +6 -7
- package/lib/scope.js.map +1 -1
- package/lib/util/camel-to-snake.d.ts +12 -0
- package/lib/util/camel-to-snake.d.ts.map +1 -0
- package/lib/util/camel-to-snake.js +16 -0
- package/lib/util/camel-to-snake.js.map +1 -0
- package/lib/util/retry.d.ts +1 -1
- package/lib/util/retry.d.ts.map +1 -1
- package/lib/util/retry.js +2 -2
- package/lib/util/retry.js.map +1 -1
- package/lib/util/validate-resource-id.d.ts +2 -0
- package/lib/util/validate-resource-id.d.ts.map +1 -0
- package/lib/util/validate-resource-id.js +11 -0
- package/lib/util/validate-resource-id.js.map +1 -0
- package/package.json +2 -2
- package/src/apply.ts +2 -0
- package/src/clickhouse/organization.ts +2 -2
- package/src/clickhouse/service.ts +124 -33
- package/src/cloudflare/account-api-token.ts +1 -1
- package/src/cloudflare/bindings.ts +13 -0
- package/src/cloudflare/bound.ts +36 -32
- package/src/cloudflare/bucket.ts +13 -4
- package/src/cloudflare/bun-spa/bun-spa.ts +42 -11
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/d1-database.ts +2 -2
- package/src/cloudflare/index.ts +2 -0
- package/src/cloudflare/logpush-job.ts +768 -0
- package/src/cloudflare/miniflare/build-worker-options.ts +18 -6
- package/src/cloudflare/miniflare/remote-binding-proxy.ts +2 -0
- package/src/cloudflare/permission-groups.ts +1832 -45
- package/src/cloudflare/queue-consumer.ts +2 -2
- package/src/cloudflare/worker-loader.ts +12 -0
- package/src/cloudflare/worker-metadata.ts +25 -3
- package/src/cloudflare/worker-stub.ts +28 -11
- package/src/cloudflare/worker-subdomain.ts +1 -1
- package/src/cloudflare/worker.ts +106 -17
- package/src/cloudflare/wrangler.json.ts +15 -0
- package/src/github/comment.ts +17 -8
- package/src/scope.ts +7 -10
- package/src/util/camel-to-snake.ts +88 -0
- package/src/util/retry.ts +2 -1
- package/src/util/validate-resource-id.ts +10 -0
- package/workers/tunnel-proxy.js +1 -1
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { type Secret } from "../secret.ts";
|
|
2
|
+
import { type CloudflareApiOptions } from "./api.ts";
|
|
3
|
+
import { type R2Bucket } from "./bucket.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Properties for creating or updating a LogPush Job
|
|
6
|
+
*/
|
|
7
|
+
export interface LogPushJobProps extends CloudflareApiOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Zone ID or Zone object for zone-level LogPush jobs
|
|
10
|
+
* Mutually exclusive with accountId
|
|
11
|
+
*/
|
|
12
|
+
zone?: string | {
|
|
13
|
+
id: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Name of the dataset. A list of supported datasets can be found on the
|
|
18
|
+
* Developer Docs
|
|
19
|
+
* @default "http_requests"
|
|
20
|
+
* @see https://developers.cloudflare.com/logs/reference/log-fields/
|
|
21
|
+
*/
|
|
22
|
+
dataset: LogPushJobDataset;
|
|
23
|
+
/**
|
|
24
|
+
* Uniquely identifies a resource (such as an s3 bucket) where data will be
|
|
25
|
+
* pushed. Additional configuration parameters supported by the destination
|
|
26
|
+
* may be included (format: uri, maxLength: 4096)
|
|
27
|
+
*
|
|
28
|
+
* Can be:
|
|
29
|
+
* - A full destination string (e.g., "s3://bucket/path" or "r2://bucket/path?account-id=...")
|
|
30
|
+
* - An R2Bucket resource (will use bucket.name and R2 credentials from environment)
|
|
31
|
+
* - A Secret containing a destination string
|
|
32
|
+
*/
|
|
33
|
+
destination: string | R2Bucket | Secret<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Filter to apply to logs (JSON string)
|
|
36
|
+
* @example '{"where":{"and":[{"key":"ClientCountry","operator":"neq","value":"ca"}]}}'
|
|
37
|
+
*/
|
|
38
|
+
filter?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Optional human readable job name. Not unique. Cloudflare suggests that you
|
|
41
|
+
* set this to a meaningful string, like the domain name, to make it easier to
|
|
42
|
+
* identify your job (maxLength: 512)
|
|
43
|
+
*/
|
|
44
|
+
name?: string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Flag that indicates if the job is enabled
|
|
47
|
+
*/
|
|
48
|
+
enabled?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Ownership challenge token (obtained from ownership validation)
|
|
51
|
+
* Required on creation if destination ownership not yet validated
|
|
52
|
+
*/
|
|
53
|
+
ownershipChallenge?: string;
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated This field is deprecated. Please use maxUploadBytes,
|
|
56
|
+
* maxUploadIntervalSeconds, or maxUploadRecords instead. The frequency at
|
|
57
|
+
* which Cloudflare sends batches of logs to your destination. Setting
|
|
58
|
+
* frequency to high sends your logs in larger quantities of smaller files.
|
|
59
|
+
* Setting frequency to low sends logs in smaller quantities of larger files
|
|
60
|
+
*/
|
|
61
|
+
frequency?: "high" | "low" | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* The kind parameter (optional) is used to differentiate between Logpush and
|
|
64
|
+
* Edge Log Delivery jobs (when supported by the dataset)
|
|
65
|
+
*/
|
|
66
|
+
kind?: "edge";
|
|
67
|
+
/**
|
|
68
|
+
* The maximum uncompressed file size of a batch of logs. This setting value
|
|
69
|
+
* must be between 5 MB and 1 GB, or 0 to disable it. Note that you cannot
|
|
70
|
+
* set a minimum file size; this means that log files may be much smaller than
|
|
71
|
+
* this batch size
|
|
72
|
+
*/
|
|
73
|
+
maxUploadBytes?: 0 | number | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* The maximum interval in seconds for log batches. This setting must be
|
|
76
|
+
* between 30 and 300 seconds (5 minutes), or 0 to disable it. Note that you
|
|
77
|
+
* cannot specify a minimum interval for log batches; this means that log
|
|
78
|
+
* files may be sent in shorter intervals than this
|
|
79
|
+
*/
|
|
80
|
+
maxUploadIntervalSeconds?: 0 | number | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* The maximum number of log lines per batch. This setting must be between
|
|
83
|
+
* 1000 and 1,000,000 lines, or 0 to disable it. Note that you cannot specify
|
|
84
|
+
* a minimum number of log lines per batch; this means that log files may
|
|
85
|
+
* contain many fewer lines than this
|
|
86
|
+
*/
|
|
87
|
+
maxUploadRecords?: 0 | number | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* The structured replacement for logpull_options. When including this field,
|
|
90
|
+
* the logpull_option field will be ignored
|
|
91
|
+
*/
|
|
92
|
+
outputOptions?: LogPushJobOutputOptions;
|
|
93
|
+
/**
|
|
94
|
+
* Whether to delete the LogPush job when removed
|
|
95
|
+
* @default true
|
|
96
|
+
*/
|
|
97
|
+
delete?: boolean;
|
|
98
|
+
}
|
|
99
|
+
export interface LogPushJobOutputOptions {
|
|
100
|
+
/**
|
|
101
|
+
* String to join fields. This field will be ignored when recordTemplate is
|
|
102
|
+
* set
|
|
103
|
+
*/
|
|
104
|
+
fieldDelimiter?: string | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* List of field names to be included in the Logpush output. For the moment,
|
|
107
|
+
* there is no option to add all fields at once, so you must specify all the
|
|
108
|
+
* field names you are interested in
|
|
109
|
+
*/
|
|
110
|
+
fieldNames?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Specifies the output type, such as ndjson or csv. This sets default
|
|
113
|
+
* values for the rest of the settings, depending on the chosen output type.
|
|
114
|
+
* Some formatting rules, like string quoting, are different between output
|
|
115
|
+
* types
|
|
116
|
+
*/
|
|
117
|
+
outputType?: "ndjson" | "csv";
|
|
118
|
+
/**
|
|
119
|
+
* String to specify the format for timestamps, such as unixnano, unix, or
|
|
120
|
+
* rfc3339
|
|
121
|
+
*/
|
|
122
|
+
timestampFormat?: "unixnano" | "unix" | "rfc3339";
|
|
123
|
+
/**
|
|
124
|
+
* Floating number to specify sampling rate. Sampling is applied on top of
|
|
125
|
+
* filtering, and regardless of the current sample_interval of the data
|
|
126
|
+
* (minimum: 0, maximum: 1)
|
|
127
|
+
*/
|
|
128
|
+
sampleRate?: number | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Prepended before each batch
|
|
131
|
+
*/
|
|
132
|
+
batchPrefix?: string | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Appended after each batch
|
|
135
|
+
*/
|
|
136
|
+
batchSuffix?: string | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* If set to true, will cause all occurrences of ${ in the generated files
|
|
139
|
+
* to be replaced with x{
|
|
140
|
+
*/
|
|
141
|
+
cve202144228?: boolean | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Be inserted in-between the records as separator
|
|
144
|
+
*/
|
|
145
|
+
recordDelimiter?: string | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* Prepended before each record
|
|
148
|
+
*/
|
|
149
|
+
recordPrefix?: string | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* After each record
|
|
152
|
+
*/
|
|
153
|
+
recordSuffix?: string | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Use as template for each record instead of the default json key value
|
|
156
|
+
* mapping. All fields used in the template must be present in fieldNames as
|
|
157
|
+
* well, otherwise they will end up as null. Format as a Go text/template
|
|
158
|
+
* without any standard functions, like conditionals, loops, sub-templates,
|
|
159
|
+
* etc
|
|
160
|
+
*/
|
|
161
|
+
recordTemplate?: string | undefined;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Output returned after LogPush Job creation/update
|
|
165
|
+
*/
|
|
166
|
+
export type LogPushJob = Omit<LogPushJobProps, "delete" | "ownershipChallenge" | "zone" | "destination"> & {
|
|
167
|
+
/**
|
|
168
|
+
* Resource type identifier
|
|
169
|
+
*/
|
|
170
|
+
type: "logpush_job";
|
|
171
|
+
/**
|
|
172
|
+
* Unique id of the job (minimum: 1)
|
|
173
|
+
* Assigned by Cloudflare upon job creation
|
|
174
|
+
*/
|
|
175
|
+
id?: number;
|
|
176
|
+
/**
|
|
177
|
+
* The Cloudflare account ID
|
|
178
|
+
*/
|
|
179
|
+
accountId: string;
|
|
180
|
+
/**
|
|
181
|
+
* The destination of the job
|
|
182
|
+
*/
|
|
183
|
+
destination: Secret<string>;
|
|
184
|
+
/**
|
|
185
|
+
* If not null, the job is currently failing. Failures are usually repetitive
|
|
186
|
+
* (example: no permissions to write to destination bucket). Only the last
|
|
187
|
+
* failure is recorded. On successful execution of a job the errorMessage and
|
|
188
|
+
* lastError are set to null
|
|
189
|
+
*/
|
|
190
|
+
errorMessage?: string | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* Records the last time for which logs have been successfully pushed. If the
|
|
193
|
+
* last successful push was for logs range 2018-07-23T10:00:00Z to
|
|
194
|
+
* 2018-07-23T10:01:00Z then the value of this field will be
|
|
195
|
+
* 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and
|
|
196
|
+
* hasn't run yet then the field will be empty (format: datetime)
|
|
197
|
+
*/
|
|
198
|
+
lastComplete?: string | undefined;
|
|
199
|
+
/**
|
|
200
|
+
* Records the last time the job failed. If not null, the job is currently
|
|
201
|
+
* failing. If null, the job has either never failed or has run successfully
|
|
202
|
+
* at least once since last failure. See also the errorMessage field (format:
|
|
203
|
+
* datetime)
|
|
204
|
+
*/
|
|
205
|
+
lastError?: string | undefined;
|
|
206
|
+
/**
|
|
207
|
+
* Time at which the job was created (Unix timestamp in ms)
|
|
208
|
+
*/
|
|
209
|
+
createdAt: number;
|
|
210
|
+
/**
|
|
211
|
+
* Time at which the job was last modified (Unix timestamp in ms)
|
|
212
|
+
*/
|
|
213
|
+
modifiedAt: number;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Check if a resource is a LogPushJob
|
|
217
|
+
*/
|
|
218
|
+
export declare function isLogPushJob(resource: any): resource is LogPushJob;
|
|
219
|
+
/**
|
|
220
|
+
* Creates and manages Cloudflare LogPush Jobs for streaming logs to external
|
|
221
|
+
* destinations.
|
|
222
|
+
*
|
|
223
|
+
* LogPush jobs can be scoped to either an account or a zone, and support
|
|
224
|
+
* various log datasets like HTTP requests, firewall events, DNS logs, and more.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* // Basic HTTP request logs to S3 (zone-level)
|
|
228
|
+
* const httpLogs = await LogPushJob("http-logs", {
|
|
229
|
+
* zone: "example.com",
|
|
230
|
+
* dataset: "http_requests",
|
|
231
|
+
* destination: "s3://my-bucket/logs?region=us-west-2",
|
|
232
|
+
* name: "HTTP Request Logs"
|
|
233
|
+
* });
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* // Account-level firewall events with filtering using a string destination
|
|
237
|
+
* const blockedRequests = await LogPushJob("blocked-requests", {
|
|
238
|
+
* dataset: "firewall_events",
|
|
239
|
+
* destination: "r2://my-bucket/firewall-logs?account-id=xxx&access-key-id=xxx&secret-access-key=xxx",
|
|
240
|
+
* filter:
|
|
241
|
+
* '{"where":{"and":[{"key":"Action","operator":"eq","value":"block"}]}}',
|
|
242
|
+
* maxUploadBytes: 100 * 1024 * 1024, // 100MB batches
|
|
243
|
+
* maxUploadIntervalSeconds: 300 // 5 minutes
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* // Stream logs to R2 using R2Bucket resource (requires R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY env vars)
|
|
248
|
+
* const bucket = await R2Bucket("logs-bucket", {
|
|
249
|
+
* name: "my-logs-bucket"
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* const logsToR2 = await LogPushJob("http-to-r2", {
|
|
253
|
+
* dataset: "http_requests",
|
|
254
|
+
* destination: bucket // Automatically constructs R2 URL with env credentials
|
|
255
|
+
* });
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* // Or use a direct destination string with embedded credentials
|
|
259
|
+
* const logsToR2 = await LogPushJob("http-to-r2", {
|
|
260
|
+
* dataset: "http_requests",
|
|
261
|
+
* destination: `r2://my-logs-bucket/logs/{DATE}?account-id=${accountId}&access-key-id=${R2_ACCESS_KEY_ID}&secret-access-key=${R2_SECRET_ACCESS_KEY}`
|
|
262
|
+
* });
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* // High-volume analytics with custom output format
|
|
266
|
+
* const analyticsLogs = await LogPushJob("analytics-logs", {
|
|
267
|
+
* zone: myZone,
|
|
268
|
+
* dataset: "http_requests",
|
|
269
|
+
* destination: "s3://analytics-bucket/logs?region=eu-west-1",
|
|
270
|
+
* sample: 0.01, // 1% sampling for high-volume sites
|
|
271
|
+
* maxUploadRecords: 100000, // 100k records per batch
|
|
272
|
+
* outputOptions: {
|
|
273
|
+
* outputType: "ndjson",
|
|
274
|
+
* timestampFormat: "unixnano",
|
|
275
|
+
* fieldNames: [
|
|
276
|
+
* "ClientIP",
|
|
277
|
+
* "ClientRequestHost",
|
|
278
|
+
* "EdgeResponseStatus",
|
|
279
|
+
* "EdgeStartTimestamp"
|
|
280
|
+
* ],
|
|
281
|
+
* sampleRate: 0.1 // Additional 10% sampling within the batch
|
|
282
|
+
* }
|
|
283
|
+
* });
|
|
284
|
+
*
|
|
285
|
+
* @see https://developers.cloudflare.com/logs/get-started/enable-destinations/
|
|
286
|
+
* @see https://developers.cloudflare.com/api/resources/logpush/
|
|
287
|
+
*/
|
|
288
|
+
export declare function LogPushJob(id: string, props: LogPushJobProps): Promise<LogPushJob>;
|
|
289
|
+
/**
|
|
290
|
+
* The structured replacement for logpull_options. When including this field, the logpull_option field will be ignored.
|
|
291
|
+
*/
|
|
292
|
+
export interface OutputOptions {
|
|
293
|
+
/**
|
|
294
|
+
* String to be prepended before each batch.
|
|
295
|
+
*/
|
|
296
|
+
batch_prefix?: string | null;
|
|
297
|
+
/**
|
|
298
|
+
* String to be appended after each batch.
|
|
299
|
+
*/
|
|
300
|
+
batch_suffix?: string | null;
|
|
301
|
+
/**
|
|
302
|
+
* If set to true, will cause all occurrences of ${ in the generated files to be replaced with x{.
|
|
303
|
+
*/
|
|
304
|
+
"CVE-2021-44228"?: boolean | null;
|
|
305
|
+
/**
|
|
306
|
+
* String to join fields. This field will be ignored when record_template is set.
|
|
307
|
+
*/
|
|
308
|
+
field_delimiter?: string | null;
|
|
309
|
+
/**
|
|
310
|
+
* List of field names to be included in the Logpush output.
|
|
311
|
+
* For the moment, there is no option to add all fields at once, so you must specify all the field names you are interested in.
|
|
312
|
+
*/
|
|
313
|
+
field_names?: string[];
|
|
314
|
+
/**
|
|
315
|
+
* Specifies the output type, such as ndjson or csv.
|
|
316
|
+
* This sets default values for the rest of the settings, depending on the chosen output type.
|
|
317
|
+
* Some formatting rules, like string quoting, are different between output types.
|
|
318
|
+
*/
|
|
319
|
+
output_type?: "ndjson" | "csv";
|
|
320
|
+
/**
|
|
321
|
+
* String to be inserted in-between the records as separator.
|
|
322
|
+
*/
|
|
323
|
+
record_delimiter?: string | null;
|
|
324
|
+
/**
|
|
325
|
+
* String to be prepended before each record.
|
|
326
|
+
*/
|
|
327
|
+
record_prefix?: string | null;
|
|
328
|
+
/**
|
|
329
|
+
* String to be appended after each record.
|
|
330
|
+
*/
|
|
331
|
+
record_suffix?: string | null;
|
|
332
|
+
/**
|
|
333
|
+
* String to use as template for each record instead of the default json key value mapping.
|
|
334
|
+
* All fields used in the template must be present in field_names as well, otherwise they will end up as null.
|
|
335
|
+
* Format as a Go text/template without any standard functions, like conditionals, loops, sub-templates, etc.
|
|
336
|
+
*/
|
|
337
|
+
record_template?: string | null;
|
|
338
|
+
/**
|
|
339
|
+
* Floating number to specify sampling rate. Sampling is applied on top of filtering, and regardless of the current sample_interval of the data.
|
|
340
|
+
* (format: float, maximum: 1, minimum: 0)
|
|
341
|
+
*/
|
|
342
|
+
sample_rate?: number | null;
|
|
343
|
+
/**
|
|
344
|
+
* String to specify the format for timestamps, such as unixnano, unix, or rfc3339.
|
|
345
|
+
*/
|
|
346
|
+
timestamp_format?: "unixnano" | "unix" | "rfc3339";
|
|
347
|
+
}
|
|
348
|
+
export type LogPushJobDataset = "access_requests" | "audit_logs_v2" | "audit_logs" | "biso_user_actions" | "casb_findings" | "device_posture_results" | "dlp_forensic_copies" | "dns_firewall_logs" | "dns_logs" | "email_security_alerts" | "firewall_events" | "gateway_dns" | "gateway_http" | "gateway_network" | "http_requests" | "magic_ids_detections" | "nel_reports" | "network_analytics_logs" | "page_shield_events" | "sinkhole_http_logs" | "spectrum_events" | "ssh_logs" | "workers_trace_events" | "zaraz_events" | "zero_trust_network_sessions" | (string & {});
|
|
349
|
+
//# sourceMappingURL=logpush-job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logpush-job.d.ts","sourceRoot":"","sources":["../../src/cloudflare/logpush-job.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { Resource, ResourceKind } from "../resource.js";
|
|
2
|
+
import { secret } from "../secret.js";
|
|
3
|
+
import { withExponentialBackoff } from "../util/retry.js";
|
|
4
|
+
import { AccountApiToken } from "./account-api-token.js";
|
|
5
|
+
import { handleApiError } from "./api-error.js";
|
|
6
|
+
import { extractCloudflareResult } from "./api-response.js";
|
|
7
|
+
import { createCloudflareApi } from "./api.js";
|
|
8
|
+
import { isBucket } from "./bucket.js";
|
|
9
|
+
/**
|
|
10
|
+
* Check if a resource is a LogPushJob
|
|
11
|
+
*/
|
|
12
|
+
export function isLogPushJob(resource) {
|
|
13
|
+
return resource?.[ResourceKind] === "cloudflare::LogPushJob";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates and manages Cloudflare LogPush Jobs for streaming logs to external
|
|
17
|
+
* destinations.
|
|
18
|
+
*
|
|
19
|
+
* LogPush jobs can be scoped to either an account or a zone, and support
|
|
20
|
+
* various log datasets like HTTP requests, firewall events, DNS logs, and more.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Basic HTTP request logs to S3 (zone-level)
|
|
24
|
+
* const httpLogs = await LogPushJob("http-logs", {
|
|
25
|
+
* zone: "example.com",
|
|
26
|
+
* dataset: "http_requests",
|
|
27
|
+
* destination: "s3://my-bucket/logs?region=us-west-2",
|
|
28
|
+
* name: "HTTP Request Logs"
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Account-level firewall events with filtering using a string destination
|
|
33
|
+
* const blockedRequests = await LogPushJob("blocked-requests", {
|
|
34
|
+
* dataset: "firewall_events",
|
|
35
|
+
* destination: "r2://my-bucket/firewall-logs?account-id=xxx&access-key-id=xxx&secret-access-key=xxx",
|
|
36
|
+
* filter:
|
|
37
|
+
* '{"where":{"and":[{"key":"Action","operator":"eq","value":"block"}]}}',
|
|
38
|
+
* maxUploadBytes: 100 * 1024 * 1024, // 100MB batches
|
|
39
|
+
* maxUploadIntervalSeconds: 300 // 5 minutes
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Stream logs to R2 using R2Bucket resource (requires R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY env vars)
|
|
44
|
+
* const bucket = await R2Bucket("logs-bucket", {
|
|
45
|
+
* name: "my-logs-bucket"
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* const logsToR2 = await LogPushJob("http-to-r2", {
|
|
49
|
+
* dataset: "http_requests",
|
|
50
|
+
* destination: bucket // Automatically constructs R2 URL with env credentials
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Or use a direct destination string with embedded credentials
|
|
55
|
+
* const logsToR2 = await LogPushJob("http-to-r2", {
|
|
56
|
+
* dataset: "http_requests",
|
|
57
|
+
* destination: `r2://my-logs-bucket/logs/{DATE}?account-id=${accountId}&access-key-id=${R2_ACCESS_KEY_ID}&secret-access-key=${R2_SECRET_ACCESS_KEY}`
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // High-volume analytics with custom output format
|
|
62
|
+
* const analyticsLogs = await LogPushJob("analytics-logs", {
|
|
63
|
+
* zone: myZone,
|
|
64
|
+
* dataset: "http_requests",
|
|
65
|
+
* destination: "s3://analytics-bucket/logs?region=eu-west-1",
|
|
66
|
+
* sample: 0.01, // 1% sampling for high-volume sites
|
|
67
|
+
* maxUploadRecords: 100000, // 100k records per batch
|
|
68
|
+
* outputOptions: {
|
|
69
|
+
* outputType: "ndjson",
|
|
70
|
+
* timestampFormat: "unixnano",
|
|
71
|
+
* fieldNames: [
|
|
72
|
+
* "ClientIP",
|
|
73
|
+
* "ClientRequestHost",
|
|
74
|
+
* "EdgeResponseStatus",
|
|
75
|
+
* "EdgeStartTimestamp"
|
|
76
|
+
* ],
|
|
77
|
+
* sampleRate: 0.1 // Additional 10% sampling within the batch
|
|
78
|
+
* }
|
|
79
|
+
* });
|
|
80
|
+
*
|
|
81
|
+
* @see https://developers.cloudflare.com/logs/get-started/enable-destinations/
|
|
82
|
+
* @see https://developers.cloudflare.com/api/resources/logpush/
|
|
83
|
+
*/
|
|
84
|
+
export function LogPushJob(id, props) {
|
|
85
|
+
return _LogPushJob(id, {
|
|
86
|
+
...props,
|
|
87
|
+
destination: typeof props.destination === "string"
|
|
88
|
+
? secret(props.destination)
|
|
89
|
+
: isBucket(props.destination)
|
|
90
|
+
? props.destination
|
|
91
|
+
: props.destination,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const _LogPushJob = Resource("cloudflare::LogPushJob", async function (_id, props) {
|
|
95
|
+
const api = await createCloudflareApi(props);
|
|
96
|
+
const isZoneScoped = !!props.zone;
|
|
97
|
+
let zoneId;
|
|
98
|
+
let accountId;
|
|
99
|
+
if (isZoneScoped) {
|
|
100
|
+
zoneId = typeof props.zone === "string" ? props.zone : props.zone.id;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
accountId = api.accountId;
|
|
104
|
+
}
|
|
105
|
+
const basePath = isZoneScoped
|
|
106
|
+
? `/zones/${zoneId}/logpush/jobs`
|
|
107
|
+
: `/accounts/${accountId}/logpush/jobs`;
|
|
108
|
+
if (this.phase === "delete") {
|
|
109
|
+
if (this.output?.id && props.delete !== false) {
|
|
110
|
+
const deleteResponse = await api.delete(`${basePath}/${this.output.id}`);
|
|
111
|
+
if (!deleteResponse.ok && deleteResponse.status !== 404) {
|
|
112
|
+
await handleApiError(deleteResponse, "delete", "logpush_job", String(this.output.id));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return this.destroy();
|
|
116
|
+
}
|
|
117
|
+
let destination;
|
|
118
|
+
let apiToken;
|
|
119
|
+
if (isBucket(props.destination)) {
|
|
120
|
+
const bucket = props.destination;
|
|
121
|
+
let accessKeyId = process.env.R2_ACCESS_KEY_ID;
|
|
122
|
+
let secretAccessKey = process.env.R2_SECRET_ACCESS_KEY;
|
|
123
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
124
|
+
try {
|
|
125
|
+
apiToken = await AccountApiToken("token", {
|
|
126
|
+
accountId: props.accountId,
|
|
127
|
+
apiKey: props.apiKey,
|
|
128
|
+
apiToken: props.apiToken,
|
|
129
|
+
baseUrl: props.baseUrl,
|
|
130
|
+
profile: props.profile,
|
|
131
|
+
email: props.email,
|
|
132
|
+
policies: [
|
|
133
|
+
{
|
|
134
|
+
effect: "allow",
|
|
135
|
+
permissionGroups: [
|
|
136
|
+
"Workers R2 Storage Write",
|
|
137
|
+
"Workers R2 Storage Read",
|
|
138
|
+
"Workers R2 Storage Bucket Item Read",
|
|
139
|
+
"Workers R2 Storage Bucket Item Write",
|
|
140
|
+
],
|
|
141
|
+
resources: {
|
|
142
|
+
[`com.cloudflare.edge.r2.bucket.${api.accountId}_${bucket.jurisdiction ?? "default"}_${bucket.name}`]: "*",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
});
|
|
147
|
+
accessKeyId = apiToken.accessKeyId.unencrypted;
|
|
148
|
+
secretAccessKey = apiToken.secretAccessKey.unencrypted;
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error(err);
|
|
152
|
+
console.warn("[Cloudflare Logpush Job] Warning: Cloudflare currently only allows the use of a Global API Key or an API Token with permission to create other API Tokens in order to generate new API Tokens programmatically.\n" +
|
|
153
|
+
"Please use your Global API Key, or create an API Token with the necessary permissions. For more information, see: https://alchemy.run/guides/cloudflare/#api-token");
|
|
154
|
+
throw new Error("Unable to create an API Token: Cloudflare only allows Global API Key or an API Token with permission to create other API Tokens. " +
|
|
155
|
+
"See https://alchemy.run/guides/cloudflare/#api-token for more details.");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
destination = `r2://${bucket.name}/logs/{DATE}?${new URLSearchParams({
|
|
159
|
+
"account-id": api.accountId,
|
|
160
|
+
"access-key-id": accessKeyId,
|
|
161
|
+
"secret-access-key": secretAccessKey,
|
|
162
|
+
}).toString()}`;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
destination = props.destination.unencrypted;
|
|
166
|
+
}
|
|
167
|
+
const jobConfig = {
|
|
168
|
+
dataset: props.dataset,
|
|
169
|
+
destination_conf: destination,
|
|
170
|
+
...(props.name && { name: props.name }),
|
|
171
|
+
...(props.enabled !== undefined && { enabled: props.enabled }),
|
|
172
|
+
...(props.frequency && { frequency: props.frequency }),
|
|
173
|
+
...(props.kind !== undefined && { kind: props.kind }),
|
|
174
|
+
...(props.maxUploadBytes !== undefined && {
|
|
175
|
+
max_upload_bytes: props.maxUploadBytes,
|
|
176
|
+
}),
|
|
177
|
+
...(props.maxUploadIntervalSeconds !== undefined && {
|
|
178
|
+
max_upload_interval_seconds: props.maxUploadIntervalSeconds,
|
|
179
|
+
}),
|
|
180
|
+
...(props.maxUploadRecords !== undefined && {
|
|
181
|
+
max_upload_records: props.maxUploadRecords,
|
|
182
|
+
}),
|
|
183
|
+
...(props.ownershipChallenge && {
|
|
184
|
+
ownership_challenge: props.ownershipChallenge,
|
|
185
|
+
}),
|
|
186
|
+
};
|
|
187
|
+
if (props.outputOptions) {
|
|
188
|
+
jobConfig.output_options = {
|
|
189
|
+
...(props.outputOptions.outputType && {
|
|
190
|
+
output_type: props.outputOptions.outputType,
|
|
191
|
+
}),
|
|
192
|
+
...(props.outputOptions.timestampFormat && {
|
|
193
|
+
timestamp_format: props.outputOptions.timestampFormat,
|
|
194
|
+
}),
|
|
195
|
+
...(props.outputOptions.fieldNames && {
|
|
196
|
+
field_names: props.outputOptions.fieldNames,
|
|
197
|
+
}),
|
|
198
|
+
...(props.outputOptions.fieldDelimiter && {
|
|
199
|
+
field_delimiter: props.outputOptions.fieldDelimiter,
|
|
200
|
+
}),
|
|
201
|
+
...(props.outputOptions.sampleRate !== undefined && {
|
|
202
|
+
sample_rate: props.outputOptions.sampleRate,
|
|
203
|
+
}),
|
|
204
|
+
...(props.outputOptions.batchPrefix && {
|
|
205
|
+
batch_prefix: props.outputOptions.batchPrefix,
|
|
206
|
+
}),
|
|
207
|
+
...(props.outputOptions.batchSuffix && {
|
|
208
|
+
batch_suffix: props.outputOptions.batchSuffix,
|
|
209
|
+
}),
|
|
210
|
+
...(props.outputOptions.cve202144228 !== undefined && {
|
|
211
|
+
"CVE-2021-44228": props.outputOptions.cve202144228,
|
|
212
|
+
}),
|
|
213
|
+
...(props.outputOptions.recordDelimiter && {
|
|
214
|
+
record_delimiter: props.outputOptions.recordDelimiter,
|
|
215
|
+
}),
|
|
216
|
+
...(props.outputOptions.recordPrefix && {
|
|
217
|
+
record_prefix: props.outputOptions.recordPrefix,
|
|
218
|
+
}),
|
|
219
|
+
...(props.outputOptions.recordSuffix && {
|
|
220
|
+
record_suffix: props.outputOptions.recordSuffix,
|
|
221
|
+
}),
|
|
222
|
+
...(props.outputOptions.recordTemplate && {
|
|
223
|
+
record_template: props.outputOptions.recordTemplate,
|
|
224
|
+
}),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const jobData = await withExponentialBackoff(async () => {
|
|
228
|
+
if (this.phase === "update" && this.output?.id) {
|
|
229
|
+
return await extractCloudflareResult(`update logpush job ${this.output.id}`, api.put(`${basePath}/${this.output.id}`, jobConfig));
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
return await extractCloudflareResult(`create logpush job for dataset ${props.dataset}`, api.post(basePath, jobConfig));
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
// if we just recently created an api token for R2, we can retry on 1002 which are caused by token propagation
|
|
236
|
+
(error) => {
|
|
237
|
+
console.warn("Received error when creating LogPush job, there may be a propagation delay", error.message);
|
|
238
|
+
return error.errorData?.[0]?.code === 1002;
|
|
239
|
+
}, 30, 100);
|
|
240
|
+
return {
|
|
241
|
+
type: "logpush_job",
|
|
242
|
+
id: jobData.id,
|
|
243
|
+
accountId: api.accountId,
|
|
244
|
+
dataset: jobData.dataset ?? props.dataset,
|
|
245
|
+
destination: secret(jobData.destination_conf ?? destination),
|
|
246
|
+
name: jobData.name ?? undefined,
|
|
247
|
+
enabled: jobData.enabled ?? props.enabled ?? true,
|
|
248
|
+
frequency: jobData.frequency ?? undefined,
|
|
249
|
+
filter: props.filter,
|
|
250
|
+
maxUploadBytes: jobData.max_upload_bytes ?? undefined,
|
|
251
|
+
maxUploadIntervalSeconds: jobData.max_upload_interval_seconds ?? undefined,
|
|
252
|
+
maxUploadRecords: jobData.max_upload_records ?? undefined,
|
|
253
|
+
outputOptions: jobData.output_options
|
|
254
|
+
? {
|
|
255
|
+
outputType: jobData.output_options.output_type,
|
|
256
|
+
timestampFormat: jobData.output_options.timestamp_format,
|
|
257
|
+
fieldNames: jobData.output_options.field_names,
|
|
258
|
+
fieldDelimiter: jobData.output_options.field_delimiter ?? undefined,
|
|
259
|
+
sampleRate: jobData.output_options.sample_rate ?? undefined,
|
|
260
|
+
batchPrefix: jobData.output_options.batch_prefix ?? undefined,
|
|
261
|
+
batchSuffix: jobData.output_options.batch_suffix ?? undefined,
|
|
262
|
+
cve202144228: jobData.output_options["CVE-2021-44228"] ?? undefined,
|
|
263
|
+
recordDelimiter: jobData.output_options.record_delimiter ?? undefined,
|
|
264
|
+
recordPrefix: jobData.output_options.record_prefix ?? undefined,
|
|
265
|
+
recordSuffix: jobData.output_options.record_suffix ?? undefined,
|
|
266
|
+
recordTemplate: jobData.output_options.record_template ?? undefined,
|
|
267
|
+
}
|
|
268
|
+
: undefined,
|
|
269
|
+
kind: jobData.kind || undefined,
|
|
270
|
+
errorMessage: jobData.error_message ?? undefined,
|
|
271
|
+
lastComplete: jobData.last_complete ?? undefined,
|
|
272
|
+
lastError: jobData.last_error ?? undefined,
|
|
273
|
+
createdAt: this.output?.createdAt ?? Date.now(),
|
|
274
|
+
modifiedAt: Date.now(),
|
|
275
|
+
};
|
|
276
|
+
});
|
|
277
|
+
//# sourceMappingURL=logpush-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logpush-job.js","sourceRoot":"","sources":["../../src/cloudflare/logpush-job.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ export interface MiniflareWorkerInput {
|
|
|
17
17
|
bundle: WorkerBundleSource;
|
|
18
18
|
port: number | undefined;
|
|
19
19
|
tunnel: boolean | undefined;
|
|
20
|
+
cwd: string;
|
|
20
21
|
}
|
|
21
22
|
export declare const buildWorkerOptions: (input: MiniflareWorkerInput) => Promise<{
|
|
22
23
|
watch: (signal: AbortSignal) => AsyncGenerator<miniflare.WorkerOptions>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-worker-options.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/miniflare/build-worker-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"build-worker-options.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/miniflare/build-worker-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AAGvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAEV,QAAQ,EAGT,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAgB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,aAAa,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kBAAkB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,YAAY,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACxC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAkCD,eAAO,MAAM,kBAAkB,GAC7B,OAAO,oBAAoB,KAC1B,OAAO,CAAC;IACT,KAAK,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,cAAc,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACxE,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC;CACrC,CA8XA,CAAC"}
|