sproutboat 0.11.13 → 0.12.1
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 +34 -1
- package/SURFACE.md +2 -2
- package/package.json +8 -7
- package/src/build.ts +8 -2
- package/src/bundle.ts +1 -1
- package/src/surface.ts +2 -2
- package/src/toolchain.ts +2 -2
- package/src/types-gen.ts +9 -5
- package/types/sproutboat.d.ts +23 -16
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,37 @@ maintained going forward by the `release` skill.
|
|
|
10
10
|
|
|
11
11
|
## Unreleased
|
|
12
12
|
|
|
13
|
+
## [0.12.1] - 2026-09-30
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `sproutboat` with no arguments linked the platform repository and said to
|
|
18
|
+
use `bunx`, not `npx`. The CLI has shipped as a self-contained binary since
|
|
19
|
+
0.11.0, so `npx` works; the help now links https://docs.sproutboat.com.
|
|
20
|
+
- Handler types now declare `batch.ackAll()`/`retryAll()`, per-message
|
|
21
|
+
`delaySeconds` in `sendBatch()` and D1 `raw()`, matching the runtime.
|
|
22
|
+
Comments that said direct R2 uploads are unavailable standalone, and that an
|
|
23
|
+
un-acked queue message is redelivered, are corrected.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- `examples/runtime-comparison` runs one Worker-style app on Node, workerd and
|
|
28
|
+
a standalone Sproutboat binary and checks every response;
|
|
29
|
+
`benchmarks/v0.12.0` holds the first tagged run, which sproutboat.com
|
|
30
|
+
renders.
|
|
31
|
+
|
|
32
|
+
## [0.12.0] - 2026-09-28
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- Run three original Cloudflare Worker examples unchanged: JSON responses,
|
|
36
|
+
cookie parsing, and redirects. The example suite now checks 21 native apps.
|
|
37
|
+
- Pass `(request, env, ctx)` to fetch handlers using the 2026-09-28
|
|
38
|
+
compatibility date while preserving the earlier two-argument form for older apps.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- Update to Porffor alpha 10 via `@sproutboat/toolchain@^0.4.14` and use
|
|
42
|
+
`@sproutboat/runtime@^0.13.0` for native request decoding and redirects.
|
|
43
|
+
|
|
13
44
|
## [0.11.13] - 2026-09-26
|
|
14
45
|
|
|
15
46
|
### Added
|
|
@@ -627,7 +658,9 @@ its own package.
|
|
|
627
658
|
- Renamed the package to `sproutboat` (was `@sproutboat/cli`); dropped the
|
|
628
659
|
`sprout` bin alias in favour of a user-defined shell alias.
|
|
629
660
|
|
|
630
|
-
[Unreleased]: https://github.com/baronunread/sproutboat-cli/compare/v0.
|
|
661
|
+
[Unreleased]: https://github.com/baronunread/sproutboat-cli/compare/v0.12.1...HEAD
|
|
662
|
+
[0.12.1]: https://github.com/baronunread/sproutboat-cli/compare/v0.12.0...v0.12.1
|
|
663
|
+
[0.12.0]: https://github.com/baronunread/sproutboat-cli/compare/v0.11.13...v0.12.0
|
|
631
664
|
[0.11.13]: https://github.com/baronunread/sproutboat-cli/compare/v0.11.12...v0.11.13
|
|
632
665
|
[0.11.12]: https://github.com/baronunread/sproutboat-cli/compare/v0.11.11...v0.11.12
|
|
633
666
|
[0.11.11]: https://github.com/baronunread/sproutboat-cli/compare/v0.11.10...v0.11.11
|
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.
|
|
6
|
+
**Package:** `sproutboat` 0.12.1
|
|
7
7
|
|
|
8
8
|
## Commands
|
|
9
9
|
|
|
@@ -76,7 +76,7 @@ usage: sproutboat <init [name] | check [project-dir] | types [project-dir] | dev
|
|
|
76
76
|
| | |
|
|
77
77
|
| --- | --- |
|
|
78
78
|
| Zig | `0.16.0` (`zig cc -target x86_64-linux-musl`, static) |
|
|
79
|
-
| Provenance stamp | `zig-musl/0.16.0+porffor/
|
|
79
|
+
| Provenance stamp | `zig-musl/0.16.0+porffor/08ac7ee+uws/360c276d` |
|
|
80
80
|
| Artifact schema | `2` |
|
|
81
81
|
| Runtime | `native-fetch` |
|
|
82
82
|
| Capability profile | `http-sync-v0` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sproutboat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
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",
|
|
@@ -64,23 +64,24 @@
|
|
|
64
64
|
"@sproutboat/artifact": "^0.3.0",
|
|
65
65
|
"@sproutboat/assets": "^0.3.0",
|
|
66
66
|
"@sproutboat/config": "^0.4.0",
|
|
67
|
-
"@sproutboat/runtime": "^0.
|
|
68
|
-
"@sproutboat/toolchain": "^0.4.
|
|
67
|
+
"@sproutboat/runtime": "^0.13.0",
|
|
68
|
+
"@sproutboat/toolchain": "^0.4.14",
|
|
69
69
|
"@sproutboat/wire": "^0.9.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@oxlint/plugins": "1.81.0",
|
|
73
73
|
"@types/bun": "1.4.0",
|
|
74
|
+
"cookie": "2.0.1",
|
|
74
75
|
"lefthook": "2.1.12",
|
|
75
76
|
"oxfmt": "0.66.0",
|
|
76
77
|
"oxlint": "1.81.0",
|
|
77
78
|
"typescript": "7.0.2"
|
|
78
79
|
},
|
|
79
80
|
"optionalDependencies": {
|
|
80
|
-
"@sproutboat/cli-darwin-arm64": "0.
|
|
81
|
-
"@sproutboat/cli-darwin-x64": "0.
|
|
82
|
-
"@sproutboat/cli-linux-arm64": "0.
|
|
83
|
-
"@sproutboat/cli-linux-x64": "0.
|
|
81
|
+
"@sproutboat/cli-darwin-arm64": "0.12.1",
|
|
82
|
+
"@sproutboat/cli-darwin-x64": "0.12.1",
|
|
83
|
+
"@sproutboat/cli-linux-arm64": "0.12.1",
|
|
84
|
+
"@sproutboat/cli-linux-x64": "0.12.1"
|
|
84
85
|
},
|
|
85
86
|
"engines": {
|
|
86
87
|
"node": ">=18"
|
package/src/build.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { cp, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { cp, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { walkAssets, type AssetManifest } from "./assets";
|
|
5
5
|
import { resourceRefs, type SproutboatConfig } from "./config";
|
|
@@ -82,7 +82,13 @@ async function integrationIdentity(): Promise<string> {
|
|
|
82
82
|
const files = ["build.ts", "compile.ts", "sqlite.ts", "bearssl.ts", "toolchain.ts"].map((file) =>
|
|
83
83
|
resolve(import.meta.dir, file),
|
|
84
84
|
);
|
|
85
|
-
|
|
85
|
+
// Hash the patch implementation and its local modules so a Unicode patch
|
|
86
|
+
// edit cannot reuse a binary compiled with earlier builtin semantics.
|
|
87
|
+
const patchDir = dirname(Bun.resolveSync("@sproutboat/toolchain/patch", import.meta.dir));
|
|
88
|
+
const toolchainFiles = (await readdir(patchDir))
|
|
89
|
+
.filter((file) => file.endsWith(".ts") && !file.endsWith(".test.ts"))
|
|
90
|
+
.sort();
|
|
91
|
+
files.push(...toolchainFiles.map((file) => resolve(patchDir, file)));
|
|
86
92
|
return digest(Buffer.concat(await Promise.all(files.map((file) => readFile(file)))));
|
|
87
93
|
}
|
|
88
94
|
|
package/src/bundle.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* #89 — bundle the handler before Porffor sees it.
|
|
3
3
|
*
|
|
4
|
-
* Porffor
|
|
4
|
+
* Porffor supports ESM imports. We still bundle first so capability
|
|
5
5
|
* validation sees every dependency and the runtime wrapper receives one
|
|
6
6
|
* controlled default export.
|
|
7
7
|
*
|
package/src/surface.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { bold, dim, leaf } from "./style";
|
|
|
7
7
|
|
|
8
8
|
export const CLI_NAME = "sproutboat";
|
|
9
9
|
export const TAGLINE = "Deploy JavaScript handlers as tiny native binaries on your own VPS.";
|
|
10
|
-
export const
|
|
10
|
+
export const DOCS_URL = "https://docs.sproutboat.com";
|
|
11
11
|
|
|
12
12
|
export type Group = "Develop" | "Ship" | "Storage" | "Configure" | "Account";
|
|
13
13
|
|
|
@@ -356,7 +356,7 @@ export function helpText(): string {
|
|
|
356
356
|
lines.push(
|
|
357
357
|
"",
|
|
358
358
|
dim(`Run \`${CLI_NAME} <command>\` with no/invalid args to see that command's full usage.`),
|
|
359
|
-
dim(`Docs: ${
|
|
359
|
+
dim(`Docs: ${DOCS_URL}`),
|
|
360
360
|
);
|
|
361
361
|
return lines.join("\n");
|
|
362
362
|
}
|
package/src/toolchain.ts
CHANGED
|
@@ -38,7 +38,7 @@ const ZIG_SHA256 = {
|
|
|
38
38
|
// frozen reference handlers and update its COMPAT.md for any new mismatch before
|
|
39
39
|
// releasing — the alpha compiler's output can shift between pins. Checked by
|
|
40
40
|
// hand at bump time, not in CI.
|
|
41
|
-
// uWebSockets commit Porffor alpha-
|
|
41
|
+
// uWebSockets commit Porffor alpha-10 fetches for the native-fetch server.
|
|
42
42
|
const UWS_COMMIT = "360c276d";
|
|
43
43
|
const UWS_COMMIT_FULL = "360c276d609d59af56ae6932adb95154ace9f15f";
|
|
44
44
|
|
|
@@ -678,7 +678,7 @@ export function porfforVersion(): string {
|
|
|
678
678
|
|
|
679
679
|
export function esbuildVersion(): string {
|
|
680
680
|
// Legacy artifact field, retained so older control planes can read manifests.
|
|
681
|
-
// Handler bundling uses Bun.build and Porffor alpha
|
|
681
|
+
// Handler bundling uses Bun.build and Porffor alpha 10 needs no esbuild binary.
|
|
682
682
|
return "unused";
|
|
683
683
|
}
|
|
684
684
|
|
package/src/types-gen.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `sproutboat types` — the project's `env`, as TypeScript.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* types worth more here than they are there, not less.
|
|
4
|
+
* `env` remains available as a global in both compatibility modes. This file
|
|
5
|
+
* gives it the project's binding names and types. From 2026-09-28 it is also
|
|
6
|
+
* the second handler argument.
|
|
8
7
|
*
|
|
9
8
|
* The output declares `env` from `sproutboat.jsonc` and references the ambient
|
|
10
9
|
* types shipped in `types/sproutboat.d.ts`, so binding *shapes* version with
|
|
@@ -75,6 +74,11 @@ export function generateTypes(config: SproutboatConfig): string {
|
|
|
75
74
|
.join("\n")
|
|
76
75
|
: " // No bindings declared in sproutboat.jsonc yet.";
|
|
77
76
|
|
|
77
|
+
const handlerNote =
|
|
78
|
+
config.compatibility_date >= "2026-09-28"
|
|
79
|
+
? "The same object is passed as the second handler argument: fetch(request, env, ctx)."
|
|
80
|
+
: "The handler signature is fetch(request, ctx); env is only a global.";
|
|
81
|
+
|
|
78
82
|
return `${HEADER}
|
|
79
83
|
/// <reference types="sproutboat/types" />
|
|
80
84
|
|
|
@@ -82,7 +86,7 @@ declare global {
|
|
|
82
86
|
/**
|
|
83
87
|
* Bindings from sproutboat.jsonc, for project "${config.name}".
|
|
84
88
|
*
|
|
85
|
-
*
|
|
89
|
+
* ${handlerNote}
|
|
86
90
|
* Every call on these is synchronous, so \`await\` is allowed and does
|
|
87
91
|
* nothing.
|
|
88
92
|
*/
|
package/types/sproutboat.d.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* generates a project's `sproutboat-env.d.ts`, which references this file and
|
|
7
7
|
* declares `env` with that project's bindings.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
9
|
+
* Bindings are synchronous. Before compatibility date 2026-09-28, `env` is a
|
|
10
|
+
* global only and `ctx` is the second handler argument. From that date, `env`
|
|
11
|
+
* is also passed as the second argument and `ctx` as the third.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
declare global {
|
|
@@ -52,6 +52,8 @@ declare global {
|
|
|
52
52
|
/** The first row, or one column of it when named. `null` if there are none. */
|
|
53
53
|
first<T = Record<string, unknown>>(): T | null;
|
|
54
54
|
first<T = unknown>(column: string): T | null;
|
|
55
|
+
/** Rows as arrays of column values. */
|
|
56
|
+
raw<T = unknown[]>(): T[];
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
interface D1Database {
|
|
@@ -81,8 +83,8 @@ declare global {
|
|
|
81
83
|
httpMetadata: R2HttpMetadata;
|
|
82
84
|
customMetadata?: Record<string, string>;
|
|
83
85
|
/**
|
|
84
|
-
* The object as a string. A get holds the object whole in memory, so
|
|
85
|
-
*
|
|
86
|
+
* The object as a string. A get holds the object whole in memory, so serve
|
|
87
|
+
* large objects with `createDownloadUrl` instead.
|
|
86
88
|
*
|
|
87
89
|
* `new Response(obj.body, ...)` corrupts any non-ASCII/binary content: the
|
|
88
90
|
* runtime cannot tell these bytes apart from a string a handler built, so
|
|
@@ -159,9 +161,9 @@ declare global {
|
|
|
159
161
|
createMultipartUpload(key: string, options?: R2PutOptions): R2MultipartUpload;
|
|
160
162
|
/** Reconstructs a multipart handle after storing its key and upload id. */
|
|
161
163
|
resumeMultipartUpload(key: string, uploadId: string): R2MultipartUpload;
|
|
162
|
-
/**
|
|
164
|
+
/** Direct PUT to a one-use URL, streamed to storage without passing through the handler. */
|
|
163
165
|
createUploadUrl(key: string, options?: R2UploadTicketOptions): R2TransferTicket;
|
|
164
|
-
/**
|
|
166
|
+
/** Direct GET or HEAD from a one-use URL, including Range. */
|
|
165
167
|
createDownloadUrl(key: string, options?: R2DownloadTicketOptions): R2TransferTicket;
|
|
166
168
|
get(key: string): R2Object | null;
|
|
167
169
|
/** Metadata without the body. */
|
|
@@ -179,14 +181,14 @@ declare global {
|
|
|
179
181
|
interface Queue<Body = unknown> {
|
|
180
182
|
/** Returns immediately. The batch reaches `queue()` out of band. */
|
|
181
183
|
send(body: Body, options?: QueueSendOptions): void;
|
|
182
|
-
sendBatch(messages: Array<{ body: Body }>): void;
|
|
184
|
+
sendBatch(messages: Array<{ body: Body; delaySeconds?: number }>): void;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
interface QueueMessage<Body = unknown> {
|
|
186
188
|
id: string;
|
|
187
189
|
timestamp: number;
|
|
188
190
|
body: Body;
|
|
189
|
-
/** Mark as handled.
|
|
191
|
+
/** Mark as handled. A message neither acked nor retried counts as acked. */
|
|
190
192
|
ack(): void;
|
|
191
193
|
/** Hand it back for another attempt. */
|
|
192
194
|
retry(): void;
|
|
@@ -195,6 +197,8 @@ declare global {
|
|
|
195
197
|
interface MessageBatch<Body = unknown> {
|
|
196
198
|
queue: string;
|
|
197
199
|
messages: Array<QueueMessage<Body>>;
|
|
200
|
+
ackAll(): void;
|
|
201
|
+
retryAll(): void;
|
|
198
202
|
}
|
|
199
203
|
|
|
200
204
|
// --------------------------------------------------- Durable Objects
|
|
@@ -273,8 +277,8 @@ declare global {
|
|
|
273
277
|
*
|
|
274
278
|
* `crypto.scryptVerify` is a Sproutboat extension (#153), not WebCrypto: it
|
|
275
279
|
* re-derives a scrypt hash and compares it in constant time, for migrating
|
|
276
|
-
* password hashes made by Node/Bun `scrypt`. Verify-only on purpose;
|
|
277
|
-
* credentials
|
|
280
|
+
* password hashes made by Node/Bun `scrypt`. Verify-only on purpose; derive
|
|
281
|
+
* new credentials with HMAC via `crypto.subtle`.
|
|
278
282
|
*/
|
|
279
283
|
interface Crypto {
|
|
280
284
|
scryptVerify(
|
|
@@ -300,11 +304,7 @@ declare global {
|
|
|
300
304
|
scheduledTime: number;
|
|
301
305
|
}
|
|
302
306
|
|
|
303
|
-
/**
|
|
304
|
-
* `env` is a global, not a parameter. `ctx` is the second argument, and its
|
|
305
|
-
* only member is `waitUntil`: work that outlives the response, drained
|
|
306
|
-
* in-process and capped at 25s.
|
|
307
|
-
*/
|
|
307
|
+
/** Work that outlives the response, drained in-process and capped at 25s. */
|
|
308
308
|
interface ExecutionContext {
|
|
309
309
|
waitUntil(promise: Promise<unknown>): void;
|
|
310
310
|
}
|
|
@@ -318,6 +318,13 @@ declare global {
|
|
|
318
318
|
queue?(batch: MessageBatch<QueueBody>, ctx: ExecutionContext): void | Promise<void>;
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
/** Handler signature for compatibility dates from 2026-09-28. */
|
|
322
|
+
interface WorkersHandler<Bindings = Record<string, unknown>, QueueBody = unknown> {
|
|
323
|
+
fetch(request: Request, env: Bindings, ctx: ExecutionContext): Response | Promise<Response>;
|
|
324
|
+
scheduled?(event: ScheduledEvent, env: Bindings, ctx: ExecutionContext): void | Promise<void>;
|
|
325
|
+
queue?(batch: MessageBatch<QueueBody>, env: Bindings, ctx: ExecutionContext): void | Promise<void>;
|
|
326
|
+
}
|
|
327
|
+
|
|
321
328
|
/**
|
|
322
329
|
* What a Durable Object class implements. Declare it above the default
|
|
323
330
|
* export and name it in `durable_objects`.
|