@jundle/cloudflare 0.0.0-stage → 0.0.1-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/src/index.d.ts ADDED
@@ -0,0 +1,389 @@
1
+ // Type declarations for @jundle/cloudflare — the Cloudflare Workers
2
+ // runtime for the jundle dev server (SPEC §16.3, §16.2, §16.11).
3
+ //
4
+ // The module is a runtime plugin: it exports { createRunner,
5
+ // defaultOptions } directly, plus the same object as the default
6
+ // export. The dev server loads it through loadRuntimePlugin and
7
+ // talks to the returned runner only through the SPEC §16.2 runner
8
+ // interface (fetch / invalidate / dispose, plus optional start);
9
+ // the extra methods on the runner (startScript, dispatchFetch,
10
+ // setScript, dispatchScheduled, getQueueProducer) are the
11
+ // standalone/test path and are not part of that interface.
12
+ //
13
+ // The SPEC §16.2 core (InvalidatedModule, InvalidateOptions, the
14
+ // fetch/invalidate/dispose/start shape) is intentionally
15
+ // duplicated per runtime package — there is no shared package to
16
+ // import it from, and these two runtimes must not cross-import.
17
+ //
18
+ // No `any` is used anywhere in this file. Two types are structural
19
+ // by necessity, not by choice:
20
+ // - WranglerConfig / CloudflareRunnerMiniflareOptions are
21
+ // hand-written from the fields this package actually reads and
22
+ // builds (wrangler's config in config.js, the Miniflare mapping
23
+ // in bindings.js). They are NOT imported from "wrangler" or
24
+ // "miniflare": miniflare 4.20260730.0's shipped declarations do
25
+ // not resolve in this workspace (they import
26
+ // @cloudflare/workers-types, ./core and ./shared, none of which
27
+ // are installed), and wrangler's declarations pull miniflare's
28
+ // in, so importing either breaks typechecking for any consumer
29
+ // without skipLibCheck. The structural types below cover every
30
+ // field this package reads or builds; WranglerConfig carries an
31
+ // index signature so other wrangler fields remain readable (as
32
+ // unknown) instead of erroring.
33
+ // - CloudflareRunner.startScript returns the underlying Miniflare
34
+ // instance, typed as unknown for the same reason.
35
+
36
+ /** One invalidated module, as the dev server reports it (SPEC §16.2). */
37
+ export interface InvalidatedModule {
38
+ /** Graph name the module belongs to. */
39
+ env: string;
40
+ /** Absolute path of the invalidated file. */
41
+ file: string;
42
+ }
43
+
44
+ /** A class export of the dev entry, as discovered by the dev server's
45
+ * static analysis (SPEC §16.11). Only classes directly extending a
46
+ * cloudflare:workers import are detected; only non-static,
47
+ * non-computed instance methods are delegated to the wrapper. */
48
+ export interface ExportShapeClass {
49
+ /** Exported name of the class. */
50
+ name: string;
51
+ /** Which Workers base class it extends. */
52
+ kind: "durable-object" | "workflow" | "entrypoint";
53
+ /** Instance method names delegated by the generated wrapper. */
54
+ methods: string[];
55
+ }
56
+
57
+ /**
58
+ * The dev entry's export shape, as produced by the dev server's
59
+ * discoverEntryExports (SPEC §16.11). The runner only reads
60
+ * `classes` (to generate the static harness wrappers); `chain` is
61
+ * the server's own bookkeeping — the canonical files in the entry's
62
+ * re-export chain, used to re-run discovery — and is ignored here.
63
+ */
64
+ export interface ExportShape {
65
+ classes: ExportShapeClass[];
66
+ chain?: Set<string>;
67
+ }
68
+
69
+ /** Options passed to a runner's `invalidate` (SPEC §16.2). */
70
+ export interface InvalidateOptions {
71
+ /**
72
+ * A changed export shape. Present only when the server detected
73
+ * an export-shape change; the runner rebuilds Miniflare with new
74
+ * wrappers. Absent on an ordinary file change, where invalidate
75
+ * is a no-op (the harness pulls the recorded batch via the version
76
+ * route on next dispatch).
77
+ */
78
+ exportShape?: ExportShape;
79
+ }
80
+
81
+ /**
82
+ * Entry options for this runtime, opaque to jundle core (SPEC
83
+ * §16.2): the dev entry's `options` object, passed to createRunner
84
+ * untouched. Only the keys below are read.
85
+ */
86
+ export interface CloudflareRunnerOptions {
87
+ /**
88
+ * Path to the wrangler config file, resolved against configDir.
89
+ * Defaults to null, which auto-discovers wrangler.jsonc,
90
+ * wrangler.json, then wrangler.toml in the config directory.
91
+ */
92
+ wranglerConfig?: string | null;
93
+ /**
94
+ * Names of bindings to serve remotely (via the deployed remote
95
+ * proxy Worker) instead of locally. Each name must be a binding
96
+ * in the wrangler file. AI / Browser Rendering / Vectorize
97
+ * bindings are always remote and need not be listed.
98
+ */
99
+ remoteBindings?: string[];
100
+ /**
101
+ * Local service-binding targets ({ name: script }): extra workers
102
+ * run alongside the main worker via Miniflare's `workers` array
103
+ * (CF-3 multi-worker). Scripts are ESM source text.
104
+ */
105
+ serviceWorkers?: Record<string, string>;
106
+ }
107
+
108
+ /** A D1 migration entry kept on the runner options (not a Miniflare
109
+ * option — wrangler dev applies migrations itself, so the runner
110
+ * applies them against the started instance; see bindings.js). */
111
+ export interface D1Migration {
112
+ /** Binding name of the D1 database. */
113
+ binding: string;
114
+ /** Absolute directory holding the .sql migration files. */
115
+ dir: string;
116
+ }
117
+
118
+ /** A remote binding reference: the binding is served through the
119
+ * deployed remote proxy Worker. Only present when a proxy URL is
120
+ * configured (CLOUDFLARE_REMOTE_PROXY_URL); the runner throws
121
+ * otherwise, never silently falling back to local. */
122
+ export interface RemoteBindingRef {
123
+ remoteProxyConnectionString: string;
124
+ }
125
+
126
+ /**
127
+ * The Miniflare options the runner was built with, as produced by
128
+ * wranglerToMiniflareOptions (bindings.js) from the wrangler file.
129
+ * Every binding is wired; nothing is silently stubbed. Persistence
130
+ * mirrors wrangler dev (.wrangler/state/v3 under the project root).
131
+ */
132
+ export interface CloudflareRunnerMiniflareOptions {
133
+ modules: true;
134
+ /** Main Worker's name, from the wrangler config. */
135
+ name?: string;
136
+ compatibilityDate?: string;
137
+ compatibilityFlags?: string[];
138
+ /** Plain bindings: wrangler `vars` overlaid with `.dev.vars`. */
139
+ bindings: Record<string, string>;
140
+ /** Set only when a remote binding is in use. */
141
+ cloudflareAccountId?: string;
142
+ /** Set only when a remote binding is in use. */
143
+ cloudflareApiToken?: string;
144
+ kvNamespaces?: string[] | Record<string, string | ({ id?: string } & RemoteBindingRef)>;
145
+ kvPersist?: string;
146
+ r2Buckets?: string[] | Record<string, string | ({ id: string } & RemoteBindingRef)>;
147
+ r2Persist?: string;
148
+ d1Databases?: Record<string, string | ({ id: string } & RemoteBindingRef)>;
149
+ d1Persist?: string;
150
+ /** Kept for the runner to apply; not a Miniflare option. */
151
+ d1Migrations?: D1Migration[];
152
+ durableObjects?: Record<string, string | ({ className: string } & Partial<RemoteBindingRef>)>;
153
+ durableObjectsPersist?: string;
154
+ queueProducers?: Record<string, string | ({ queueName: string } & Partial<RemoteBindingRef>)>;
155
+ queueConsumers?: Record<
156
+ string,
157
+ {
158
+ maxBatchSize?: number;
159
+ maxBatchTimeout?: number;
160
+ maxRetries?: number;
161
+ deadLetterQueue?: string;
162
+ }
163
+ >;
164
+ workflows?: Record<string, { name: string; className: string } & Partial<RemoteBindingRef>>;
165
+ workflowsPersist?: string;
166
+ /** Cron triggers, from wrangler `triggers.crons`. */
167
+ crons?: string[];
168
+ serviceBindings?: Record<string, string>;
169
+ assets?: {
170
+ directory: string;
171
+ routerConfig: { has_user_worker: boolean };
172
+ };
173
+ ai?: { binding: string } & RemoteBindingRef;
174
+ browserRendering?: { binding: string } & RemoteBindingRef;
175
+ vectorize?: Record<string, { index_name: string } & RemoteBindingRef>;
176
+ }
177
+
178
+ /**
179
+ * The wrangler config object returned by wrangler's
180
+ * unstable_readConfig, as this package reads it. Only the fields
181
+ * this package uses are typed precisely; any other wrangler field
182
+ * is readable through the index signature as `unknown`. See the
183
+ * header note for why this is structural instead of imported from
184
+ * "wrangler".
185
+ */
186
+ export interface WranglerConfig {
187
+ name?: string;
188
+ compatibility_date?: string;
189
+ compatibility_flags?: string[];
190
+ /** Plain `vars` (string bindings) from the wrangler file. */
191
+ vars?: Record<string, string>;
192
+ kv_namespaces?: Array<{
193
+ binding: string;
194
+ id?: string;
195
+ preview_id?: string;
196
+ remote?: boolean;
197
+ }>;
198
+ r2_buckets?: Array<{
199
+ binding: string;
200
+ bucket_name?: string;
201
+ preview_bucket_name?: string;
202
+ jurisdiction?: string;
203
+ }>;
204
+ d1_databases?: Array<{
205
+ binding: string;
206
+ database_name?: string;
207
+ database_id?: string;
208
+ preview_database_id?: string;
209
+ migrations_dir?: string;
210
+ migrations_table?: string;
211
+ }>;
212
+ durable_objects?: {
213
+ bindings?: Array<{
214
+ name: string;
215
+ class_name: string;
216
+ script_name?: string;
217
+ }>;
218
+ };
219
+ queues?: {
220
+ producers?: Array<{
221
+ binding: string;
222
+ queue: string;
223
+ delivery_delay?: number;
224
+ remote?: boolean;
225
+ }>;
226
+ consumers?: Array<{
227
+ queue: string;
228
+ max_batch_size?: number;
229
+ max_batch_timeout?: number;
230
+ max_retries?: number;
231
+ dead_letter_queue?: string;
232
+ }>;
233
+ };
234
+ workflows?: Array<{
235
+ binding: string;
236
+ name: string;
237
+ class_name: string;
238
+ }>;
239
+ triggers?: {
240
+ crons?: string[];
241
+ };
242
+ services?: Array<{
243
+ binding: string;
244
+ service: string;
245
+ environment?: string;
246
+ }>;
247
+ /** A plain path string, or an object with a `directory`. */
248
+ assets?: string | { directory?: string };
249
+ ai?: {
250
+ binding: string;
251
+ staging?: boolean;
252
+ remote?: boolean;
253
+ };
254
+ browser?: {
255
+ binding: string;
256
+ };
257
+ vectorize?: Array<{
258
+ binding: string;
259
+ index_name?: string;
260
+ }>;
261
+ [key: string]: unknown;
262
+ }
263
+
264
+ /** Result of dispatching a scheduled event (cf-plugin-cf3.test.js
265
+ * asserts `outcome === "ok"`). */
266
+ export interface ScheduledDispatchResult {
267
+ outcome: string;
268
+ }
269
+
270
+ /** Options for sending a message through a Queue producer binding. */
271
+ export interface QueueSendOptions {
272
+ contentType?: "text" | "json" | "bytes" | "v8";
273
+ delaySeconds?: number;
274
+ }
275
+
276
+ /**
277
+ * A Queue producer binding, as returned by
278
+ * {@link CloudflareRunner.getQueueProducer}. The producer sends to
279
+ * the real queue; the consumer Worker's queue() handler runs on
280
+ * delivery. `send` is exercised by the repo's tests;
281
+ * `sendBatch` is the other half of the Workers Queue producer
282
+ * surface.
283
+ */
284
+ export interface QueueProducer<Body = unknown> {
285
+ send(message: Body, options?: QueueSendOptions): Promise<void>;
286
+ sendBatch(batch: Iterable<{ body: Body } & QueueSendOptions>): Promise<void>;
287
+ }
288
+
289
+ /**
290
+ * The runner returned by {@link createRunner}. The first group is
291
+ * the SPEC §16.2 runner interface the dev server uses; the second
292
+ * group is plugin-specific (standalone/test path, not part of the
293
+ * interface). `config`, `wranglerFile` and `options` are the
294
+ * resolved wrangler state, exposed for inspection.
295
+ */
296
+ export interface CloudflareRunner {
297
+ /** Parsed wrangler config (see {@link WranglerConfig}). */
298
+ config: WranglerConfig;
299
+ /** Absolute path of the wrangler config file that was read. */
300
+ wranglerFile: string;
301
+ /** Miniflare options built from the wrangler config. */
302
+ options: CloudflareRunnerMiniflareOptions;
303
+
304
+ /** Dispatch an app request to the entry's app. Throws if the
305
+ * runner has not been started. */
306
+ fetch(request: Request): Promise<Response>;
307
+ /**
308
+ * File-change signal. A no-op unless `opts.exportShape` is
309
+ * present, in which case Miniflare is rebuilt with new wrappers
310
+ * (built before the old instance is disposed) and the
311
+ * reconstruction is logged. Throws if called before start with
312
+ * an export shape.
313
+ */
314
+ invalidate(invalidated: InvalidatedModule[], opts?: InvalidateOptions): Promise<void>;
315
+ /**
316
+ * Start the harness worker, once the dev server has bound (it
317
+ * needs the base URL to fetch dev modules). Re-starting disposes
318
+ * the previous Miniflare instance first.
319
+ */
320
+ start(options: { baseUrl: string }): Promise<void>;
321
+ /** Dispose the Miniflare instance, if any. Safe to call twice. */
322
+ dispose(): Promise<void>;
323
+
324
+ /**
325
+ * Standalone/test path: start Miniflare with a given script (no
326
+ * harness). Not part of the runner interface. Returns the
327
+ * underlying Miniflare instance (typed as unknown — see the
328
+ * header note).
329
+ */
330
+ startScript(script: string): Promise<unknown>;
331
+ /**
332
+ * Dispatch a fetch by plain values, not a Request object
333
+ * (Miniflare's dispatchFetch does a cross-realm instanceof check
334
+ * that Node's Request fails). Throws if not started.
335
+ */
336
+ dispatchFetch(url: string, init?: RequestInit): Promise<Response>;
337
+ /** Replace the running worker's script. Throws if not started. */
338
+ setScript(script: string): Promise<void>;
339
+ /**
340
+ * Trigger the Worker's scheduled handler with a cron expression
341
+ * (empty string when omitted). Throws if not started.
342
+ */
343
+ dispatchScheduled(cron?: string): Promise<ScheduledDispatchResult>;
344
+ /**
345
+ * Return the Queue producer for a binding, so the caller can
346
+ * send; the consumer runs automatically on delivery. Throws if
347
+ * not started.
348
+ */
349
+ getQueueProducer(binding: string): Promise<QueueProducer>;
350
+ }
351
+
352
+ /** Arguments to {@link createRunner}. */
353
+ export interface CreateCloudflareRunnerArgs {
354
+ /** Project root: the wrangler file is resolved against this. */
355
+ configDir: string;
356
+ /** Dev URL of the entry module, fetched by the harness. */
357
+ entryUrl: string;
358
+ /**
359
+ * The entry's export shape from the server's static analysis
360
+ * (SPEC §16.11). Tolerated when absent — the harness is then
361
+ * built with no class wrappers.
362
+ */
363
+ exportShape?: ExportShape | null;
364
+ /** This runtime's entry options (see {@link CloudflareRunnerOptions}). */
365
+ options?: CloudflareRunnerOptions;
366
+ }
367
+
368
+ /**
369
+ * Create the Cloudflare Workers runner for a dev entry. Reads the
370
+ * wrangler config (via wrangler's unstable_readConfig) and maps it
371
+ * to Miniflare options; the Miniflare instance itself is not
372
+ * started until {@link CloudflareRunner.start} (the harness needs
373
+ * the dev server's bound base URL). Throws when no wrangler file
374
+ * is found, when remote bindings lack credentials or a proxy URL,
375
+ * or when `remoteBindings` names an unknown binding.
376
+ */
377
+ export declare function createRunner(args: CreateCloudflareRunnerArgs): Promise<CloudflareRunner>;
378
+
379
+ /** Default entry options: wrangler config auto-discovery. */
380
+ export declare const defaultOptions: CloudflareRunnerOptions;
381
+
382
+ /** The runtime plugin shape (SPEC §16.2): a single runtime. */
383
+ export interface CloudflareRuntimePlugin {
384
+ createRunner: typeof createRunner;
385
+ defaultOptions: CloudflareRunnerOptions;
386
+ }
387
+
388
+ declare const _default: CloudflareRuntimePlugin;
389
+ export default _default;