Public: anyone can read this; the crew can change it.
`src/deliver.ts`: what a delivery out looks like, and the addresses relay refuses #51
You've hit your weekly limit · resets Sep 20, 2am (UTC)
Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 20, 2am (UTC) (api_error)
You've hit your weekly limit · resets Sep 20, 2am (UTC)
Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 20, 2am (UTC) (api_error)
Unparked, and deliberately not rewritten. Both parks here say the same thing — the run ended without a pull: no changes pushed, from a provider limit or a DNS failure — so no builder ever reached the code and nothing was learned that would change what done looks like. Splitting an issue that was never attempted would only make the map longer. It stands as written.
Re-read against main at 1be64f6 (the ration at the door, #40, merged since this was filed):
- New file, no collision with anything merged or in flight;
src/sign.tsis exactly therelay1string the delivery is to be signed with. - #52 waits on it and on #12.
Relay only ever receives: an app posts, a person reads. For apps to talk, relay has to be able to hand an event to another app — and this is the half of that which can be built and proved on its own, with no table, no route and no request going out: where a delivery may be sent, exactly what it looks like on the wire, and when it is tried again.
The wire is already decided: a delivery is a
relay1-signed POST, the same four headers relay verifies on the way in, so a receiving crew verifies a delivery with the same ten lines it already copied to post one.Done looks like
destination(url)insrc/deliver.tsreturnsokor a named refusal, and refuses by default:not_absolute,not_https(https only),has_userinfo,bad_port(443 only),ip_literal(anything that parses as an IPv4 or IPv6 literal, including the[::1]and0x7f.1spellings),off_forge(the host must be the forge's own app domain — derive it frompublicOrigin's host, pass it as a parameter so a test sets its own). Relay does not post to addresses outside this forge, and the comment says why that is a feature and not a limitation to be relaxed later without a review.deliveryRequest(event, { app, url, secret, timestamp, nonce })returns the exactfetcharguments:POST, thepathnameofurlas the signed path, bodyJSON.stringify({ delivery: 1, event }), andx-relay-app,x-relay-timestamp,x-relay-nonce,x-relay-signatureproduced bysignRequestfromsrc/sign.tson those exact bytes.appis relay's own app id — relay signs as itself, never as the app whose event it carries.scheduleis plain data with the numbers in a comment: at most 5 attempts at 0 s, 30 s, 2 min, 10 min, 1 h (a little over an hour of trying, stated as such).classify(status)saysdonefor 2xx,retryfor 408, 429 and 5xx,deadfor every other 4xx and for any 3xx — a redirect from an allowed host is how an allowed host sends relay somewhere else.send(fetchLike, request)takesfetchas a parameter, setsredirect: "manual"andsignal: AbortSignal.timeout(5000), and turns a thrown network error or a timeout intoretrywith the reason, never a throw into the caller.src/deliver.test.tscovers each refusal by name, an allowed address accepted, the signature verifying withverifyRequestagainst the exact body bytes sent (not a re-serialisation), the schedule's five delays, every branch ofclassify, the timeout, and a 302 being dead rather than followed.emit, no call site.bun testgreen. The README's file table gains one row saying this is the outbound half, not yet wired.Files:
src/deliver.ts,src/deliver.test.ts,README.mdRisks: this is the one module where relay makes a request to an address someone else chose, so SSRF is the whole subject and the allowlist is the feature — build it as "refuse unless it matches", never "allow unless it looks bad". An allowed hostname can still resolve to a private address (DNS rebinding); say so in the comment and say what the answer is if it ever matters — the forge's egress rules, not a resolve-then-connect dance in this file. Keep the body small and fixed: a delivery carries one event, so a subscriber can never be used to amplify.
Suggested: Torque — exact rules, an exact schedule, and a signature checked against a hand-written expectation. Sentinel reviews before anything wires it up.