sproutboat 0.13.0 → 0.14.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,28 @@ maintained going forward by the `release` skill.
10
10
 
11
11
  ## Unreleased
12
12
 
13
+ ## [0.14.0] - 2026-10-04
14
+
15
+ ### Changed
16
+
17
+ - `fetch()` reaches any public address with no configuration, and never a
18
+ private or reserved one: loopback, private networks, link-local and cloud
19
+ metadata, and their IPv6 forms. The check runs on the resolved address at
20
+ connect time, in deployed sprouts and standalone binaries alike. Operators can
21
+ allow specific addresses with `SB_EGRESS_ALLOW`
22
+ (baronunread/sproutboat#174).
23
+ - Every build writes `bindings.json`, so every deployment gets a broker.
24
+
25
+ ### Deprecated
26
+
27
+ - `outbound` in `sproutboat.jsonc` is ignored with a warning, and will be
28
+ refused in a later release.
29
+
30
+ ### Fixed
31
+
32
+ - `fetch()` to an IPv6 literal such as `http://[::1]:9/` works in standalone
33
+ binaries; `URL.hostname` used to come back as `[`.
34
+
13
35
  ## [0.13.0] - 2026-10-04
14
36
 
15
37
  ### Added
@@ -782,7 +804,8 @@ its own package.
782
804
  - Renamed the package to `sproutboat` (was `@sproutboat/cli`); dropped the
783
805
  `sprout` bin alias in favour of a user-defined shell alias.
784
806
 
785
- [Unreleased]: https://github.com/baronunread/sproutboat-cli/compare/v0.13.0...HEAD
807
+ [Unreleased]: https://github.com/baronunread/sproutboat-cli/compare/v0.14.0...HEAD
808
+ [0.14.0]: https://github.com/baronunread/sproutboat-cli/compare/v0.13.0...v0.14.0
786
809
  [0.13.0]: https://github.com/baronunread/sproutboat-cli/compare/v0.12.7...v0.13.0
787
810
  [0.12.7]: https://github.com/baronunread/sproutboat-cli/compare/v0.12.6...v0.12.7
788
811
  [0.12.6]: https://github.com/baronunread/sproutboat-cli/compare/v0.12.5...v0.12.6
package/README.md CHANGED
@@ -133,7 +133,6 @@ complete export. Existing output files require `--force`.
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 })
136
- "outbound": ["api.example.com"],
137
136
  "triggers": { "crons": ["*/5 * * * *"] },
138
137
  "assets": { "directory": "public", "binding": "ASSETS", "run_sprout_first": ["/api/*"] }
139
138
  }
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.13.0
6
+ **Package:** `sproutboat` 0.14.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.13.0",
3
+ "version": "0.14.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.4.0",
67
- "@sproutboat/runtime": "^0.13.5",
66
+ "@sproutboat/config": "^0.5.0",
67
+ "@sproutboat/runtime": "^0.14.0",
68
68
  "@sproutboat/toolchain": "^0.4.24",
69
- "@sproutboat/wire": "^0.9.3"
69
+ "@sproutboat/wire": "^0.11.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@oxlint/plugins": "1.81.0",
@@ -78,10 +78,10 @@
78
78
  "typescript": "7.0.2"
79
79
  },
80
80
  "optionalDependencies": {
81
- "@sproutboat/cli-darwin-arm64": "0.13.0",
82
- "@sproutboat/cli-darwin-x64": "0.13.0",
83
- "@sproutboat/cli-linux-arm64": "0.13.0",
84
- "@sproutboat/cli-linux-x64": "0.13.0"
81
+ "@sproutboat/cli-darwin-arm64": "0.14.0",
82
+ "@sproutboat/cli-darwin-x64": "0.14.0",
83
+ "@sproutboat/cli-linux-arm64": "0.14.0",
84
+ "@sproutboat/cli-linux-x64": "0.14.0"
85
85
  },
86
86
  "engines": {
87
87
  "node": ">=18"
package/src/build.ts CHANGED
@@ -138,7 +138,6 @@ export async function buildArtifact(input: BuildInput): Promise<BuildOutput> {
138
138
  const bindings = {
139
139
  kv: refsByKind.kv.map((ref) => ref.binding),
140
140
  secrets: input.config.secrets ?? [],
141
- outbound: input.config.outbound ?? [],
142
141
  d1: refsByKind.d1.map((ref) => ref.binding),
143
142
  r2: refsByKind.r2.map((ref) => ref.binding),
144
143
  queues: refsByKind.queue.map((ref) => ref.binding),
@@ -320,15 +319,10 @@ export async function buildArtifact(input: BuildInput): Promise<BuildOutput> {
320
319
  await writeFile(resolve(artifactDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`);
321
320
  // Bindings live beside the manifest, not in it: the artifact manifest schema is
322
321
  // frozen at v2. The control plane reads this to configure the per-deployment
323
- // broker (KV / D1 / R2 / queue names, secret names, outbound allowlist, cron
324
- // schedules, Durable Object classes).
325
- const hasBindings =
326
- Object.values(bindings).some((value) => Array.isArray(value) && value.length > 0) ||
327
- Object.keys(bindings.resources).length > 0 ||
328
- Object.keys(bindings.vars).length > 0;
329
- if (hasBindings) {
330
- await writeFile(resolve(artifactDir, "bindings.json"), `${JSON.stringify(bindings, null, 2)}\n`);
331
- } else await rm(resolve(artifactDir, "bindings.json"), { force: true });
322
+ // broker (KV / D1 / R2 / queue names, secret names, cron schedules, Durable
323
+ // Object classes). Written even when empty: its presence is what gives a
324
+ // deployment a broker, and fetch() needs one with no binding (#174).
325
+ await writeFile(resolve(artifactDir, "bindings.json"), `${JSON.stringify(bindings, null, 2)}\n`);
332
326
 
333
327
  // Static assets: copy the directory next to the artifact and record a manifest
334
328
  // the edge serves from directly (assets-first) and the broker reads for
package/src/main.ts CHANGED
@@ -212,6 +212,7 @@ async function readProjectConfig(directory = process.cwd()) {
212
212
  }
213
213
  const parsed = parseConfig(configSource);
214
214
  if (!parsed.ok) fail(parsed.errors.join("\n"));
215
+ for (const warning of parsed.warnings) console.warn(amber(`! ${warning}`));
215
216
  return { directory: projectDirectory, config: parsed.value };
216
217
  }
217
218
 
@@ -234,7 +235,7 @@ async function readProject(directory = process.cwd()) {
234
235
  } catch (cause) {
235
236
  fail(cause instanceof BundleError ? cause.message : String(cause));
236
237
  }
237
- const supported = validateHttpSyncSource(bundle.code, (project.config.outbound ?? []).length > 0);
238
+ const supported = validateHttpSyncSource(bundle.code);
238
239
  if (!supported.ok) fail(supported.errors.join("\n"));
239
240
  return { ...project, sourcePath, source, bundle };
240
241
  }
package/src/report.ts CHANGED
@@ -66,7 +66,6 @@ function bindingRows(config: SproutboatConfig): string[][] {
66
66
  rows.push([`env.${name}`, "durable object", className]);
67
67
  for (const rl of config.ratelimiters ?? [])
68
68
  rows.push([`env.${rl.binding}`, "rate limiter", `${rl.limit} / ${rl.period}s`]);
69
- for (const host of config.outbound ?? []) rows.push([`fetch()`, "outbound", host]);
70
69
  for (const cron of config.triggers?.crons ?? []) rows.push([`scheduled()`, "cron", cron]);
71
70
  if (config.assets?.binding) rows.push([`env.${config.assets.binding}`, "assets", config.assets.directory ?? ""]);
72
71
  return rows;
@@ -29,7 +29,7 @@ export type StandaloneBuildResult = { outPath: string; bytes: number };
29
29
  * Outbound `fetch` is absent from this list: http and https both work, with
30
30
  * BearSSL and the Mozilla root set compiled in.
31
31
  */
32
- export function unsupportedBindings(bindings: Pick<Partial<Bindings>, "services" | "outbound">): string[] {
32
+ export function unsupportedBindings(bindings: Pick<Partial<Bindings>, "services">): string[] {
33
33
  const reasons: string[] = [];
34
34
  if ((bindings.services ?? []).length > 0) {
35
35
  reasons.push("service bindings call another deployment through an edge, which a standalone binary has none of");