@kiwa-test/edge 1.0.2 → 1.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/dist/index.d.ts CHANGED
@@ -63,4 +63,522 @@ interface InvokeEdgeHandlerResult {
63
63
  */
64
64
  declare function invokeEdgeHandler<TEnv extends EdgeEnvBindings = EdgeEnvBindings>(opts: InvokeEdgeHandlerOptions<TEnv>): Promise<InvokeEdgeHandlerResult>;
65
65
 
66
- export { type EdgeEnvBindings, type EdgeFetchHandler, type InvokeEdgeHandlerOptions, type InvokeEdgeHandlerResult, type KVMockEntry, type KVNamespace, type KVNamespaceListOptions, type KVNamespaceListResult, type KVNamespacePutOptions, type SimulatedExecutionContext, createKvNamespace, invokeEdgeHandler };
66
+ /**
67
+ * Advanced edge semantics — platform-neutral axis SSOT.
68
+ *
69
+ * v0.1 edge mocks only carried fetch invocation + lightweight KV helpers.
70
+ * v0.2 adds 8 production semantics that edge runtimes expose differently —
71
+ * Durable Objects, websocket upgrades, edge KV, geo replication, cron triggers,
72
+ * subrequest limits, CPU time limits, and streaming responses. Each axis is
73
+ * expressed as a small pure state-machine helper that returns a neutral
74
+ * envelope, so downstream tests can drive the axis without knowing the
75
+ * platform's payload dialect.
76
+ */
77
+ type EdgePlatform = 'cloudflare' | 'vercel' | 'deno';
78
+ type EdgeAxis = 'durable-object' | 'websocket-edge' | 'edge-kv' | 'geo-replicated' | 'cron-trigger' | 'subrequest-limit' | 'cpu-time-limit' | 'streaming-response';
79
+ /**
80
+ * Platform-neutral event names used inside the axis helpers. Real edge
81
+ * platforms expose different string ids (Cloudflare `durable_object.fetch`,
82
+ * Vercel `edge_function.session_affinity`, Deno Deploy `deploy.stateful_fetch`)
83
+ * — the {@link platformEventName} map handles the translation. Tests can
84
+ * assert on the neutral name via `step.neutralEvent` or on the
85
+ * platform-specific one via `step.platformEvent`.
86
+ */
87
+ type NeutralEventName = 'durable-object.created' | 'durable-object.requested' | 'durable-object.alarm-fired' | 'durable-object.storage-written' | 'websocket.upgrade-requested' | 'websocket.accepted' | 'websocket.message' | 'websocket.closed' | 'kv.read' | 'kv.write' | 'kv.cache-hit' | 'kv.cache-miss' | 'geo.primary-write' | 'geo.replica-lagged' | 'geo.replica-synced' | 'geo.conflict-resolved' | 'cron.scheduled' | 'cron.started' | 'cron.completed' | 'cron.failed' | 'subrequest.started' | 'subrequest.counted' | 'subrequest.limited' | 'subrequest.completed' | 'cpu.started' | 'cpu.budget-warning' | 'cpu.limited' | 'cpu.completed' | 'stream.opened' | 'stream.chunk-sent' | 'stream.backpressure' | 'stream.closed';
88
+ /**
89
+ * Translate a neutral event name to the platform dialect. Falls back to the
90
+ * neutral name if the platform has no specific dialect entry — this makes
91
+ * the map partial-safe without silent typos.
92
+ */
93
+ declare function platformEventName(platform: EdgePlatform, neutral: NeutralEventName): string;
94
+ /**
95
+ * Axis result envelope returned by every state-machine step. Edge semantics
96
+ * are pure helpers (no adapters); the envelope surfaces the next state
97
+ * transition metadata so tests can drive the next call without re-reading
98
+ * runtime-specific telemetry.
99
+ */
100
+ interface AxisStep<TState> {
101
+ neutralEvent: NeutralEventName;
102
+ platformEvent: string;
103
+ state: TState;
104
+ platform: EdgePlatform;
105
+ metadata: Record<string, string | number | boolean>;
106
+ }
107
+
108
+ /**
109
+ * Fidelity harness — collects the platform × axis coverage grid that
110
+ * downstream release-gate reports on. Not a runner (no side effect emit);
111
+ * pure inspection so tests / release-gate can assert "3 platform × 8 axis"
112
+ * without walking every neutral event by hand.
113
+ */
114
+ interface FidelityRow {
115
+ platform: EdgePlatform;
116
+ axis: EdgeAxis;
117
+ neutralEvents: NeutralEventName[];
118
+ platformEvents: string[];
119
+ }
120
+ interface FidelityCoverage {
121
+ platforms: EdgePlatform[];
122
+ axes: EdgeAxis[];
123
+ rows: FidelityRow[];
124
+ }
125
+ declare const AXIS_TO_EVENTS: Record<EdgeAxis, NeutralEventName[]>;
126
+ /**
127
+ * Collect the platform × axis coverage grid. `platforms` is the list of
128
+ * platforms to inspect — usually all 3 (`cloudflare`, `vercel`, `deno`).
129
+ *
130
+ * The output is a flat row list `platforms.length * 8 = 24` for the default
131
+ * setup, plus `platforms` + `axes` roll-up lists so callers can assert on
132
+ * the grid dimensions.
133
+ */
134
+ declare function collectFidelityCoverage(platforms: EdgePlatform[]): FidelityCoverage;
135
+
136
+ /**
137
+ * Durable Object — stateful, single-instance actor pinned to one edge
138
+ * location. Cloudflare Durable Objects are the canonical example; Vercel's
139
+ * closest analogue is a session-affine edge function, Deno Deploy exposes
140
+ * stateful objects backed by Deno KV. The mock reproduces the user-observable
141
+ * lifecycle: an instance is created once, receives fetch requests (which pin
142
+ * it "active"), can wake on a scheduled alarm, and persists to transactional
143
+ * storage. Hibernation / eviction is intentionally out of scope for v0.2 — the
144
+ * axis only exposes the 4 neutral events the fidelity grid tracks.
145
+ *
146
+ * State transitions:
147
+ * created → 'initialized'
148
+ * requestDurableObject → 'active' (from initialized or active)
149
+ * fireAlarm → 'active' (an alarm wakes the object)
150
+ * writeStorage → 'active' (a storage write implies an active handler)
151
+ */
152
+ type DoState = 'initialized' | 'active' | 'hibernated' | 'terminated';
153
+ interface DurableObjectSession {
154
+ id: string;
155
+ platform: EdgePlatform;
156
+ state: DoState;
157
+ requestCount: number;
158
+ storageKeys: Map<string, string>;
159
+ scheduledAlarmAt: number | null;
160
+ history: AxisStep<DoState>[];
161
+ }
162
+ /**
163
+ * Create a durable object instance. State starts at 'initialized' and no
164
+ * request has been served yet. Emits `durable-object.created`.
165
+ */
166
+ declare function createDurableObject(input: {
167
+ id: string;
168
+ platform: EdgePlatform;
169
+ }): DurableObjectSession;
170
+ /**
171
+ * Route a fetch request to the object. Pins the instance 'active' and bumps
172
+ * the request counter. Emits `durable-object.requested`.
173
+ */
174
+ declare function requestDurableObject(session: DurableObjectSession, input: {
175
+ url: string;
176
+ }): AxisStep<DoState>;
177
+ /**
178
+ * Fire the scheduled alarm. Wakes the object into 'active' regardless of the
179
+ * prior state and clears the pending alarm. Emits `durable-object.alarm-fired`.
180
+ */
181
+ declare function fireAlarm(session: DurableObjectSession): AxisStep<DoState>;
182
+ /**
183
+ * Write a key to transactional storage. Implies an active handler, so the
184
+ * object stays 'active'. Emits `durable-object.storage-written`.
185
+ */
186
+ declare function writeStorage(session: DurableObjectSession, input: {
187
+ key: string;
188
+ value: string;
189
+ }): AxisStep<DoState>;
190
+
191
+ /**
192
+ * WebSocket at the edge — the HTTP-upgrade handshake plus the message /
193
+ * close lifecycle. All three runtimes accept a `101 Switching Protocols`
194
+ * upgrade (Cloudflare `WebSocketPair`, Vercel edge websockets, Deno
195
+ * `Deno.upgradeWebSocket`) but expose different telemetry strings. The mock
196
+ * drives the neutral lifecycle so a test can assert the handshake ordering
197
+ * without a live socket.
198
+ *
199
+ * State transitions:
200
+ * requestWebSocketUpgrade → 'pending'
201
+ * acceptWebSocket → 'open' (only from 'pending')
202
+ * sendMessage → 'open' (only while 'open')
203
+ * closeWebSocket → 'closed'
204
+ */
205
+ type WsState = 'pending' | 'open' | 'closing' | 'closed';
206
+ interface WebSocketSession {
207
+ id: string;
208
+ platform: EdgePlatform;
209
+ state: WsState;
210
+ messages: string[];
211
+ history: AxisStep<WsState>[];
212
+ }
213
+ /**
214
+ * Begin the upgrade handshake. State starts 'pending' until the server
215
+ * accepts. Emits `websocket.upgrade-requested`.
216
+ */
217
+ declare function requestWebSocketUpgrade(input: {
218
+ id: string;
219
+ platform: EdgePlatform;
220
+ }): WebSocketSession;
221
+ /**
222
+ * Accept the pending upgrade, moving the socket 'open'. Rejects if the socket
223
+ * is not awaiting acceptance. Emits `websocket.accepted`.
224
+ */
225
+ declare function acceptWebSocket(session: WebSocketSession): AxisStep<WsState>;
226
+ /**
227
+ * Send a frame over the open socket. Rejects unless the socket is 'open'.
228
+ * Emits `websocket.message`.
229
+ */
230
+ declare function sendMessage(session: WebSocketSession, input: {
231
+ data: string;
232
+ }): AxisStep<WsState>;
233
+ /**
234
+ * Close the socket with a status code. Rejects if already closed. Emits
235
+ * `websocket.closed`.
236
+ */
237
+ declare function closeWebSocket(session: WebSocketSession, input: {
238
+ code: number;
239
+ }): AxisStep<WsState>;
240
+
241
+ /**
242
+ * Edge KV — a globally replicated key/value store with a read-through cache.
243
+ * Cloudflare KV, Vercel Edge Config, and Deno KV all trade strong consistency
244
+ * for low-latency edge reads: a write may take time to propagate, and reads
245
+ * are served from a per-POP cache when warm. The mock models the observable
246
+ * surface: a backing `store`, a `cache` layer that a read populates and a
247
+ * write invalidates, and a range query over a key prefix.
248
+ *
249
+ * There is no state machine per se — the store is always usable. `state`
250
+ * records the consistency model the caller declared so downstream tests can
251
+ * assert on it. The 4 neutral events distinguish a cold read, a write, a warm
252
+ * cache hit, and a miss on an absent key.
253
+ */
254
+ type KvState = 'consistent' | 'eventually-consistent';
255
+ interface EdgeKvSession {
256
+ platform: EdgePlatform;
257
+ store: Map<string, string>;
258
+ cache: Map<string, string>;
259
+ state: KvState;
260
+ history: AxisStep<KvState>[];
261
+ }
262
+ /**
263
+ * Construct a KV session. No event is emitted — the store is simply opened.
264
+ * Defaults to eventual consistency, the common edge-KV replication model.
265
+ */
266
+ declare function createEdgeKvSession(input: {
267
+ platform: EdgePlatform;
268
+ state?: KvState;
269
+ }): EdgeKvSession;
270
+ /**
271
+ * Read a key. Three outcomes:
272
+ * - cache warm → `kv.cache-hit`
273
+ * - store only → `kv.read` and the cache is populated (read-through)
274
+ * - absent → `kv.cache-miss`
275
+ */
276
+ declare function kvRead(session: EdgeKvSession, input: {
277
+ key: string;
278
+ }): AxisStep<KvState>;
279
+ /**
280
+ * Write a key. Updates the backing store and invalidates the cache entry so
281
+ * the next read goes through to the store. Emits `kv.write`.
282
+ */
283
+ declare function kvWrite(session: EdgeKvSession, input: {
284
+ key: string;
285
+ value: string;
286
+ }): AxisStep<KvState>;
287
+ /**
288
+ * Range query over a key prefix. Returns the matching keys (sorted, up to
289
+ * `limit`) alongside the emitted step. Emits `kv.read` since a range scan is a
290
+ * store read. `limit` defaults to no cap.
291
+ */
292
+ declare function kvRangeQuery(session: EdgeKvSession, input: {
293
+ prefix: string;
294
+ limit?: number;
295
+ }): {
296
+ matches: string[];
297
+ step: AxisStep<KvState>;
298
+ };
299
+
300
+ /**
301
+ * Geo-replicated store — a primary region that accepts writes and N replica
302
+ * regions that catch up asynchronously. This is the multi-region consistency
303
+ * model behind Cloudflare Smart Placement + KV replication, Vercel Edge Config
304
+ * replication, and Deno KV's primary/replica topology. The mock exposes the
305
+ * observable lifecycle a test cares about: a primary write bumps a version and
306
+ * leaves replicas lagging, each replica is marked lagged then synced, and a
307
+ * write conflict can be explicitly resolved.
308
+ *
309
+ * State transitions:
310
+ * createGeoReplicatedSession → 'in-sync' (version 0, no lag)
311
+ * geoPrimaryWrite → 'lagging' (replicas fall behind)
312
+ * markReplicaLagged → 'lagging'
313
+ * syncReplica → 'in-sync' (only once every replica lag = 0)
314
+ * resolveConflict → 'in-sync'
315
+ */
316
+ type GeoRegion = string;
317
+ type GeoState = 'in-sync' | 'lagging' | 'conflict-detected';
318
+ interface GeoReplicatedSession {
319
+ platform: EdgePlatform;
320
+ primaryRegion: GeoRegion;
321
+ replicaRegions: GeoRegion[];
322
+ state: GeoState;
323
+ version: number;
324
+ lagMs: Record<GeoRegion, number>;
325
+ history: AxisStep<GeoState>[];
326
+ }
327
+ /**
328
+ * Construct a geo-replicated session. Starts 'in-sync' at version 0 with every
329
+ * replica at zero lag. No event is emitted.
330
+ */
331
+ declare function createGeoReplicatedSession(input: {
332
+ platform: EdgePlatform;
333
+ primaryRegion: GeoRegion;
334
+ replicaRegions: GeoRegion[];
335
+ }): GeoReplicatedSession;
336
+ /**
337
+ * Write to the primary region. Bumps the version and marks every replica as
338
+ * lagging (they have not yet received the new version). Emits
339
+ * `geo.primary-write`.
340
+ */
341
+ declare function geoPrimaryWrite(session: GeoReplicatedSession, input: {
342
+ data: string;
343
+ }): AxisStep<GeoState>;
344
+ /**
345
+ * Report replication lag for a specific replica. Rejects an unknown region.
346
+ * Emits `geo.replica-lagged`.
347
+ */
348
+ declare function markReplicaLagged(session: GeoReplicatedSession, input: {
349
+ region: GeoRegion;
350
+ lagMs: number;
351
+ }): AxisStep<GeoState>;
352
+ /**
353
+ * Mark a replica caught up (lag → 0). When every replica has zero lag the
354
+ * session returns 'in-sync'. Rejects an unknown region. Emits
355
+ * `geo.replica-synced`.
356
+ */
357
+ declare function syncReplica(session: GeoReplicatedSession, input: {
358
+ region: GeoRegion;
359
+ }): AxisStep<GeoState>;
360
+ /**
361
+ * Resolve a write conflict for a region by picking a winning version. Rejects
362
+ * an unknown region. Adopts the chosen version, clears every replica's lag and
363
+ * forces the session back to 'in-sync'. Emits `geo.conflict-resolved`.
364
+ */
365
+ declare function resolveConflict(session: GeoReplicatedSession, input: {
366
+ region: GeoRegion;
367
+ chosenVersion: number;
368
+ }): AxisStep<GeoState>;
369
+
370
+ /**
371
+ * Cron trigger — scheduled invocation lifecycle. Edge platforms fire scheduled
372
+ * handlers from distinct sources (Cloudflare Cron Triggers + Queue consumers +
373
+ * Email routing, Vercel Cron jobs, Deno Deploy cron) yet share the same
374
+ * observable lifecycle: an event is scheduled, starts running, then either
375
+ * completes or fails. A failed run re-enters the schedule until `maxRetries`
376
+ * is exhausted, at which point it terminates in `failed`.
377
+ */
378
+ type CronState = 'scheduled' | 'running' | 'completed' | 'failed';
379
+ /** Which trigger source fired the scheduled handler. */
380
+ type CronTriggerType = 'scheduled' | 'queue' | 'email';
381
+ interface CronSession {
382
+ id: string;
383
+ platform: EdgePlatform;
384
+ triggerType: CronTriggerType;
385
+ cronSpec: string;
386
+ state: CronState;
387
+ startedAt: number | null;
388
+ retryCount: number;
389
+ maxRetries: number;
390
+ history: AxisStep<CronState>[];
391
+ }
392
+ /**
393
+ * Schedule a cron invocation. Emits `cron.scheduled` and seeds the session in
394
+ * the `scheduled` state. `triggerType` defaults to `scheduled` (a plain time
395
+ * trigger) and `maxRetries` defaults to 3.
396
+ */
397
+ declare function scheduleCron(input: {
398
+ id: string;
399
+ platform: EdgePlatform;
400
+ triggerType?: CronTriggerType;
401
+ cronSpec: string;
402
+ maxRetries?: number;
403
+ }): CronSession;
404
+ /**
405
+ * Begin executing a scheduled invocation. Transitions `scheduled` → `running`,
406
+ * stamps `startedAt`, and emits `cron.started`. Rejects if the session is not
407
+ * currently `scheduled` (already running / terminal).
408
+ */
409
+ declare function startCron(session: CronSession): AxisStep<CronState>;
410
+ /**
411
+ * Finish a running invocation successfully. Transitions `running` →
412
+ * `completed` and emits `cron.completed`. Rejects if not `running`.
413
+ */
414
+ declare function completeCron(session: CronSession, input: {
415
+ durationMs: number;
416
+ }): AxisStep<CronState>;
417
+ /**
418
+ * Fail a running invocation. Increments `retryCount`; if retries remain the
419
+ * session re-enters the `scheduled` state (to be picked up again), otherwise it
420
+ * terminates in `failed`. Emits `cron.failed` with `willRetry` reflecting the
421
+ * decision. Rejects if the session already `completed`.
422
+ */
423
+ declare function failCron(session: CronSession, input: {
424
+ reason: string;
425
+ }): AxisStep<CronState>;
426
+
427
+ /**
428
+ * Subrequest limit — outbound fetch budget per invocation. Edge runtimes cap
429
+ * how many subrequests a single handler may issue (Cloudflare Workers default
430
+ * 50 on the free plan, Vercel + Deno enforce comparable ceilings). The axis
431
+ * tracks a running count against the limit: below a warning threshold the
432
+ * session is `ok`, at the threshold it is `approaching-limit`, and once the
433
+ * count reaches the hard limit it is `limited` and further fetches are refused.
434
+ */
435
+ type SubrequestState = 'ok' | 'approaching-limit' | 'limited';
436
+ interface SubrequestSession {
437
+ platform: EdgePlatform;
438
+ count: number;
439
+ limit: number;
440
+ warningThreshold: number;
441
+ state: SubrequestState;
442
+ history: AxisStep<SubrequestState>[];
443
+ }
444
+ /**
445
+ * Open a subrequest budget. `limit` defaults to 50 (Workers free-plan default)
446
+ * and `warningThreshold` to 40 (80% of the default limit). Emits nothing — the
447
+ * budget is inert until the first {@link startSubrequest}.
448
+ */
449
+ declare function startSubrequestBudget(input: {
450
+ platform: EdgePlatform;
451
+ limit?: number;
452
+ warningThreshold?: number;
453
+ }): SubrequestSession;
454
+ /**
455
+ * Announce an outbound subrequest. Emits `subrequest.started` but does not
456
+ * advance the count (starting is distinct from counting — a started request
457
+ * only counts once it is admitted via {@link countSubrequest}). Rejects when
458
+ * the budget is already `limited`.
459
+ */
460
+ declare function startSubrequest(session: SubrequestSession, input: {
461
+ url: string;
462
+ }): AxisStep<SubrequestState>;
463
+ /**
464
+ * Count an admitted subrequest against the budget. Increments the count and
465
+ * emits `subrequest.limited` when the count reaches the hard limit (state →
466
+ * `limited`), otherwise `subrequest.counted` — flipping to `approaching-limit`
467
+ * once the warning threshold is crossed.
468
+ */
469
+ declare function countSubrequest(session: SubrequestSession): AxisStep<SubrequestState>;
470
+ /**
471
+ * Mark an outbound subrequest as finished. Emits `subrequest.completed` with
472
+ * the final count. Does not mutate state — a completed request that already
473
+ * tripped the limit stays `limited`.
474
+ */
475
+ declare function completeSubrequest(session: SubrequestSession, input: {
476
+ url: string;
477
+ durationMs: number;
478
+ }): AxisStep<SubrequestState>;
479
+ /** Remaining subrequest budget (never negative). */
480
+ declare function remainingBudget(session: SubrequestSession): number;
481
+
482
+ /**
483
+ * CPU time limit — per-invocation compute budget. Edge runtimes bill wall-clock
484
+ * loosely but enforce a hard CPU budget (Cloudflare Workers 50ms on the free
485
+ * plan, Vercel + Deno enforce comparable ceilings). The axis accumulates
486
+ * elapsed CPU time across ticks: below a warning threshold it is `running`, at
487
+ * the threshold it flips to `warning`, and once the budget is exhausted the
488
+ * invocation is `throttled` and no further work is admitted.
489
+ */
490
+ type CpuState = 'idle' | 'running' | 'warning' | 'throttled' | 'completed';
491
+ interface CpuSession {
492
+ platform: EdgePlatform;
493
+ budgetMs: number;
494
+ warningAtMs: number;
495
+ elapsedMs: number;
496
+ state: CpuState;
497
+ history: AxisStep<CpuState>[];
498
+ }
499
+ /**
500
+ * Open a CPU budget. `budgetMs` defaults to 50 (Workers free-plan default) and
501
+ * `warningAtMs` to 40 (80% of the default budget). Emits nothing — the budget
502
+ * is `idle` until {@link startCpu}.
503
+ */
504
+ declare function startCpuBudget(input: {
505
+ platform: EdgePlatform;
506
+ budgetMs?: number;
507
+ warningAtMs?: number;
508
+ }): CpuSession;
509
+ /**
510
+ * Begin consuming the CPU budget. Transitions `idle` → `running` and emits
511
+ * `cpu.started`. Rejects if the session is not `idle`.
512
+ */
513
+ declare function startCpu(session: CpuSession): AxisStep<CpuState>;
514
+ /**
515
+ * Advance the CPU clock by `deltaMs`. Emits `cpu.limited` when the accumulated
516
+ * time reaches the budget (state → `throttled`), `cpu.budget-warning` when it
517
+ * crosses the warning threshold (state → `warning`), otherwise a `cpu.started`
518
+ * heartbeat carrying the remaining budget. Rejects once the session is
519
+ * `throttled` or `completed`.
520
+ */
521
+ declare function tickCpu(session: CpuSession, input: {
522
+ deltaMs: number;
523
+ }): AxisStep<CpuState>;
524
+ /**
525
+ * Finish the invocation. Transitions to `completed` and emits `cpu.completed`
526
+ * with the used ratio. Rejects if the session never started (`idle`).
527
+ */
528
+ declare function completeCpu(session: CpuSession): AxisStep<CpuState>;
529
+
530
+ /**
531
+ * Streaming response — chunked / SSE / websocket body delivery with
532
+ * backpressure. Edge runtimes stream responses through a bounded buffer: while
533
+ * buffered bytes stay under the high-water mark the stream is `open` and chunks
534
+ * flow freely; once the mark is exceeded the stream enters `backpressure` and
535
+ * the producer must wait for the consumer to drain before resuming.
536
+ */
537
+ type StreamState = 'open' | 'backpressure' | 'closed';
538
+ /** Delivery mechanism for the streamed body. */
539
+ type StreamKind = 'chunked' | 'sse' | 'websocket';
540
+ interface StreamSession {
541
+ id: string;
542
+ platform: EdgePlatform;
543
+ kind: StreamKind;
544
+ state: StreamState;
545
+ chunksSent: number;
546
+ bytesSent: number;
547
+ highWaterMark: number;
548
+ history: AxisStep<StreamState>[];
549
+ }
550
+ /**
551
+ * Open a response stream. `kind` defaults to `chunked` and `highWaterMark` to
552
+ * 65536 bytes (64 KiB). Emits `stream.opened` and seeds counters at zero.
553
+ */
554
+ declare function openStream(input: {
555
+ id: string;
556
+ platform: EdgePlatform;
557
+ kind?: StreamKind;
558
+ highWaterMark?: number;
559
+ }): StreamSession;
560
+ /**
561
+ * Write a chunk to the stream. Advances `chunksSent` + `bytesSent`; when the
562
+ * buffered byte total exceeds the high-water mark the stream flips to
563
+ * `backpressure` and emits `stream.backpressure`, otherwise `stream.chunk-sent`.
564
+ * Rejects if the stream is already `closed`.
565
+ */
566
+ declare function sendChunk(session: StreamSession, input: {
567
+ data: string;
568
+ }): AxisStep<StreamState>;
569
+ /**
570
+ * Resume a back-pressured stream after the consumer drained. Transitions
571
+ * `backpressure` → `open`, drains one high-water mark worth of buffered bytes,
572
+ * and re-emits `stream.chunk-sent` tagged `resumed: true` (there is no distinct
573
+ * neutral resume event). Rejects unless the stream is `backpressure`.
574
+ */
575
+ declare function resumeStream(session: StreamSession): AxisStep<StreamState>;
576
+ /**
577
+ * Close the stream. Transitions to `closed` and emits `stream.closed` with the
578
+ * final chunk + byte totals. Rejects if the stream is already `closed`.
579
+ */
580
+ declare function closeStream(session: StreamSession, input: {
581
+ reason: string;
582
+ }): AxisStep<StreamState>;
583
+
584
+ export { AXIS_TO_EVENTS, type AxisStep, type CpuSession, type CpuState, type CronSession, type CronState, type CronTriggerType, type DoState, type DurableObjectSession, type EdgeAxis, type EdgeEnvBindings, type EdgeFetchHandler, type EdgeKvSession, type EdgePlatform, type FidelityCoverage, type FidelityRow, type GeoRegion, type GeoReplicatedSession, type GeoState, type InvokeEdgeHandlerOptions, type InvokeEdgeHandlerResult, type KVMockEntry, type KVNamespace, type KVNamespaceListOptions, type KVNamespaceListResult, type KVNamespacePutOptions, type KvState, type NeutralEventName, type SimulatedExecutionContext, type StreamKind, type StreamSession, type StreamState, type SubrequestSession, type SubrequestState, type WebSocketSession, type WsState, acceptWebSocket, closeStream, closeWebSocket, collectFidelityCoverage, completeCpu, completeCron, completeSubrequest, countSubrequest, createDurableObject, createEdgeKvSession, createGeoReplicatedSession, createKvNamespace, failCron, fireAlarm, geoPrimaryWrite, invokeEdgeHandler, kvRangeQuery, kvRead, kvWrite, markReplicaLagged, openStream, platformEventName, remainingBudget, requestDurableObject, requestWebSocketUpgrade, resolveConflict, resumeStream, scheduleCron, sendChunk, sendMessage, startCpu, startCpuBudget, startCron, startSubrequest, startSubrequestBudget, syncReplica, tickCpu, writeStorage };