Public: anyone can read this; the crew can change it.

Ship and close from the inbox and the feed land back on the same page with a one-line flash #1766

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Ship and close now return to the page they were taken from, with a flash like "Shipped #N · see it live" carrying one link. `test/studio.test.ts` and the asks tests pass. The type check couldn't run here: `tsc` fails with "Cannot find type definition file for 'bun'", even after `bun install`.

shipped production is serving it deploy eb43263

opened this

Ship and close now return to the page they were taken from, with a flash like "Shipped #N · see it live" carrying one link. test/studio.test.ts and the asks tests pass. The type check couldn't run here: tsc fails with "Cannot find type definition file for 'bun'", even after bun install.

What changed

  • back field: POST …/pulls/:number/ship and POST …/pulls/:number/state read a back field. It is accepted only if it is a same-origin path: one leading /, no //, no backslash, no control bytes, at most 512 characters. Anything else, such as https://evil.example/, falls back to the pull page. The check is isLocalPath in src/web/flash.ts, used through backTo in src/web/form.ts.
  • Pull page unchanged in intent: the pull page's forms send no back, so they redirect to that pull's page, /changes/N in studio mode. A bare ship used to redirect to the repo page, so that fallback moved to the pull page. The "stay on the pull page" line in the issue is why.
  • Ship flash: a successful ship now says "Shipped #N · see it live". The link goes to <repo>/app/production/open. This needed a small addition: Flash gets an optional link, which is re-validated as a local path when the flash is read and rendered in the toast.
  • Inbox forms: the inbox's Ship and Close forms carry back as the current page's path. This is decisionForm(d, back) in asks.ts, called from asks_page.ts.
  • Issues also honor back: stateSubmit is shared with issues, so an issue's close and reopen honor back too. Nothing sends it yet.
  • Tests: both are in test/studio.test.ts. Ship from the home with back=/ returns to / with the flash and link. A back of https://evil.example/ lands on the pull page. Close from the home returns to / and closes the pull.

Left out

  • I found no ship or close form in the feed, so I added no back there. The routes accept back from the feed as soon as it sends one.
  • Not touched, as the issue says: the say, review-state and asks' decide routes, and in-place fragment re-render.

Try it: open the home with a green change waiting, press Ship, and you land on / with the toast and the "see it live" link.

🤖 Generated with Claude Code

Closes #1567

commented

Ship and close from the home inbox now return to the page they were taken from, with a one-line flash. A successful ship says "Shipped #N · see it live" and carries one link. The type check and test/studio.test.ts (178 tests) pass locally; the check on the last push failed with a type error, which this push fixes.

What changed

  • back field: POST …/pulls/:number/ship and …/state read a back field. It is used only if it is a same-origin path. Anything else, such as https://evil.example/, falls back to the pull page. The validator is isLocalPath in src/web/flash.ts, used through backTo in src/web/form.ts.
  • Pull page: its forms send no back, so they land on that pull's page (/changes/N in studio mode).
  • Ship fallback moved: a bare ship used to redirect to the repo page. It now redirects to the pull page, which is what "stay on the pull page" asks for.
  • Flash link: Flash gets an optional link that points at <repo>/app/production/open. It is checked as a local path again when the flash is read, and the toast shows it.
  • Inbox forms: the inbox's Ship and Close forms (decisionForm in src/web/studio/asks.ts) now send the current page's path as back.
  • Type fix: under exactOptionalPropertyTypes, linkOf in src/web/flash.ts returned a type that allowed undefined for link. It now returns NonNullable<Flash["link"]>.
  • Tests: three, in test/studio.test.ts. Ship from the home returns to / with the flash and link. A back of https://evil.example/ lands on the pull page. Close from the home returns to / and closes the pull.

Left out

  • Feed: I found no ship or close form there, so it sends no back yet. The routes honor back as soon as it does.
  • Issue close: stateSubmit is shared with issues, so an issue's close and reopen also honor back. Nothing sends it yet.
  • Not touched: the say, review-state and asks' decide routes, and in-place fragment re-render, as the issue says.

Try it: open the home with a green change waiting and press Ship. You land on / with the toast and the "see it live" link.

🤖 Generated with Claude Code

Approved

Ship and close from the home inbox now land back on the page they came from. The flash is one line with one "see it live" link. back is accepted only as a local path, checked again when the flash cookie is read, and the tests cover the foreign-URL fallback. I could not open the preview (the sandbox blocked the host) and did not look at the screenshots, so this is a read of the source and diff only. Next: (1) the title names the feed, but no feed form sends back yet; add it where the feed offers ship or close, or open an issue. (2) back is ctx.url.pathname, so it drops any query string such as a filter the owner set. Carry the query too, still validated by isLocalPath.

commented

The full gate on land was red and named no test; the pull is open again.

commented

The full gate on land was red and named no test; the pull is open again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs