@sproutboat/toolchain 0.4.7 → 0.4.9

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,21 @@
1
1
  # @sproutboat/toolchain
2
2
 
3
+ ## 0.4.9
4
+
5
+ ### Patch Changes
6
+
7
+ - f070d70: Revert native R2 transfer size-gating (#202). It saved ~11KB of `__text`
8
+ (~1.3% of a typical binary) and on macOS didn't even change the shipped
9
+ file size, since `__TEXT` is page-aligned. Not worth the `#ifdef`
10
+ guard-placement bug class it introduced. R2 transfer support is native code
11
+ again, always compiled in with 404 stubs where unused, same as before #202.
12
+
13
+ ## 0.4.8
14
+
15
+ ### Patch Changes
16
+
17
+ - Republish under a new version: npm registry stuck 0.4.7 in a conflicted staged state after an interrupted OIDC trusted-publish attempt. No code changes from 0.4.7.
18
+
3
19
  ## 0.4.7
4
20
 
5
21
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutboat/toolchain",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -28,9 +28,7 @@ async function fixture(): Promise<{ archive: string; sha256: string }> {
28
28
  " }\n" +
29
29
  " return -1;\n" +
30
30
  "}\n",
31
- "compiler/index.js":
32
- " '-xc', '-', '-c',\n uSocketsArchive,\n '-lm'\n" +
33
- " '-I', `${uwsDir}/uSockets/src`,\n",
31
+ "compiler/index.js": " '-xc', '-', '-c',\n uSocketsArchive,\n '-lm'\n",
34
32
  "compiler/uwebsockets.js":
35
33
  "static const size_t REQUEST_BODY_MAX_BYTES = 1024u * 1024u;\n" +
36
34
  "int porf_native_fetch_read_value(struct jsval value, const char** out_buf, size_t* out_len, char** out_owned);\n" +
package/src/patch.test.ts CHANGED
@@ -3,7 +3,7 @@ import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { EMPTY_BINDINGS, wrapNativeFetchHandler } from "../../runtime/src/wrap";
6
- import { patchCompilerArgs, patchRenderJs, patchUwebsockets } from "./patch";
6
+ import { patchRenderJs, patchUwebsockets } from "./patch";
7
7
 
8
8
  // The parts of Porffor's compiler/render.js the patch anchors to.
9
9
  const RENDER = `void porf_native_fetch_runtime_init(void) {
@@ -37,16 +37,6 @@ int porf_native_fetch_read_value(jsval value, const char** out_buf, size_t* out_
37
37
  }
38
38
  `;
39
39
 
40
- const COMPILER_INDEX = `const compileArgs = [
41
- '-xc', '-', '-c',
42
- ];
43
- const linkArgs = [
44
- '-I', \`${"${uwsDir}"}/uSockets/src\`,
45
- uSocketsArchive,
46
- '-lm'
47
- ];
48
- `;
49
-
50
40
  // Porffor's compiler/uwebsockets.js, trimmed to the parts the patch touches:
51
41
  // body limit (#56), the #156 status-line switch, #163's collect_headers, and
52
42
  // #176's read_value forward decl / is_forbidden_response_header /
@@ -241,23 +231,7 @@ test("a drifted shim fails loudly instead of silently no-op'ing", async () => {
241
231
  }
242
232
  });
243
233
 
244
- test("native capability flags reach both the generated C and socket-shim C++ compiles", async () => {
245
- const root = await mkdtemp(join(tmpdir(), "sb-patch-compiler-"));
246
- try {
247
- await mkdir(join(root, "compiler"), { recursive: true });
248
- await writeFile(join(root, "compiler/index.js"), COMPILER_INDEX);
249
- await patchCompilerArgs(root);
250
- const once = await readFile(join(root, "compiler/index.js"), "utf8");
251
- expect(once.match(/SB_EXTRA_CFLAGS/g)).toHaveLength(4);
252
- expect(once).toContain("SB_UWS_EXTRA_CFLAGS");
253
- await patchCompilerArgs(root);
254
- expect(await readFile(join(root, "compiler/index.js"), "utf8")).toBe(once);
255
- } finally {
256
- await rm(root, { recursive: true, force: true });
257
- }
258
- });
259
-
260
- test("R2 builds define every direct transfer symbol the gated socket shim calls", async () => {
234
+ test("broker transport defines every direct R2 transfer symbol the patched shim calls", async () => {
261
235
  const root = await shimDir();
262
236
  try {
263
237
  await patchUwebsockets(root);
@@ -269,7 +243,7 @@ test("R2 builds define every direct transfer symbol the gated socket shim calls"
269
243
  "export default { fetch() { return new Response('ok'); } }",
270
244
  "",
271
245
  {},
272
- { ...EMPTY_BINDINGS, r2: ["OBJECTS"] },
246
+ EMPTY_BINDINGS,
273
247
  8080,
274
248
  "2026-08-26",
275
249
  "test",
@@ -285,42 +259,6 @@ test("R2 builds define every direct transfer symbol the gated socket shim calls"
285
259
  }
286
260
  });
287
261
 
288
- test("the direct R2 socket path is excluded unless the compiler enables it", async () => {
289
- const root = await shimDir();
290
- try {
291
- await patchUwebsockets(root);
292
- const shim = await readFile(join(root, "compiler/uwebsockets.js"), "utf8");
293
- expect(shim).toContain("#ifdef SB_R2_TRANSFER");
294
- expect(shim).toContain("#endif\n __porffor_js_enter();");
295
- } finally {
296
- await rm(root, { recursive: true, force: true });
297
- }
298
- });
299
-
300
- test("an existing compiler cache upgrades to the gated R2 socket path", async () => {
301
- const root = await shimDir();
302
- try {
303
- await patchUwebsockets(root);
304
- const file = join(root, "compiler/uwebsockets.js");
305
- const current = await readFile(file, "utf8");
306
- const legacy = current
307
- .replace('#ifdef SB_R2_TRANSFER\nextern "C" {', 'extern "C" {')
308
- .replace("\n#endif\nstatic void on_request", "\nstatic void on_request")
309
- .replace(
310
- "#ifdef SB_R2_TRANSFER\n if (try_handle_r2_transfer(res, req, method)) return;\n#endif\n",
311
- " if (try_handle_r2_transfer(res, req, method)) return;\n",
312
- );
313
- await writeFile(file, legacy);
314
-
315
- await patchUwebsockets(root);
316
- const upgraded = await readFile(file, "utf8");
317
- expect(upgraded).toContain('#ifdef SB_R2_TRANSFER\nextern "C" {');
318
- expect(upgraded).toContain("#endif\n __porffor_js_enter();");
319
- } finally {
320
- await rm(root, { recursive: true, force: true });
321
- }
322
- });
323
-
324
262
  test("#165: render.js routes console output to stderr, unbuffered, idempotently", async () => {
325
263
  const root = await mkdtemp(join(tmpdir(), "sb-patch-render-"));
326
264
  try {
package/src/patch.ts CHANGED
@@ -167,14 +167,6 @@ const CFLAGS_INJECT =
167
167
  " ...(process.env.SB_EXTRA_CFLAGS ? process.env.SB_EXTRA_CFLAGS.split(' ').filter(Boolean) : []),\n";
168
168
  const CFLAGS_MARKER = "SB_EXTRA_CFLAGS";
169
169
 
170
- /** The native-fetch socket shim is a separately compiled C++ translation unit.
171
- * It needs the same optional capability flags as the generated C object. */
172
- const UWS_CFLAGS_ANCHOR = " '-I', `${uwsDir}/uSockets/src`,\n";
173
- const UWS_CFLAGS_INJECT =
174
- " // SB_UWS_EXTRA_CFLAGS\n" +
175
- " ...(process.env.SB_EXTRA_CFLAGS ? process.env.SB_EXTRA_CFLAGS.split(' ').filter(Boolean) : []),\n";
176
- const UWS_CFLAGS_MARKER = "SB_UWS_EXTRA_CFLAGS";
177
-
178
170
  /**
179
171
  * #56 — make the inbound request-body limit configurable.
180
172
  *
@@ -424,10 +416,8 @@ const WRITE_RESPONSE_MARKER = "porf_native_fetch_read_raw_bytes(body_value";
424
416
  // #195: reserve a direct-transfer ticket before native-fetch allocates the
425
417
  // ordinary in-memory PendingRequest. uWS then gives each wire chunk directly
426
418
  // to the runtime C ABI, which owns the temporary object file.
427
- const R2_TRANSFER_ANCHOR =
428
- "static void on_request(uWS::HttpResponse<false>* res, uWS::HttpRequest* req) {\n";
429
- const R2_TRANSFER_INJECT = `#ifdef SB_R2_TRANSFER
430
- extern "C" {
419
+ const R2_TRANSFER_ANCHOR = "static void on_request(uWS::HttpResponse<false>* res, uWS::HttpRequest* req) {\n";
420
+ const R2_TRANSFER_INJECT = `extern "C" {
431
421
  struct sb_r2_transfer_ctx;
432
422
  int sb_r2_transfer_open(const char*, const char*, size_t, sb_r2_transfer_ctx**);
433
423
  int sb_r2_transfer_write(sb_r2_transfer_ctx*, const char*, size_t);
@@ -542,17 +532,13 @@ static bool try_handle_r2_transfer(uWS::HttpResponse<false>* res, uWS::HttpReque
542
532
  });
543
533
  return true;
544
534
  }
545
- #endif
546
535
  static void on_request(uWS::HttpResponse<false>* res, uWS::HttpRequest* req) {
547
536
  `;
548
537
  const R2_TRANSFER_MARKER = "sb_r2_transfer_path(std::string_view path";
549
- const R2_TRANSFER_CALL_ANCHOR =
550
- " __porffor_js_enter();\n const i32 url_ptr = alloc_request_url(req);";
538
+ const R2_TRANSFER_CALL_ANCHOR = " __porffor_js_enter();\n const i32 url_ptr = alloc_request_url(req);";
551
539
  const R2_TRANSFER_CALL_INJECT =
552
- "#ifdef SB_R2_TRANSFER\n if (try_handle_r2_transfer(res, req, method)) return;\n#endif\n" +
553
- R2_TRANSFER_CALL_ANCHOR;
540
+ " if (try_handle_r2_transfer(res, req, method)) return;\n" + R2_TRANSFER_CALL_ANCHOR;
554
541
  const R2_TRANSFER_CALL_MARKER = "try_handle_r2_transfer(res, req, method)";
555
- const R2_GATE_MARKER = "#ifdef SB_R2_TRANSFER";
556
542
  const R2_DOWNLOAD_CACHE_MARKER = "sb_r2_transfer_download_v1";
557
543
  const R2_RANGE_CACHE_MARKER = "sb_r2_transfer_range_v1";
558
544
  const R2_CONDITIONAL_CACHE_MARKER = "sb_r2_transfer_conditional_v1";
@@ -566,8 +552,7 @@ const R2_DOWNLOAD_DECL_INJECT =
566
552
  " const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);\n" +
567
553
  " size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx*, size_t, char*, size_t);\n" +
568
554
  " void sb_r2_transfer_download_close(sb_r2_transfer_ctx*);\n}";
569
- const R2_DOWNLOAD_BRANCH_ANCHOR =
570
- ' if (method != "PUT") { respond_with_error(res, "405 Method Not Allowed", "R2 transfer requires PUT", true); return true; }';
555
+ const R2_DOWNLOAD_BRANCH_ANCHOR = ' if (method != "PUT") { respond_with_error(res, "405 Method Not Allowed", "R2 transfer requires PUT", true); return true; }';
571
556
  const R2_DOWNLOAD_BRANCH_INJECT = ` // sb_r2_transfer_download_v1
572
557
  // sb_r2_transfer_range_v1
573
558
  // sb_r2_transfer_range_header_v2
@@ -660,18 +645,8 @@ const UWS_EDITS = [
660
645
  WRITE_RESPONSE_INJECT,
661
646
  "detect x-sb-raw-body, steer the body read (#176)",
662
647
  ],
663
- [
664
- R2_TRANSFER_MARKER,
665
- R2_TRANSFER_ANCHOR,
666
- R2_TRANSFER_INJECT,
667
- "native direct R2 transfer ingress (#195)",
668
- ],
669
- [
670
- R2_TRANSFER_CALL_MARKER,
671
- R2_TRANSFER_CALL_ANCHOR,
672
- R2_TRANSFER_CALL_INJECT,
673
- "direct R2 transfer dispatch (#195)",
674
- ],
648
+ [R2_TRANSFER_MARKER, R2_TRANSFER_ANCHOR, R2_TRANSFER_INJECT, "native direct R2 transfer ingress (#195)"],
649
+ [R2_TRANSFER_CALL_MARKER, R2_TRANSFER_CALL_ANCHOR, R2_TRANSFER_CALL_INJECT, "direct R2 transfer dispatch (#195)"],
675
650
  ] as const;
676
651
 
677
652
  /** The uWebSockets shim source: body limit + the #156 status-line fix. Exported for tests. */
@@ -679,41 +654,18 @@ export async function patchUwebsockets(root: string): Promise<void> {
679
654
  const file = resolve(root, "compiler/uwebsockets.js");
680
655
  let src = await readFile(file, "utf8");
681
656
  let changed = false;
682
- // Existing shared compiler caches already contain the direct-transfer patch.
683
- // Upgrade them in place so a cache built before #202 does not keep linking
684
- // the R2 path into every subsequent artifact.
685
- if (src.includes(R2_TRANSFER_MARKER) && !src.includes(R2_GATE_MARKER)) {
686
- const oldOpen = 'extern "C" {\n struct sb_r2_transfer_ctx;';
687
- const newOpen = '#ifdef SB_R2_TRANSFER\nextern "C" {\n struct sb_r2_transfer_ctx;';
688
- const oldClose = `}\n${R2_TRANSFER_ANCHOR}`;
689
- const newClose = `}\n#endif\n${R2_TRANSFER_ANCHOR}`;
690
- const oldCall =
691
- " if (try_handle_r2_transfer(res, req, method)) return;\n" + R2_TRANSFER_CALL_ANCHOR;
692
- if (!src.includes(oldOpen) || !src.includes(oldClose) || !src.includes(oldCall))
693
- throw new Error(
694
- `could not gate Porffor's direct R2 transfer bridge: anchor not found in ${file}.`,
695
- );
696
- src = src
697
- .replace(oldOpen, newOpen)
698
- .replace(oldClose, newClose)
699
- .replace(oldCall, R2_TRANSFER_CALL_INJECT);
700
- changed = true;
701
- }
702
657
  // Upgrade already-patched caches from the initial upload-only bridge. New
703
658
  // caches receive the full bridge below; old ones need declarations plus the
704
659
  // GET dispatch grafted onto their existing transfer handler.
705
660
  if (src.includes(R2_TRANSFER_MARKER) && !src.includes(R2_DOWNLOAD_CACHE_MARKER)) {
706
661
  if (!src.includes(R2_DOWNLOAD_DECL_ANCHOR) || !src.includes(R2_DOWNLOAD_BRANCH_ANCHOR))
707
- throw new Error(
708
- `could not upgrade Porffor's direct R2 transfer bridge: anchor not found in ${file}.`,
709
- );
662
+ throw new Error(`could not upgrade Porffor's direct R2 transfer bridge: anchor not found in ${file}.`);
710
663
  src = src.replace(R2_DOWNLOAD_DECL_ANCHOR, R2_DOWNLOAD_DECL_INJECT);
711
664
  src = src.replace(R2_DOWNLOAD_BRANCH_ANCHOR, R2_DOWNLOAD_BRANCH_INJECT);
712
665
  changed = true;
713
666
  }
714
667
  if (src.includes(R2_DOWNLOAD_CACHE_MARKER) && !src.includes(R2_RANGE_CACHE_MARKER)) {
715
- const stateAnchor =
716
- " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, sb_r2_transfer_download_size(download)});";
668
+ const stateAnchor = " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, sb_r2_transfer_download_size(download)});";
717
669
  const range = ` const uintmax_t full_size = sb_r2_transfer_download_size(download);
718
670
  uintmax_t first = 0, last = full_size ? full_size - 1 : 0;
719
671
  const std::string_view range = req->getHeader("range");
@@ -729,30 +681,18 @@ export async function patchUwebsockets(root: string): Promise<void> {
729
681
  res->writeStatus("206 Partial Content"); res->writeHeader("Content-Range", content_range);
730
682
  }
731
683
  `;
732
- const state =
733
- " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, first, last - first + 1});";
734
- if (!src.includes(stateAnchor))
735
- throw new Error(
736
- `could not upgrade Porffor's direct R2 range bridge: anchor not found in ${file}.`,
737
- );
738
- src = src.replace(
739
- " // sb_r2_transfer_download_v1\n",
740
- " // sb_r2_transfer_download_v1\n // sb_r2_transfer_range_v1\n",
741
- );
684
+ const state = " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, first, last - first + 1});";
685
+ if (!src.includes(stateAnchor)) throw new Error(`could not upgrade Porffor's direct R2 range bridge: anchor not found in ${file}.`);
686
+ src = src.replace(" // sb_r2_transfer_download_v1\n", " // sb_r2_transfer_download_v1\n // sb_r2_transfer_range_v1\n");
742
687
  src = src.replace(stateAnchor, range + state);
743
- src = src.replace(
744
- "sb_r2_transfer_download_read(state->ctx, (size_t)offset, chunk, sizeof(chunk))",
745
- "sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk))",
746
- );
688
+ src = src.replace("sb_r2_transfer_download_read(state->ctx, (size_t)offset, chunk, sizeof(chunk))", "sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk))");
747
689
  changed = true;
748
690
  }
749
691
  if (src.includes(R2_RANGE_CACHE_MARKER) && !src.includes(R2_CONDITIONAL_CACHE_MARKER)) {
750
692
  const declaration = " size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx*);\n";
751
- const declarationReplacement =
752
- declaration + " const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);\n";
693
+ const declarationReplacement = declaration + " const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);\n";
753
694
  const anchor = " const uintmax_t full_size = sb_r2_transfer_download_size(download);\n";
754
- const inject =
755
- ` // sb_r2_transfer_conditional_v1
695
+ const inject = ` // sb_r2_transfer_conditional_v1
756
696
  const std::string etag = sb_r2_transfer_download_etag(download);
757
697
  res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");
758
698
  const std::string_view if_none_match = req->getHeader("if-none-match");
@@ -760,10 +700,7 @@ export async function patchUwebsockets(root: string): Promise<void> {
760
700
  sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->end(); return true;
761
701
  }
762
702
  ` + anchor;
763
- if (!src.includes(declaration) || !src.includes(anchor))
764
- throw new Error(
765
- `could not upgrade Porffor's direct R2 conditional bridge: anchor not found in ${file}.`,
766
- );
703
+ if (!src.includes(declaration) || !src.includes(anchor)) throw new Error(`could not upgrade Porffor's direct R2 conditional bridge: anchor not found in ${file}.`);
767
704
  src = src.replace(declaration, declarationReplacement).replace(anchor, inject);
768
705
  changed = true;
769
706
  }
@@ -782,28 +719,15 @@ export async function patchUwebsockets(root: string): Promise<void> {
782
719
  if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
783
720
  if (!result.first) { res->onWritable([pump](uintmax_t) { return (*pump)(); }); return false; }
784
721
  }`;
785
- if (!src.includes(oldPump))
786
- throw new Error(
787
- `could not upgrade Porffor's direct R2 streaming bridge: anchor not found in ${file}.`,
788
- );
789
- src = src
790
- .replace(
791
- " // sb_r2_transfer_conditional_v1\n",
792
- " // sb_r2_transfer_conditional_v1\n // sb_r2_transfer_streaming_v2\n",
793
- )
794
- .replace(oldPump, newPump);
722
+ if (!src.includes(oldPump)) throw new Error(`could not upgrade Porffor's direct R2 streaming bridge: anchor not found in ${file}.`);
723
+ src = src.replace(" // sb_r2_transfer_conditional_v1\n", " // sb_r2_transfer_conditional_v1\n // sb_r2_transfer_streaming_v2\n").replace(oldPump, newPump);
795
724
  changed = true;
796
725
  }
797
726
  // A short-lived v2 cache marker was written before its pump fix. Repair
798
727
  // those caches as well as applying the current form to future upgrades.
799
- if (
800
- src.includes("state->base + offset") &&
801
- src.includes("uintmax_t size; bool closed = false;")
802
- ) {
803
- const oldState =
804
- "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };";
805
- const newState =
806
- "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; uintmax_t sent = 0; bool closed = false; };";
728
+ if (src.includes("state->base + offset") && src.includes("uintmax_t size; bool closed = false;")) {
729
+ const oldState = "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };";
730
+ const newState = "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; uintmax_t sent = 0; bool closed = false; };";
807
731
  const oldPump = ` const uintmax_t offset = res->getWriteOffset(); char chunk[65536];
808
732
  const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk));
809
733
  const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
@@ -817,10 +741,7 @@ export async function patchUwebsockets(root: string): Promise<void> {
817
741
  if (!result.first) { res->onWritable([pump, state](uintmax_t offset) { state->sent = offset; return (*pump)(); }); return false; }
818
742
  state->sent += bytes;
819
743
  }`;
820
- if (!src.includes(oldState) || !src.includes(oldPump))
821
- throw new Error(
822
- `could not repair Porffor's direct R2 streaming bridge: anchor not found in ${file}.`,
823
- );
744
+ if (!src.includes(oldState) || !src.includes(oldPump)) throw new Error(`could not repair Porffor's direct R2 streaming bridge: anchor not found in ${file}.`);
824
745
  src = src.replace(oldState, newState).replace(oldPump, newPump);
825
746
  changed = true;
826
747
  }
@@ -835,79 +756,37 @@ export async function patchUwebsockets(root: string): Promise<void> {
835
756
  changed = true;
836
757
  }
837
758
  if (src.includes(R2_STREAMING_CACHE_MARKER) && !src.includes(R2_RANGE_HEADER_CACHE_MARKER)) {
838
- const rangeHeader = ' const std::string_view range = req->getHeader("range");\n';
839
- if (!src.includes(rangeHeader))
840
- throw new Error(
841
- `could not upgrade Porffor's direct R2 range-header bridge: anchor not found in ${file}.`,
842
- );
843
- src = src.replace(
844
- " // sb_r2_transfer_range_v1\n",
845
- " // sb_r2_transfer_range_v1\n // sb_r2_transfer_range_header_v2\n",
846
- );
847
- src = src.replace(
848
- rangeHeader,
849
- ' std::string_view range = req->getHeader("range"); if (range.empty()) range = req->getHeader("Range");\n',
850
- );
759
+ const rangeHeader = " const std::string_view range = req->getHeader(\"range\");\n";
760
+ if (!src.includes(rangeHeader)) throw new Error(`could not upgrade Porffor's direct R2 range-header bridge: anchor not found in ${file}.`);
761
+ src = src.replace(" // sb_r2_transfer_range_v1\n", " // sb_r2_transfer_range_v1\n // sb_r2_transfer_range_header_v2\n");
762
+ src = src.replace(rangeHeader, " std::string_view range = req->getHeader(\"range\"); if (range.empty()) range = req->getHeader(\"Range\");\n");
851
763
  changed = true;
852
764
  }
853
- const earlyConditionalHeaders =
854
- ' res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");\n';
855
- if (
856
- src.includes(earlyConditionalHeaders) &&
857
- src.indexOf(earlyConditionalHeaders) <
858
- src.indexOf(" const uintmax_t full_size = sb_r2_transfer_download_size(download);")
859
- ) {
860
- const old304 =
861
- ' sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->end(); return true;';
862
- const new304 =
863
- ' sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->writeHeader("ETag", etag); res->end(); return true;';
864
- const rangeEnd =
865
- ' res->writeStatus("206 Partial Content"); res->writeHeader("Content-Range", content_range);\n }\n';
866
- if (!src.includes(old304) || !src.includes(rangeEnd))
867
- throw new Error(
868
- `could not repair Porffor's direct R2 response ordering: anchor not found in ${file}.`,
869
- );
870
- src = src
871
- .replace(earlyConditionalHeaders, "")
872
- .replace(old304, new304)
873
- .replace(
874
- rangeEnd,
875
- rangeEnd +
876
- ' res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");\n',
877
- );
765
+ const earlyConditionalHeaders = " res->writeHeader(\"ETag\", etag); res->writeHeader(\"Accept-Ranges\", \"bytes\");\n";
766
+ if (src.includes(earlyConditionalHeaders) && src.indexOf(earlyConditionalHeaders) < src.indexOf(" const uintmax_t full_size = sb_r2_transfer_download_size(download);")) {
767
+ const old304 = " sb_r2_transfer_download_close(download); res->writeStatus(\"304 Not Modified\"); res->end(); return true;";
768
+ const new304 = " sb_r2_transfer_download_close(download); res->writeStatus(\"304 Not Modified\"); res->writeHeader(\"ETag\", etag); res->end(); return true;";
769
+ const rangeEnd = " res->writeStatus(\"206 Partial Content\"); res->writeHeader(\"Content-Range\", content_range);\n }\n";
770
+ if (!src.includes(old304) || !src.includes(rangeEnd)) throw new Error(`could not repair Porffor's direct R2 response ordering: anchor not found in ${file}.`);
771
+ src = src.replace(earlyConditionalHeaders, "").replace(old304, new304).replace(rangeEnd, rangeEnd + " res->writeHeader(\"ETag\", etag); res->writeHeader(\"Accept-Ranges\", \"bytes\");\n");
878
772
  changed = true;
879
773
  }
880
774
  if (src.includes("state->sent") && src.includes(R2_DOWNLOAD_CACHE_MARKER)) {
881
775
  const stateStart = src.indexOf(" struct Download {", src.indexOf(R2_DOWNLOAD_CACHE_MARKER));
882
- const stateEnd = src.indexOf(' res->writeHeader("Content-Type"', stateStart);
776
+ const stateEnd = src.indexOf(" res->writeHeader(\"Content-Type\"", stateStart);
883
777
  const freshStart = R2_DOWNLOAD_BRANCH_INJECT.indexOf(" struct Download {");
884
- const freshEnd = R2_DOWNLOAD_BRANCH_INJECT.indexOf(
885
- ' res->writeHeader("Content-Type"',
886
- freshStart,
887
- );
888
- if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0)
889
- throw new Error(
890
- `could not replace Porffor's direct R2 stream pump: anchor not found in ${file}.`,
891
- );
892
- src =
893
- src.slice(0, stateStart) +
894
- R2_DOWNLOAD_BRANCH_INJECT.slice(freshStart, freshEnd) +
895
- src.slice(stateEnd);
778
+ const freshEnd = R2_DOWNLOAD_BRANCH_INJECT.indexOf(" res->writeHeader(\"Content-Type\"", freshStart);
779
+ if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0) throw new Error(`could not replace Porffor's direct R2 stream pump: anchor not found in ${file}.`);
780
+ src = src.slice(0, stateStart) + R2_DOWNLOAD_BRANCH_INJECT.slice(freshStart, freshEnd) + src.slice(stateEnd);
896
781
  changed = true;
897
782
  }
898
783
  if (src.includes("writable_offset") && src.includes(R2_DOWNLOAD_CACHE_MARKER)) {
899
784
  const stateStart = src.indexOf(" struct Download {", src.indexOf(R2_DOWNLOAD_CACHE_MARKER));
900
- const stateEnd = src.indexOf(' res->writeHeader("Content-Type"', stateStart);
785
+ const stateEnd = src.indexOf(" res->writeHeader(\"Content-Type\"", stateStart);
901
786
  const freshStart = R2_TRANSFER_INJECT.indexOf(" struct Download {");
902
- const freshEnd = R2_TRANSFER_INJECT.indexOf(' res->writeHeader("Content-Type"', freshStart);
903
- if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0)
904
- throw new Error(
905
- `could not restore Porffor's direct R2 stream pump: anchor not found in ${file}.`,
906
- );
907
- src =
908
- src.slice(0, stateStart) +
909
- R2_TRANSFER_INJECT.slice(freshStart, freshEnd) +
910
- src.slice(stateEnd);
787
+ const freshEnd = R2_TRANSFER_INJECT.indexOf(" res->writeHeader(\"Content-Type\"", freshStart);
788
+ if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0) throw new Error(`could not restore Porffor's direct R2 stream pump: anchor not found in ${file}.`);
789
+ src = src.slice(0, stateStart) + R2_TRANSFER_INJECT.slice(freshStart, freshEnd) + src.slice(stateEnd);
911
790
  changed = true;
912
791
  }
913
792
  for (const [marker, anchor, inject, what] of UWS_EDITS) {
@@ -924,14 +803,13 @@ export async function patchUwebsockets(root: string): Promise<void> {
924
803
  if (changed) await writeFile(file, src);
925
804
  }
926
805
 
927
- export async function patchCompilerArgs(root: string): Promise<void> {
806
+ async function patchCompilerArgs(root: string): Promise<void> {
928
807
  const file = resolve(root, "compiler/index.js");
929
808
  let src = await readFile(file, "utf8");
930
809
  let changed = false;
931
810
  for (const [marker, anchor, inject, what] of [
932
811
  [LINK_MARKER, LINK_ANCHOR, LINK_INJECT, "extra link args"],
933
812
  [CFLAGS_MARKER, CFLAGS_ANCHOR, CFLAGS_INJECT, "extra compiler flags"],
934
- [UWS_CFLAGS_MARKER, UWS_CFLAGS_ANCHOR, UWS_CFLAGS_INJECT, "native-fetch shim compiler flags"],
935
813
  ] as const) {
936
814
  if (src.includes(marker)) continue;
937
815
  const at = src.indexOf(anchor);
@@ -941,10 +819,10 @@ export async function patchCompilerArgs(root: string): Promise<void> {
941
819
  "Porffor's native-fetch build changed — check patches/UPSTREAM.md.",
942
820
  );
943
821
  }
944
- // After the anchor for compiler flags (the args follow it), before it for
945
- // the link line (the object list ends with it).
822
+ // After the anchor for cflags (the args follow it), before it for the link
823
+ // line (the object list ends with it).
946
824
  src =
947
- marker === CFLAGS_MARKER || marker === UWS_CFLAGS_MARKER
825
+ marker === CFLAGS_MARKER
948
826
  ? src.slice(0, at + anchor.length) + inject + src.slice(at + anchor.length)
949
827
  : src.slice(0, at) + inject + src.slice(at);
950
828
  changed = true;