Repository: remix-run/remix
Pull request #4881 (2022-12-15 18:51:26)

ci(release): make commenting work for changeset releases
Signed-off-by: Logan McAnsh <logan@mcan.sh>

<!--

👋 Hey, thanks for your interest in contributing to Remix!

If this is a simple docs change, go ahead and delete all this.

**Please ask first before starting work on any significant new features.**

It's never a fun experience to have your pull request declined after investing a
lot of time and effort into a new feature. To avoid this from happening, we
request that contributors create a
[Feature Request discussion](https://github.com/remix-run/remix/discussions/new?category=ideas)
to first discuss any significant new features.

https://github.com/remix-run/remix/blob/main/CONTRIBUTING.md

Please fill in or delete each item below:

-->

Closes: #

- [ ] Docs
- [ ] Tests

Testing Strategy:

<!--
Please explain how you tested this. For example:

> This test covers this code: <link to test>

Or

> I opened up my windows machine and ran this script:
>
> ```
> npx create-remix@0.0.0-experimental-7e420ee3 --template remix my-test
> cd my-test
> npm run dev
> ```
-->


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: b66ffad044dece5460423c97ff38528f6b7d7126

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/remix-run/remix/new/logan/remove-postrelease-workflow?filename=.changeset/witty-colts-teach.md&value=---%0A%0A---%0A%0Aci(release)%3A%20parse%20changesets%20publishedPackages%20for%20new%20remix%20version%E2%80%A6%0A)



Patch:
diff --git a/.github/workflows/postrelease.yml b/.github/workflows/postrelease.yml
deleted file mode 100644
index dcd1168a1..000000000
--- a/.github/workflows/postrelease.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: 🕊 Post-release
-
-on:
-  push:
-    tags:
-      # only run on `remix` tags
-      - remix@**
-
-jobs:
-  comment:
-    name: 📝 Comment on related issues and pull requests
-    if: github.repository == 'remix-run/remix'
-    uses: remix-run/remix/.github/workflows/release-comments.yml@main
-    with:
-      ref: ${{ github.ref }}
-      # this should match the above tag to watch excluding the trailing "@"
-      packageVersionToFollow: "remix"
-
-  deployments:
-    name: 🚀 Deployment Tests
-    if: github.repository == 'remix-run/remix'
-    uses: remix-run/remix/.github/workflows/deployments.yml@main
-    secrets:
-      TEST_AWS_ACCESS_KEY_ID: ${{ secrets.TEST_AWS_ACCESS_KEY_ID }}
-      TEST_AWS_SECRET_ACCESS_KEY: ${{ secrets.TEST_AWS_SECRET_ACCESS_KEY }}
-      TEST_CF_ACCOUNT_ID: ${{ secrets.TEST_CF_ACCOUNT_ID }}
-      TEST_CF_GLOBAL_API_KEY: ${{ secrets.TEST_CF_GLOBAL_API_KEY }}
-      TEST_CF_EMAIL: ${{ secrets.TEST_CF_EMAIL }}
-      TEST_CF_PAGES_API_TOKEN: ${{ secrets.TEST_CF_PAGES_API_TOKEN }}
-      TEST_CF_API_TOKEN: ${{ secrets.TEST_CF_API_TOKEN }}
-      TEST_DENO_DEPLOY_TOKEN: ${{ secrets.TEST_DENO_DEPLOY_TOKEN }}
-      TEST_FLY_TOKEN: ${{ secrets.TEST_FLY_TOKEN }}
-      TEST_NETLIFY_TOKEN: ${{ secrets.TEST_NETLIFY_TOKEN }}
-      TEST_VERCEL_TOKEN: ${{ secrets.TEST_VERCEL_TOKEN }}
-      TEST_VERCEL_USER_ID: ${{ secrets.TEST_VERCEL_USER_ID }}
-
-  stacks:
-    name: 🥞 Remix Stacks Test
-    if: github.repository == 'remix-run/remix'
-    uses: remix-run/remix/.github/workflows/stacks.yml@main
-    with:
-      version: ${{ github.ref_name }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 46425923b..bb479cc9a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -20,6 +20,9 @@ jobs:
       github.repository == 'remix-run/remix' &&
       !contains(github.ref, 'nightly')
     runs-on: ubuntu-latest
+    outputs:
+      publishedPackages: ${{ steps.changesets.outputs.publishedPackages }}
+      published: ${{ steps.changesets.outputs.published }}
     steps:
       - name: 🛑 Cancel Previous Runs
         uses: styfle/cancel-workflow-action@0.11.0
@@ -61,3 +64,67 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ secrets.NIGHTLY_PAT }}
           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+
+  findPackage:
+    name: 🦋 Find Package
+    needs: [release]
+    runs-on: ubuntu-latest
+    if: github.repository == 'remix-run/remix' && needs.release.outputs.published == 'true'
+    outputs:
+      package: ${{ steps.findPackage.outputs.package }}
+    steps:
+      - name: 🛑 Cancel Previous Runs
+        uses: styfle/cancel-workflow-action@0.11.0
+
+      - name: ⬇️ Checkout repo
+        uses: actions/checkout@v3
+
+      - name: ⎔ Setup node
+        uses: actions/setup-node@v3
+        with:
+          node-version: 16
+          cache: "npm"
+
+      - id: findPackage
+        run: |
+          package=$(node ./scripts/release/find-release-from-changeset.js)
+          echo "package=${package}" >> $GITHUB_OUTPUT
+        env:
+          packageVersionToFollow: "remix"
+          publishedPackages: ${{ needs.release.outputs.publishedPackages }}
+
+  comment:
+    name: 📝 Comment on related issues and pull requests
+    if: github.repository == 'remix-run/remix' && needs.findPackage.outputs.package != ''
+    needs: [release, findPackage]
+    uses: ./.github/workflows/release-comments.yml
+    with:
+      ref: refs/tags/${{ needs.findPackage.outputs.package }}
+      packageVersionToFollow: "remix"
+
+  deployments:
+    name: 🚀 Deployment Tests
+    if: github.repository == 'remix-run/remix'
+    needs: [release, findPackage]
+    uses: ./.github/workflows/deployments.yml
+    secrets:
+      TEST_AWS_ACCESS_KEY_ID: ${{ secrets.TEST_AWS_ACCESS_KEY_ID }}
+      TEST_AWS_SECRET_ACCESS_KEY: ${{ secrets.TEST_AWS_SECRET_ACCESS_KEY }}
+      TEST_CF_ACCOUNT_ID: ${{ secrets.TEST_CF_ACCOUNT_ID }}
+      TEST_CF_GLOBAL_API_KEY: ${{ secrets.TEST_CF_GLOBAL_API_KEY }}
+      TEST_CF_EMAIL: ${{ secrets.TEST_CF_EMAIL }}
+      TEST_CF_PAGES_API_TOKEN: ${{ secrets.TEST_CF_PAGES_API_TOKEN }}
+      TEST_CF_API_TOKEN: ${{ secrets.TEST_CF_API_TOKEN }}
+      TEST_DENO_DEPLOY_TOKEN: ${{ secrets.TEST_DENO_DEPLOY_TOKEN }}
+      TEST_FLY_TOKEN: ${{ secrets.TEST_FLY_TOKEN }}
+      TEST_NETLIFY_TOKEN: ${{ secrets.TEST_NETLIFY_TOKEN }}
+      TEST_VERCEL_TOKEN: ${{ secrets.TEST_VERCEL_TOKEN }}
+      TEST_VERCEL_USER_ID: ${{ secrets.TEST_VERCEL_USER_ID }}
+
+  stacks:
+    name: 🥞 Remix Stacks Test
+    if: github.repository == 'remix-run/remix'
+    needs: [release, findPackage]
+    uses: ./.github/workflows/stacks.yml
+    with:
+      version: ${{ needs.findPackage.outputs.package }}
diff --git a/README.md b/README.md
index fee71ad0f..2ecd384fa 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 We are happy you're here!
 
-[Remix](https://remix.run/) is a full stack web framework that lets you focus on the user interface and work back through web fundamentals to deliver a fast, slick, and resilient user experience that deploys to any Node.js server and even non-Node.js environments at the edge like Cloudflare Workers.
+[Remix](https://remix.run) is a full stack web framework that lets you focus on the user interface and work back through web fundamentals to deliver a fast, slick, and resilient user experience that deploys to any Node.js server and even non-Node.js environments at the edge like Cloudflare Workers.
 
 Want to know more? Read the [Technical Explanation of Remix](https://remix.run/pages/technical-explanation)
 
diff --git a/contributors.yml b/contributors.yml
index ac41aabb7..3534a70a2 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -162,6 +162,7 @@
 - hicksy
 - himorishige
 - hkan
+- hokaccha
 - Holben888
 - hollandThomas
 - Hopsken
diff --git a/packages/remix-deno/README.md b/packages/remix-deno/README.md
index a8877461c..5fe16dbcd 100644
--- a/packages/remix-deno/README.md
+++ b/packages/remix-deno/README.md
@@ -2,7 +2,7 @@
 
 This package contains a Deno module that provides abstractions for Remix.
 
-For more, see the [Remix docs](https://remix.run/docs/).
+For more, see the [Remix docs](https://remix.run/docs).
 
 ## Install
 
diff --git a/packages/remix-node/sessions/fileStorage.ts b/packages/remix-node/sessions/fileStorage.ts
index cdb7cf74c..bc03da253 100644
--- a/packages/remix-node/sessions/fileStorage.ts
+++ b/packages/remix-node/sessions/fileStorage.ts
@@ -27,7 +27,7 @@ interface FileSessionStorageOptions {
  * The advantage of using this instead of cookie session storage is that
  * files may contain much more data than cookies.
  *
- * @see https://remix.run/api/remix#createfilesessionstorage-node
+ * @see https://remix.run/utils/sessions#createfilesessionstorage-node
  */
 export function createFileSessionStorage({
   cookie,
diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx
index 45e4a9efc..0fd5eb685 100644
--- a/packages/remix-react/components.tsx
+++ b/packages/remix-react/components.tsx
@@ -469,7 +469,7 @@ function usePrefetchBehavior(
 /**
  * A special kind of `<Link>` that knows whether or not it is "active".
  *
- * @see https://remix.run/api/remix#navlink
+ * @see https://remix.run/components/nav-link
  */
 let NavLink = React.forwardRef<HTMLAnchorElement, RemixNavLinkProps>(
   ({ to, prefetch = "none", ...props }, forwardedRef) => {
@@ -497,7 +497,7 @@ export { NavLink };
  * This component renders an anchor tag and is the primary way the user will
  * navigate around your website.
  *
- * @see https://remix.run/api/remix#link
+ * @see https://remix.run/components/link
  */
 let Link = React.forwardRef<HTMLAnchorElement, RemixLinkProps>(
   ({ to, prefetch = "none", ...props }, forwardedRef) => {
@@ -539,7 +539,7 @@ export function composeEventHandlers<
 /**
  * Renders the `<link>` tags for the current routes.
  *
- * @see https://remix.run/api/remix#meta-links-scripts
+ * @see https://remix.run/components/links
  */
 export function Links() {
   let { matches, routeModules, manifest } = useRemixEntryContext();
@@ -602,7 +602,7 @@ export function Links() {
  *
  * @param props
  * @param props.page
- * @see https://remix.run/api/remix#prefetchpagelinks-
+ * @see https://remix.run/components/prefetch-page-links
  */
 export function PrefetchPageLinks({
   page,
@@ -698,7 +698,7 @@ function PrefetchPageLinksImpl({
 /**
  * Renders the `<title>` and `<meta>` tags for the current routes.
  *
- * @see https://remix.run/api/remix#meta-links-scripts
+ * @see https://remix.run/components/meta
  */
 function V1Meta() {
   let { matches, routeData, routeModules } = useRemixEntryContext();
@@ -732,9 +732,9 @@ function V1Meta() {
             " returns an array. This is only supported with the `v2_meta` future flag " +
             "in the Remix config. Either set the flag to `true` or update the route's " +
             "meta function to return an object." +
-            "\n\nTo reference the v1 meta function API, see https://remix.run/api/conventions#meta"
+            "\n\nTo reference the v1 meta function API, see https://remix.run/route/meta"
           // TODO: Add link to the docs once they are written
-          // + "\n\nTo reference future flags and the v2 meta API, see https://remix.run/api/remix#future-v2-meta."
+          // + "\n\nTo reference future flags and the v2 meta API, see https://remix.run/file-conventions/remix-config#future-v2-meta."
         );
       }
       Object.assign(meta, routeMeta);
@@ -842,8 +842,8 @@ function V2Meta() {
           " returns an invalid value. In v2, all route meta functions must " +
           "return an array of meta objects." +
           // TODO: Add link to the docs once they are written
-          // "\n\nTo reference future flags and the v2 meta API, see https://remix.run/api/remix#future-v2-meta." +
-          "\n\nTo reference the v1 meta function API, see https://remix.run/api/conventions#meta"
+          // "\n\nTo reference future flags and the v2 meta API, see https://remix.run/file-conventions/remix-config#future-v2-meta." +
+          "\n\nTo reference the v1 meta function API, see https://remix.run/route/meta"
       );
     }
 
@@ -910,7 +910,7 @@ type ScriptProps = Omit<
  * In addition to scripts, \<link rel="modulepreload"> tags receive the crossOrigin
  * property if provided.
  *
- * @see https://remix.run/api/remix#meta-links-scripts
+ * @see https://remix.run/components/scripts
  */
 export function Scripts(props: ScriptProps) {
   let {
@@ -1066,7 +1066,7 @@ export interface FormProps extends FormHTMLAttributes<HTMLFormElement> {
  * requests, allowing components to add nicer UX to the page as the form is
  * submitted and returns with data.
  *
- * @see https://remix.run/api/remix#form
+ * @see https://remix.run/components/form
  */
 let Form = React.forwardRef<HTMLFormElement, FormProps>((props, ref) => {
   return <FormImpl {...props} ref={ref} />;
@@ -1142,7 +1142,7 @@ type HTMLFormSubmitter = HTMLButtonElement | HTMLInputElement;
 /**
  * Resolves a `<form action>` path relative to the current route.
  *
- * @see https://remix.run/api/remix#useformaction
+ * @see https://remix.run/hooks/use-form-action
  */
 export function useFormAction(
   action?: string,
@@ -1246,7 +1246,7 @@ export interface SubmitFunction {
  * Returns a function that may be used to programmatically submit a form (or
  * some arbitrary data) to the server.
  *
- * @see https://remix.run/api/remix#usesubmit
+ * @see https://remix.run/hooks/use-submit
  */
 export function useSubmit(): SubmitFunction {
   return useSubmitImpl();
@@ -1444,7 +1444,7 @@ function isInputElement(object: any): object is HTMLInputElement {
  * Note: The `callback` argument should be a function created with
  * `React.useCallback()`.
  *
- * @see https://remix.run/api/remix#usebeforeunload
+ * @see https://remix.run/hooks/use-before-unload
  */
 export function useBeforeUnload(
   callback: (event: BeforeUnloadEvent) => any
@@ -1469,7 +1469,7 @@ export interface RouteMatch {
   /**
    * The dynamic parameters of the matched route
    *
-   * @see https://remix.run/docs/api/conventions#dynamic-route-parameters
+   * @see https://remix.run/file-conventions/routes-files#dynamic-route-parameters
    */
   params: Params<string>;
   /**
@@ -1479,7 +1479,7 @@ export interface RouteMatch {
   /**
    * The exported `handle` object of the matched route.
    *
-   * @see https://remix.run/docs/api/conventions#handle
+   * @see https://remix.run/route/handle
    */
   handle: undefined | { [key: string]: any };
 }
@@ -1488,7 +1488,7 @@ export interface RouteMatch {
  * Returns the current route matches on the page. This is useful for creating
  * layout abstractions with your current routes.
  *
- * @see https://remix.run/api/remix#usematches
+ * @see https://remix.run/hooks/use-matches
  */
 export function useMatches(): RouteMatch[] {
   let { matches, routeData, routeModules } = useRemixEntryContext();
@@ -1514,7 +1514,7 @@ export function useMatches(): RouteMatch[] {
 /**
  * Returns the JSON parsed data from the current route's `loader`.
  *
- * @see https://remix.run/api/remix#useloaderdata
+ * @see https://remix.run/hooks/use-loader-data
  */
 export function useLoaderData<T = AppData>(): SerializeFrom<T> {
   return useRemixRouteContext().data;
@@ -1523,7 +1523,7 @@ export function useLoaderData<T = AppData>(): SerializeFrom<T> {
 /**
  * Returns the JSON parsed data from the current route's `action`.
  *
- * @see https://remix.run/api/remix#useactiondata
+ * @see https://remix.run/hooks/use-action-data
  */
 export function useActionData<T = AppData>(): SerializeFrom<T> | undefined {
   let { id: routeId } = useRemixRouteContext();
@@ -1536,7 +1536,7 @@ export function useActionData<T = AppData>(): SerializeFrom<T> | undefined {
  * Returns everything you need to know about a page transition to build pending
  * navigation indicators and optimistic UI on data mutations.
  *
- * @see https://remix.run/api/remix#usetransition
+ * @see https://remix.run/hooks/use-transition
  */
 export function useTransition(): Transition {
   let { transitionManager } = useRemixEntryContext();
@@ -1568,7 +1568,7 @@ export type FetcherWithComponents<TData> = Fetcher<TData> & {
  * Interacts with route loaders and actions without causing a navigation. Great
  * for any interaction that stays on the same page.
  *
- * @see https://remix.run/api/remix#usefetcher
+ * @see https://remix.run/hooks/use-fetcher
  */
 export function useFetcher<TData = any>(): FetcherWithComponents<
   SerializeFrom<TData>
@@ -1608,7 +1608,7 @@ export function useFetcher<TData = any>(): FetcherWithComponents<
  * Provides all fetchers currently on the page. Useful for layouts and parent
  * routes that need to provide pending/optimistic UI regarding the fetch.
  *
- * @see https://remix.run/api/remix#usefetchers
+ * @see https://remix.run/hooks/use-fetchers
  */
 export function useFetchers(): Fetcher[] {
   let { transitionManager } = useRemixEntryContext();
diff --git a/packages/remix-react/errorBoundaries.tsx b/packages/remix-react/errorBoundaries.tsx
index 81a905bc0..860e84757 100644
--- a/packages/remix-react/errorBoundaries.tsx
+++ b/packages/remix-react/errorBoundaries.tsx
@@ -117,7 +117,7 @@ let RemixCatchContext = React.createContext<ThrownResponse | undefined>(
 /**
  * Returns the status code and thrown response data.
  *
- * @see https://remix.run/api/conventions#catchboundary
+ * @see https://remix.run/route/catch-boundary
  */
 export function useCatch<
   Result extends ThrownResponse = ThrownResponse
diff --git a/packages/remix-react/routeModules.ts b/packages/remix-react/routeModules.ts
index 88ae3254e..7a9972a0f 100644
--- a/packages/remix-react/routeModules.ts
+++ b/packages/remix-react/routeModules.ts
@@ -32,14 +32,14 @@ export interface RouteModule {
 /**
  * A React component that is rendered when the server throws a Response.
  *
- * @see https://remix.run/api/conventions#catchboundary
+ * @see https://remix.run/route/catch-boundary
  */
 export type CatchBoundaryComponent = ComponentType<{}>;
 
 /**
  * A React component that is rendered when there is an error on a route.
  *
- * @see https://remix.run/api/conventions#errorboundary
+ * @see https://remix.run/route/error-boundary
  */
 export type ErrorBoundaryComponent = ComponentType<{ error: Error }>;
 
@@ -47,7 +47,7 @@ export type ErrorBoundaryComponent = ComponentType<{ error: Error }>;
  * A function that defines `<link>` tags to be inserted into the `<head>` of
  * the document on route transitions.
  *
- * @see https://remix.run/api/remix#meta-links-scripts
+ * @see https://remix.run/route/meta
  */
 export interface LinksFunction {
   (): LinkDescriptor[];
@@ -58,7 +58,7 @@ export interface LinksFunction {
  * `<meta>` tags for a route. These tags will be merged with (and take
  * precedence over) tags from parent routes.
  *
- * @see https://remix.run/api/remix#meta-links-scripts
+ * @see https://remix.run/route/meta
  */
 export interface V1_MetaFunction {
   (args: {
@@ -126,7 +126,7 @@ export type V2_HtmlMetaDescriptor =
  * environment variables: after form submissions the root probably doesn't need
  * to be reloaded.
  *
- * @see https://remix.run/api/conventions#unstable_shouldreload
+ * @see https://remix.run/route/should-reload
  */
 export interface ShouldReloadFunction {
   (args: {
@@ -145,7 +145,7 @@ export type RouteComponent = ComponentType<{}>;
 /**
  * An arbitrary object that is associated with a route.
  *
- * @see https://remix.run/api/conventions#handle
+ * @see https://remix.run/route/handle
  */
 export type RouteHandle = any;
 
diff --git a/packages/remix-react/scroll-restoration.tsx b/packages/remix-react/scroll-restoration.tsx
index b517b4362..5deafde98 100644
--- a/packages/remix-react/scroll-restoration.tsx
+++ b/packages/remix-react/scroll-restoration.tsx
@@ -18,7 +18,7 @@ if (typeof document !== "undefined") {
  * This component will emulate the browser's scroll restoration on location
  * changes.
  *
- * @see https://remix.run/api/remix#scrollrestoration
+ * @see https://remix.run/components/scroll-restoration
  */
 export function ScrollRestoration({ nonce = undefined }: { nonce?: string }) {
   useScrollRestoration();
diff --git a/packages/remix-server-runtime/cookies.ts b/packages/remix-server-runtime/cookies.ts
index b002f0423..806b6dc39 100644
--- a/packages/remix-server-runtime/cookies.ts
+++ b/packages/remix-server-runtime/cookies.ts
@@ -30,7 +30,7 @@ export type CookieOptions = CookieParseOptions &
  * `serialize()` methods that allow a single instance to be reused for
  * parsing/encoding multiple different values.
  *
- * @see https://remix.run/api/remix#cookie-api
+ * @see https://remix.run/utils/cookies#cookie-api
  */
 export interface Cookie {
   /**
@@ -75,7 +75,7 @@ export type CreateCookieFunction = (
 /**
  * Creates a logical container for managing a browser cookie from the server.
  *
- * @see https://remix.run/api/remix#createcookie
+ * @see https://remix.run/utils/cookies#createcookie
  */
 export const createCookieFactory =
   ({
@@ -135,7 +135,7 @@ export type IsCookieFunction = (object: any) => object is Cookie;
 /**
  * Returns true if an object is a Remix cookie container.
  *
- * @see https://remix.run/api/remix#iscookie
+ * @see https://remix.run/utils/cookies#iscookie
  */
 export const isCookie: IsCookieFunction = (object): object is Cookie => {
   return (
diff --git a/packages/remix-server-runtime/formData.ts b/packages/remix-server-runtime/formData.ts
index 8d6d40955..5e1baef2d 100644
--- a/packages/remix-server-runtime/formData.ts
+++ b/packages/remix-server-runtime/formData.ts
@@ -30,7 +30,7 @@ export function composeUploadHandlers(
  * Allows you to handle multipart forms (file uploads) for your app.
  *
  * TODO: Update this comment
- * @see https://remix.run/api/remix#parsemultipartformdata-node
+ * @see https://remix.run/utils/parse-multipart-form-data
  */
 export async function parseMultipartFormData(
   request: Request,
diff --git a/packages/remix-server-runtime/responses.ts b/packages/remix-server-runtime/responses.ts
index 748f98b1d..a67a416d8 100644
--- a/packages/remix-server-runtime/responses.ts
+++ b/packages/remix-server-runtime/responses.ts
@@ -13,7 +13,7 @@ export type TypedResponse<T extends unknown = unknown> = Response & {
  * This is a shortcut for creating `application/json` responses. Converts `data`
  * to JSON and sets the `Content-Type` header.
  *
- * @see https://remix.run/api/remix#json
+ * @see https://remix.run/utils/json
  */
 export const json: JsonFunction = (data, init = {}) => {
   let responseInit = typeof init === "number" ? { status: init } : init;
@@ -38,7 +38,7 @@ export type RedirectFunction = (
  * A redirect response. Sets the status code and the `Location` header.
  * Defaults to "302 Found".
  *
- * @see https://remix.run/api/remix#redirect
+ * @see https://remix.run/utils/redirect
  */
 export const redirect: RedirectFunction = (url, init = 302) => {
   let responseInit = init;
diff --git a/packages/remix-server-runtime/sessions.ts b/packages/remix-server-runtime/sessions.ts
index 4367d110c..6d3a05bec 100644
--- a/packages/remix-server-runtime/sessions.ts
+++ b/packages/remix-server-runtime/sessions.ts
@@ -14,7 +14,7 @@ export interface SessionData {
 /**
  * Session persists data across HTTP requests.
  *
- * @see https://remix.run/api/remix#session-api
+ * @see https://remix.run/utils/sessions#session-api
  */
 export interface Session {
   /**
@@ -76,7 +76,7 @@ export type CreateSessionFunction = (
  * Note: This function is typically not invoked directly by application code.
  * Instead, use a `SessionStorage` object's `getSession` method.
  *
- * @see https://remix.run/api/remix#createsession
+ * @see https://remix.run/utils/sessions#createsession
  */
 export const createSession: CreateSessionFunction = (
   initialData = {},
@@ -123,7 +123,7 @@ export type IsSessionFunction = (object: any) => object is Session;
 /**
  * Returns true if an object is a Remix session.
  *
- * @see https://remix.run/api/remix#issession
+ * @see https://remix.run/utils/sessions#issession
  */
 export const isSession: IsSessionFunction = (object): object is Session => {
   return (
@@ -222,7 +222,7 @@ export type CreateSessionStorageFunction = (
  * Note: This is a low-level API that should only be used if none of the
  * existing session storage options meet your requirements.
  *
- * @see https://remix.run/api/remix#createsessionstorage
+ * @see https://remix.run/utils/sessions#createsessionstorage
  */
 export const createSessionStorageFactory =
   (createCookie: CreateCookieFunction): CreateSessionStorageFunction =>
@@ -265,7 +265,7 @@ export function warnOnceAboutSigningSessionCookie(cookie: Cookie) {
     cookie.isSigned,
     `The "${cookie.name}" cookie is not signed, but session cookies should be ` +
       `signed to prevent tampering on the client before they are sent back to the ` +
-      `server. See https://remix.run/api/remix#signing-cookies ` +
+      `server. See https://remix.run/utils/cookies#signing-cookies ` +
       `for more information.`
   );
 }
diff --git a/packages/remix-server-runtime/sessions/cookieStorage.ts b/packages/remix-server-runtime/sessions/cookieStorage.ts
index 90d0a34da..2c3223f82 100644
--- a/packages/remix-server-runtime/sessions/cookieStorage.ts
+++ b/packages/remix-server-runtime/sessions/cookieStorage.ts
@@ -24,7 +24,7 @@ export type CreateCookieSessionStorageFunction = (
  * also has the limitation that serialized session data may not exceed the
  * browser's maximum cookie size. Trade-offs!
  *
- * @see https://remix.run/api/remix#createcookiesessionstorage
+ * @see https://remix.run/utils/sessions#createcookiesessionstorage
  */
 export const createCookieSessionStorageFactory =
   (createCookie: CreateCookieFunction): CreateCookieSessionStorageFunction =>
diff --git a/packages/remix-server-runtime/sessions/memoryStorage.ts b/packages/remix-server-runtime/sessions/memoryStorage.ts
index 0398eead8..f7ebcedf7 100644
--- a/packages/remix-server-runtime/sessions/memoryStorage.ts
+++ b/packages/remix-server-runtime/sessions/memoryStorage.ts
@@ -24,7 +24,7 @@ export type CreateMemorySessionStorageFunction = (
  * Note: This storage does not scale beyond a single process, so it is not
  * suitable for most production scenarios.
  *
- * @see https://remix.run/api/remix#creatememorysessionstorage
+ * @see https://remix.run/utils/sessions#creatememorysessionstorage
  */
 export const createMemorySessionStorageFactory =
   (
diff --git a/scripts/release/find-release-from-changeset.js b/scripts/release/find-release-from-changeset.js
new file mode 100644
index 000000000..ea0cb529e
--- /dev/null
+++ b/scripts/release/find-release-from-changeset.js
@@ -0,0 +1,38 @@
+/**
+ *
+ * @param {string | undefined} publishedPackages
+ * @param {string | undefined} packageVersionToFollow
+ * @returns {string | undefined}
+ */
+function findReleaseFromChangeset(publishedPackages, packageVersionToFollow) {
+  if (!publishedPackages) {
+    throw new Error("No published packages found");
+  }
+
+  let packages = JSON.parse(publishedPackages);
+
+  if (!Array.isArray(packages)) {
+    throw new Error("Published packages is not an array");
+  }
+
+  /** @see https://github.com/changesets/action#outputs */
+  /** @type { { name: string; version: string }[] }  */
+  let typed = packages.filter((pkg) => "name" in pkg && "version" in pkg);
+
+  let found = typed.find((pkg) => pkg.name === packageVersionToFollow);
+
+  if (!found) {
+    throw new Error(
+      `${packageVersionToFollow} was not found in the published packages`
+    );
+  }
+
+  let result = `${found.name}@${found.version}`;
+  console.log(result);
+  return result;
+}
+
+findReleaseFromChangeset(
+  process.env.publishedPackages,
+  process.env.packageVersionToFollow
+);
diff --git a/templates/cloudflare-pages/package.json b/templates/cloudflare-pages/package.json
index 5a312d6dc..2000d7f90 100644
--- a/templates/cloudflare-pages/package.json
+++ b/templates/cloudflare-pages/package.json
@@ -4,10 +4,11 @@
   "scripts": {
     "build": "remix build",
     "dev:remix": "remix watch",
-    "dev:wrangler": "cross-env NODE_ENV=development wrangler pages dev ./public",
+    "dev:wrangler": "cross-env NODE_ENV=development npm run wrangler",
     "dev": "remix build && run-p \"dev:*\"",
-    "start": "cross-env NODE_ENV=production npm run dev:wrangler",
-    "typecheck": "tsc -b"
+    "start": "cross-env NODE_ENV=production npm run wrangler",
+    "typecheck": "tsc -b",
+    "wrangler": "wrangler pages dev ./public"
   },
   "dependencies": {
     "@remix-run/cloudflare": "*",


Test patch:
diff --git a/packages/remix-server-runtime/__tests__/sessions-test.ts b/packages/remix-server-runtime/__tests__/sessions-test.ts
index 98f62e7de..5aca3ea48 100644
--- a/packages/remix-server-runtime/__tests__/sessions-test.ts
+++ b/packages/remix-server-runtime/__tests__/sessions-test.ts
@@ -161,7 +161,7 @@ describe("Cookie session storage", () => {
 
       expect(spy.console).toHaveBeenCalledTimes(1);
       expect(spy.console).toHaveBeenCalledWith(
-        'The "__session" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://remix.run/api/remix#signing-cookies for more information.'
+        'The "__session" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://remix.run/utils/cookies#signing-cookies for more information.'
       );
     });
   });