@sproutboat/runtime 0.9.4 → 0.9.5

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
@@ -1,5 +1,11 @@
1
1
  # @sproutboat/runtime
2
2
 
3
+ ## 0.9.5
4
+
5
+ ### Patch Changes
6
+
7
+ - a357b91: Compile direct R2 transfer support only into artifacts that declare an R2 binding.
8
+
3
9
  ## 0.9.4
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutboat/runtime",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -578,6 +578,7 @@ static void sb_r2_delete_blob(const char* path, const char* bucket, const char*
578
578
  // path before it allocates a PendingRequest body. The context owns only a file
579
579
  // descriptor and small metadata buffers; object bytes stay in the kernel page
580
580
  // cache until the final fixed-size digest pass.
581
+ #ifdef SB_R2_TRANSFER
581
582
  typedef struct sb_r2_transfer_ctx {
582
583
  FILE* file;
583
584
  sqlite3* db;
@@ -805,6 +806,7 @@ size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx* ctx, size_t offset, char
805
806
  return fread(out, 1, wanted, ctx->file);
806
807
  }
807
808
  void sb_r2_transfer_download_close(sb_r2_transfer_ctx* ctx) { if (ctx) { if (ctx->file) fclose(ctx->file); free(ctx); } }
809
+ #endif
808
810
 
809
811
  // Run a script: one or more statements separated by semicolons. sqlite3_exec
810
812
  // handles the whole string, which prepare/step does not — it compiles the first
@@ -0,0 +1,17 @@
1
+ import { expect, test } from "bun:test";
2
+ import { EMPTY_BINDINGS, wrapNativeFetchHandler } from "./wrap";
3
+
4
+ const handler = "export default { fetch() { return new Response('ok'); } };";
5
+
6
+ test("direct R2 transfer ABI is emitted only for an R2 binding", () => {
7
+ const empty = wrapNativeFetchHandler(handler, "", {}, EMPTY_BINDINGS);
8
+ expect(empty).not.toContain("sb_r2_transfer_open");
9
+
10
+ const r2 = wrapNativeFetchHandler(handler, "", {}, { ...EMPTY_BINDINGS, r2: ["OBJECTS"] });
11
+ expect(r2).toContain("sb_r2_transfer_open");
12
+ });
13
+
14
+ test("scrypt remains available without a capability declaration", () => {
15
+ const wrapped = wrapNativeFetchHandler(handler, "sb_scrypt", {}, EMPTY_BINDINGS);
16
+ expect(wrapped).toContain("sb_scrypt");
17
+ });
package/src/wrap.ts CHANGED
@@ -194,13 +194,14 @@ export function wrapNativeFetchHandler(
194
194
  `globalThis.__sbOutbound = ${JSON.stringify(bindings.outbound)};\n` +
195
195
  (assets ? `globalThis.__sbAssets = ${JSON.stringify(assets)};\n` : "");
196
196
  // The native transfer hook runs before JavaScript receives its Request. It
197
- // has a real file-backed implementation only in embedded builds. The broker
198
- // transport supplies ABI-compatible stubs because its separate transfer
199
- // listener owns these URLs, while the shared uWebSockets patch is global.
197
+ // is only emitted for an R2 build, keeping its ABI out of applications that
198
+ // cannot issue an R2 ticket.
200
199
  const nativeTransferAbi =
201
- transport === "embedded"
202
- ? `Porffor.c\`const char* sb_standalone_app_name(void) { return ${JSON.stringify(appName)}; }\`;\n`
203
- : "Porffor.c`typedef struct sb_r2_transfer_ctx { int unused; } sb_r2_transfer_ctx; int sb_r2_transfer_open(const char* a, const char* b, size_t c, sb_r2_transfer_ctx** d) { if (d) *d = 0; return 404; } int sb_r2_transfer_write(sb_r2_transfer_ctx* a, const char* b, size_t c) { return 404; } int sb_r2_transfer_finish(sb_r2_transfer_ctx* a) { return 404; } void sb_r2_transfer_abort(sb_r2_transfer_ctx* a) {} int sb_r2_transfer_download_open(const char* a, const char* b, sb_r2_transfer_ctx** c) { if (c) *c = 0; return 404; } size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx* a) { return 0; } const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx* a) { return \"\"; } size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx* a, size_t b, char* c, size_t d) { return 0; } void sb_r2_transfer_download_close(sb_r2_transfer_ctx* a) {}`;\n";
200
+ bindings.r2.length === 0
201
+ ? ""
202
+ : transport === "embedded"
203
+ ? `Porffor.c\`const char* sb_standalone_app_name(void) { return ${JSON.stringify(appName)}; }\`;\n`
204
+ : 'Porffor.c`typedef struct sb_r2_transfer_ctx { int unused; } sb_r2_transfer_ctx; int sb_r2_transfer_open(const char* a, const char* b, size_t c, sb_r2_transfer_ctx** d) { if (d) *d = 0; return 404; } int sb_r2_transfer_write(sb_r2_transfer_ctx* a, const char* b, size_t c) { return 404; } int sb_r2_transfer_finish(sb_r2_transfer_ctx* a) { return 404; } void sb_r2_transfer_abort(sb_r2_transfer_ctx* a) {} int sb_r2_transfer_download_open(const char* a, const char* b, sb_r2_transfer_ctx** c) { if (c) *c = 0; return 404; } size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx* a) { return 0; } const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx* a) { return ""; } size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx* a, size_t b, char* c, size_t d) { return 0; } void sb_r2_transfer_download_close(sb_r2_transfer_ctx* a) {}`;\n';
204
205
  const wire = hasBindings(bindings)
205
206
  ? `__sbInstallBindings(env, ${JSON.stringify(bindings)});\n`
206
207
  : "";