sproutboat 0.32.0 → 0.33.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/CHANGELOG.md CHANGED
@@ -10,6 +10,37 @@ maintained going forward by the `release` skill.
10
10
 
11
11
  ## Unreleased
12
12
 
13
+ ## [0.33.0] - 2026-10-25
14
+
15
+ Built on `@sproutboat/runtime` 0.32.0, `@sproutboat/wire` 0.20.0 and
16
+ `@sproutboat/config` 0.6.0.
17
+
18
+ ### Added
19
+
20
+ - **Queue names and consumer settings.** A `queues` entry may be
21
+ `{ "binding": "JOBS", "queue": "jobs", "max_batch_size": 10, "max_batch_timeout": 1,
22
+ "max_retries": 3, "retry_delay": 0, "dead_letter_queue": "failed" }`. The settings
23
+ are named as in wrangler's `queues.consumers`, and `id` is optional there. `batch.queue`
24
+ is the queue's name. The build bakes the settings into `bindings.json` as `queueConfig`,
25
+ and `deploy` pins a provisioned id into such an object. These apply at every compatibility
26
+ date.
27
+ - **Queues like Cloudflare's from compatibility date 2026-10-31.**
28
+ - `send()` and `sendBatch()` return Promises of the queue's backlog, and `metrics()` is new.
29
+ - Bodies keep their content type (`json`, `text`, `bytes`, `v8`).
30
+ - Arguments are checked with workerd's errors.
31
+ - Messages carry `timestamp` as a Date of when they were sent, and `retry({ delaySeconds })`.
32
+ - The first of `ack()` and `retry()` wins.
33
+ - By default a retry is immediate, with at most 3 retries before the message is dropped or
34
+ sent to the dead letter queue.
35
+ - Queues conformance: 17/46 before, 41/46 after, standalone and through `sproutboat dev`.
36
+ The other 5 cases follow Cloudflare's documented behaviour where miniflare differs: real
37
+ backlog metrics, and first call wins.
38
+
39
+ ### Changed
40
+
41
+ - `types/sproutboat.d.ts`: the Queues types follow Workers (`QueueSendResult`,
42
+ `QueueMetrics`, readonly message fields, `metadata`, retry options).
43
+
13
44
  ## [0.32.0] - 2026-10-25
14
45
 
15
46
  Built on `@sproutboat/runtime` 0.31.0, `@sproutboat/toolchain` 0.16.1 and
package/README.md CHANGED
@@ -129,7 +129,7 @@ complete export. Existing output files require `--force`.
129
129
  "kv_namespaces": ["CACHE"], // bare name, or { "binding": "CACHE", "id": "kv_..." }
130
130
  "d1_databases": ["DB"],
131
131
  "r2_buckets": ["UPLOADS"],
132
- "queues": ["JOBS"],
132
+ "queues": ["JOBS"], // or { "binding": "JOBS", "queue": "jobs", "max_retries": 3, "dead_letter_queue": "failed" }
133
133
  "analytics_engine_datasets": ["METRICS"], // bare name only, no id
134
134
  "durable_objects": { "COUNTER": "Counter" },
135
135
  "ratelimiters": [{ "binding": "API", "limit": 100, "period": 60 }], // env.API.limit({ key })
package/SURFACE.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > Generated by `src/surface.test.ts` from `src/surface.ts` + the pinned
4
4
  > toolchain constants. Do not edit by hand — run `UPDATE_SURFACE=1 bun test`.
5
5
 
6
- **Package:** `sproutboat` 0.32.0
6
+ **Package:** `sproutboat` 0.33.0
7
7
 
8
8
  ## Commands
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sproutboat",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "Wrangler-shaped CLI for Sproutboat. Deploys workers to any control plane via --api-url / SPROUTBOAT_API_URL.",
5
5
  "keywords": [
6
6
  "cli",
@@ -63,10 +63,10 @@
63
63
  "dependencies": {
64
64
  "@sproutboat/artifact": "^0.3.0",
65
65
  "@sproutboat/assets": "^0.3.0",
66
- "@sproutboat/config": "^0.5.0",
67
- "@sproutboat/runtime": "^0.31.0",
66
+ "@sproutboat/config": "^0.6.0",
67
+ "@sproutboat/runtime": "^0.32.0",
68
68
  "@sproutboat/toolchain": "^0.16.1",
69
- "@sproutboat/wire": "^0.19.1"
69
+ "@sproutboat/wire": "^0.20.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@oxlint/plugins": "1.85.0",
@@ -78,10 +78,10 @@
78
78
  "typescript": "7.0.2"
79
79
  },
80
80
  "optionalDependencies": {
81
- "@sproutboat/cli-darwin-arm64": "0.32.0",
82
- "@sproutboat/cli-darwin-x64": "0.32.0",
83
- "@sproutboat/cli-linux-arm64": "0.32.0",
84
- "@sproutboat/cli-linux-x64": "0.32.0"
81
+ "@sproutboat/cli-darwin-arm64": "0.33.0",
82
+ "@sproutboat/cli-darwin-x64": "0.33.0",
83
+ "@sproutboat/cli-linux-arm64": "0.33.0",
84
+ "@sproutboat/cli-linux-x64": "0.33.0"
85
85
  },
86
86
  "engines": {
87
87
  "node": ">=18"
package/src/build.ts CHANGED
@@ -3,7 +3,7 @@ import { NATIVE_RESTORE_IDENTITY } from "./native-restore";
3
3
  import { cp, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { readAssetRules, walkAssets, type AssetManifest } from "./assets";
6
- import { resourceRefs, type SproutboatConfig } from "./config";
6
+ import { queueSettings, resourceRefs, type SproutboatConfig } from "./config";
7
7
  import { ensureSqliteObject } from "./sqlite";
8
8
  import { sqliteStamp } from "./sqlite";
9
9
  import { bearsslStamp, ensureBearssl } from "./bearssl";
@@ -149,6 +149,9 @@ async function prepareBuild(input: BuildInput) {
149
149
  d1: refsByKind.d1.map((ref) => ref.binding),
150
150
  r2: refsByKind.r2.map((ref) => ref.binding),
151
151
  queues: refsByKind.queue.map((ref) => ref.binding),
152
+ // Each queue's name and consumer settings (runtime 0.32): the sprout names batches and
153
+ // applies retries with them, the broker batches with them. Older readers ignore it.
154
+ queueConfig: queueSettings(input.config.queues),
152
155
  analytics: input.config.analytics_engine_datasets ?? [],
153
156
  do: Object.entries(input.config.durable_objects ?? {}).map(([binding, className]) => ({ binding, className })),
154
157
  services: input.config.services ?? [],
@@ -174,31 +174,64 @@ declare global {
174
174
 
175
175
  // ------------------------------------------------------------ Queues
176
176
 
177
+ type QueuesContentType = "json" | "text" | "bytes" | "v8";
178
+
177
179
  interface QueueSendOptions {
178
180
  delaySeconds?: number;
181
+ /** From compatibility date 2026-10-31. */
182
+ contentType?: QueuesContentType;
183
+ }
184
+
185
+ /** Cloudflare's QueueMetrics; `oldestMessageTimestamp` in ms since the epoch. */
186
+ interface QueueMetrics {
187
+ backlogCount: number;
188
+ backlogBytes: number;
189
+ oldestMessageTimestamp?: number;
179
190
  }
180
191
 
192
+ interface QueueSendResult {
193
+ metadata: { metrics: QueueMetrics };
194
+ }
195
+
196
+ /**
197
+ * From compatibility date 2026-10-31, send() and sendBatch() return Promises of the queue's
198
+ * backlog after the send, as on Workers; earlier dates return nothing at once.
199
+ */
181
200
  interface Queue<Body = unknown> {
182
- /** Returns immediately. The batch reaches `queue()` out of band. */
183
- send(body: Body, options?: QueueSendOptions): void;
184
- sendBatch(messages: Array<{ body: Body; delaySeconds?: number }>): void;
201
+ send(body: Body, options?: QueueSendOptions): Promise<QueueSendResult>;
202
+ sendBatch(
203
+ messages: Iterable<{ body: Body; delaySeconds?: number; contentType?: QueuesContentType }>,
204
+ options?: { delaySeconds?: number },
205
+ ): Promise<QueueSendResult>;
206
+ /** From compatibility date 2026-10-31. */
207
+ metrics(): Promise<QueueMetrics>;
208
+ }
209
+
210
+ interface QueueRetryOptions {
211
+ delaySeconds?: number;
185
212
  }
186
213
 
187
214
  interface QueueMessage<Body = unknown> {
188
- id: string;
189
- timestamp: number;
190
- body: Body;
191
- /** Mark as handled. A message neither acked nor retried counts as acked. */
215
+ readonly id: string;
216
+ /** When it was sent: a Date from compatibility date 2026-10-31, epoch ms before. */
217
+ readonly timestamp: Date;
218
+ readonly body: Body;
219
+ /** 1 on the first delivery. */
220
+ readonly attempts: number;
221
+ /** Mark as handled. A message neither acked nor retried counts as acked (retried if queue() throws). */
192
222
  ack(): void;
193
- /** Hand it back for another attempt. */
194
- retry(): void;
223
+ /** Hand it back for another attempt. The first of ack() and retry() wins. */
224
+ retry(options?: QueueRetryOptions): void;
195
225
  }
196
226
 
197
227
  interface MessageBatch<Body = unknown> {
198
- queue: string;
199
- messages: Array<QueueMessage<Body>>;
228
+ /** The queue's name (`queue` in sproutboat.jsonc, else the binding name). */
229
+ readonly queue: string;
230
+ readonly messages: ReadonlyArray<QueueMessage<Body>>;
231
+ /** From compatibility date 2026-10-31. */
232
+ readonly metadata: { metrics: QueueMetrics };
200
233
  ackAll(): void;
201
- retryAll(): void;
234
+ retryAll(options?: QueueRetryOptions): void;
202
235
  }
203
236
 
204
237
  // --------------------------------------------------- Durable Objects