@sproutboat/runtime 0.12.0 → 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 +9 -2
- package/package.json +1 -1
- package/src/native-fetch-prelude.js +9 -5
- package/test/native-crypto.ts +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @sproutboat/runtime
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ed9640a: Point Porffor patch diagnostics, runtime comments, and historical notes to the
|
|
8
|
+
shared upstream notes in the Sproutboat platform repository.
|
|
9
|
+
|
|
3
10
|
## 0.12.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
|
@@ -131,11 +138,11 @@
|
|
|
131
138
|
|
|
132
139
|
Verified end-to-end against both transports (kitchen-sink's full conformance suite, 24/24 standalone + 27/27 broker) and with new unit tests for file-backed persistence, the `:memory:` fallback, and a real binary round-trip over the v1 wire protocol.
|
|
133
140
|
|
|
134
|
-
**Known limitation found while verifying this, not fixed here:** a binary `put()` body (bytes ≥ 0x80) is corrupted on the way *in*, before it ever reaches storage
|
|
141
|
+
**Known limitation found while verifying this, not fixed here:** a binary `put()` body (bytes ≥ 0x80) is corrupted on the way *in*, before it ever reaches storage: `porf_native_fetch_read_value` (the function every inline-C string read in the runtime goes through) always UTF-8-encodes a Latin-1-range string on read, which is correct for genuine text but wrong for opaque bytes coming off a raw HTTP body. This predates this change (the old SQLite-blob path had the identical corruption) and is not something the storage backend can fix. It needs an input-side counterpart to `#176`'s `x-sb-raw-body` marker, or real `ArrayBuffer`/`Uint8Array` body support (the upstream ask was filed as Porffor #386 and later retracted; see `https://github.com/baronunread/sproutboat/blob/main/patches/upstream/request-body-report-386.md`).
|
|
135
142
|
|
|
136
143
|
### Patch Changes
|
|
137
144
|
|
|
138
|
-
- 188d8e4: Fix (baronunread/sproutboat#184): a `put()` body (R2, both transports) with bytes ≥ 0x80 was corrupted on the way *in*, before storage
|
|
145
|
+
- 188d8e4: Fix (baronunread/sproutboat#184): a `put()` body (R2, both transports) with bytes ≥ 0x80 was corrupted on the way *in*, before storage: `porf_native_fetch_read_value` (the one function every inline-C string read in the runtime funnels through) always UTF-8-encodes a Latin-1-range value, correct for genuine text, wrong for opaque bytes off a raw HTTP upload. A 256-byte binary upload landed as 384 stored bytes.
|
|
139
146
|
|
|
140
147
|
`__sbR2PutRaw` (embedded) and `__sbCallBin` (broker, the only caller that ever passes it a real body) now try `porf_native_fetch_read_raw_bytes` first, falling back to the normal encoding path only for a genuine multi-byte JS string (which isn't a "bytestring" and so isn't eligible for the raw read anyway). This predates the #56 storage change — the old SQLite-blob `put()` called the identical `read_value`, so it was equally corrupted; the existing R2 conformance check never caught it because it only ever exercises a plain ASCII string.
|
|
141
148
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Prepended to every handler by tools/compile.ts, before Porffor's native-fetch
|
|
2
|
-
//
|
|
2
|
+
// bundled handler. Porffor's runtime/fetch-globals.js (checked through alpha-4)
|
|
3
3
|
// gives URL (href/origin/pathname/search only) and Response without a static
|
|
4
4
|
// json(). This adds, additively, the rest of the WHATWG surface Worker code
|
|
5
5
|
// expects: URLSearchParams (read + write), URL.prototype.searchParams and the
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
// formData()/bytes() (#60). Each is feature-detected; delete a block once
|
|
10
10
|
// Porffor ships that global. crypto.scryptVerify (#153) is a Sproutboat
|
|
11
11
|
// extension, not WHATWG, and stays.
|
|
12
|
-
// Tracked upstream
|
|
12
|
+
// Tracked in the platform's upstream notes:
|
|
13
|
+
// https://github.com/baronunread/sproutboat/blob/main/patches/upstream/whatwg-fetch-globals.md
|
|
13
14
|
//
|
|
14
15
|
// Declared before it is referenced: a getter body that names a later top-level
|
|
15
|
-
// class throws ReferenceError in Porffor
|
|
16
|
+
// class throws ReferenceError in Porffor. See:
|
|
17
|
+
// https://github.com/baronunread/sproutboat/blob/main/patches/upstream/class-declaration-scope.md
|
|
16
18
|
|
|
17
19
|
// Duck-typing helpers, `typeof`-free (the repo's anti-slop lint bans `typeof`;
|
|
18
20
|
// these express the same spec-mandated checks and are verified under Porffor
|
|
@@ -386,7 +388,8 @@ if (!("bytes" in Response.prototype)) {
|
|
|
386
388
|
// Porffor's URL exposes href / origin / pathname / search only. Add the rest of
|
|
387
389
|
// the WHATWG read surface, derived from `origin` (scheme://host[:port]).
|
|
388
390
|
// `hash` is always '' server-side — browsers strip the fragment before the
|
|
389
|
-
// request, so there is nothing to recover.
|
|
391
|
+
// request, so there is nothing to recover. See:
|
|
392
|
+
// https://github.com/baronunread/sproutboat/blob/main/patches/upstream/whatwg-fetch-globals.md
|
|
390
393
|
function __sbDefineURLAccessor(name, get) {
|
|
391
394
|
if (!(name in URL.prototype)) Object.defineProperty(URL.prototype, name, { configurable: true, get });
|
|
392
395
|
}
|
|
@@ -1816,7 +1819,8 @@ function __sbTriggerAuthed(request) {
|
|
|
1816
1819
|
// #163 — the connection's remote address, for `request.cf.clientIp`.
|
|
1817
1820
|
//
|
|
1818
1821
|
// `x-sb-remote-addr` is the TCP peer, appended by the server (see
|
|
1819
|
-
// patches/
|
|
1822
|
+
// https://github.com/baronunread/sproutboat/blob/main/patches/upstream/remote-address.md)
|
|
1823
|
+
// and stripped from anything a client sends, so it
|
|
1820
1824
|
// cannot be forged. With no proxy in front, that is the client. Behind one, set
|
|
1821
1825
|
// `SB_TRUSTED_PROXIES` to a comma-separated list of trusted CIDRs (or bare IPs):
|
|
1822
1826
|
// when the peer is trusted, the client is the rightmost `x-forwarded-for` entry
|
package/test/native-crypto.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
|
-
import {
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
5
|
import { ensurePorffor } from "../../toolchain/src/acquire";
|
|
6
6
|
import { preludePath, TRANSPORT_MARKER, transportPath, wrapNativeFetchHandler } from "../src/wrap";
|
|
7
7
|
|
|
@@ -18,6 +18,7 @@ const expected = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const handler = `
|
|
21
|
+
import { keyBytes } from "./crypto-helper.js";
|
|
21
22
|
const hex = (buffer) => {
|
|
22
23
|
const bytes = new Uint8Array(buffer);
|
|
23
24
|
let out = "";
|
|
@@ -28,7 +29,7 @@ export default {
|
|
|
28
29
|
async fetch() {
|
|
29
30
|
const key = await crypto.subtle.importKey(
|
|
30
31
|
"raw",
|
|
31
|
-
|
|
32
|
+
keyBytes(),
|
|
32
33
|
{ name: "HMAC", hash: "SHA-256" },
|
|
33
34
|
false,
|
|
34
35
|
["sign"],
|
|
@@ -67,9 +68,8 @@ const workdir = await mkdtemp(join(tmpdir(), "sb-native-crypto-"));
|
|
|
67
68
|
let server: ReturnType<typeof Bun.spawn> | undefined;
|
|
68
69
|
try {
|
|
69
70
|
const porffor = await ensurePorffor({ cacheRoot: workdir });
|
|
70
|
-
const esbuild = Bun.which("esbuild");
|
|
71
71
|
const node = Bun.which("node");
|
|
72
|
-
if (!
|
|
72
|
+
if (!node) throw new Error("native crypto test needs node on PATH");
|
|
73
73
|
|
|
74
74
|
const [core, broker] = await Promise.all([
|
|
75
75
|
readFile(preludePath, "utf8"),
|
|
@@ -79,12 +79,15 @@ try {
|
|
|
79
79
|
const prelude = core.replace(TRANSPORT_MARKER, broker);
|
|
80
80
|
const generated = join(workdir, "crypto.generated.js");
|
|
81
81
|
const binary = join(workdir, "crypto-native");
|
|
82
|
+
// This is a direct ESM import into Porffor, with no bundler in front of it.
|
|
83
|
+
await writeFile(join(workdir, "crypto-helper.js"),
|
|
84
|
+
"export const keyBytes = () => Uint8Array.from({ length: 16 }, (_, index) => index + 1);\n");
|
|
82
85
|
await writeFile(generated, wrapNativeFetchHandler(handler, prelude));
|
|
83
86
|
await rm(binary, { force: true });
|
|
84
87
|
|
|
85
88
|
const compile = Bun.spawn([node, resolve(porffor, "runtime/index.js"), "native", generated, "-o", binary, "-s", "-O0"], {
|
|
86
89
|
cwd: workdir,
|
|
87
|
-
env:
|
|
90
|
+
env: process.env,
|
|
88
91
|
stdout: "pipe",
|
|
89
92
|
stderr: "pipe",
|
|
90
93
|
});
|