Skip to content

Commit

Permalink
Fix legacy routes
Browse files Browse the repository at this point in the history
  • Loading branch information
ije committed Jan 15, 2025
1 parent 436f075 commit f5856ca
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 13 deletions.
41 changes: 28 additions & 13 deletions server/legacy_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,27 @@ func esmLegacyRouter(buildStorage storage.Storage) rex.Handle {
}

// `/[email protected]&pin=v135`
if strings.Contains(pathname, "&pin=") {
return legacyESM(ctx, buildStorage, pathname, false)
if strings.Contains(pathname, "&pin=v") {
return legacyESM(ctx, buildStorage, pathname, "")
}

// `/[email protected]?pin=v135`
if q := ctx.R.URL.RawQuery; strings.HasPrefix(q, "pin=") || strings.Contains(q, "&pin=") {
if q := ctx.R.URL.RawQuery; strings.HasPrefix(q, "pin=v") || strings.Contains(q, "&pin=v") {
query := ctx.R.URL.Query()
v := query.Get("pin")
if len(v) > 1 && v[0] == 'v' && valid.IsDigtalOnlyString(v[1:]) {
bv, _ := strconv.Atoi(v[1:])
if bv <= 0 || bv > 135 {
return rex.Status(400, "Invalid `pin` query")
}
return legacyESM(ctx, buildStorage, pathname, false)
return legacyESM(ctx, buildStorage, pathname, "")
}
}

// `/stable/[email protected]?dev`
// `/stable/[email protected]/es2022/react.mjs`
if strings.HasPrefix(pathname, "/stable/") {
return legacyESM(ctx, buildStorage, pathname[7:], true)
return legacyESM(ctx, buildStorage, pathname[7:], "stable")
}

// `/v135/[email protected]?dev`
Expand All @@ -87,7 +87,7 @@ func esmLegacyRouter(buildStorage storage.Storage) rex.Handle {
pathname = "/build"
goto START
}
return legacyESM(ctx, buildStorage, "/"+path, true)
return legacyESM(ctx, buildStorage, "/"+path, "v"+legacyBuildVersion)
}
}

Expand All @@ -100,7 +100,7 @@ func esmLegacyRouter(buildStorage storage.Storage) rex.Handle {
}
}

func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string, hasBuildVersionPrefix bool) any {
func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string, buildVersionPrefix string) any {
query := ""
if ctx.R.URL.RawQuery != "" {
query = "?" + ctx.R.URL.RawQuery
Expand All @@ -109,7 +109,7 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string
if strings.HasPrefix(modulePath, "/node_") && strings.HasSuffix(modulePath, ".js") {
isStatic = true
} else {
pkgName, pkgVersion, hasTargetSegment, err := splitLegacyESMPath(modulePath)
pkgName, pkgVersion, subPath, hasTargetSegment, err := splitLegacyESMPath(modulePath)
if err != nil {
return rex.Status(400, err.Error())
}
Expand All @@ -122,12 +122,27 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string
}
return rex.Status(500, err.Error())
}
return redirect(ctx, getOrigin(ctx)+strings.Replace(ctx.R.URL.Path, "@"+pkgVersion, "@"+pkgInfo.Version, 1)+query, false)
var b strings.Builder
b.WriteString(getOrigin(ctx))
if buildVersionPrefix != "" {
b.WriteByte('/')
b.WriteString(buildVersionPrefix)
}
b.WriteByte('/')
b.WriteString(pkgName)
b.WriteByte('@')
b.WriteString(pkgInfo.Version)
if subPath != "" {
b.WriteByte('/')
b.WriteString(subPath)
}
b.WriteString(query)
return redirect(ctx, b.String(), false)
}
isStatic = hasTargetSegment
}
savePath := "legacy/" + normalizeSavePath("", ctx.R.URL.Path[1:])
if (hasBuildVersionPrefix && isStatic) || endsWith(modulePath, ".d.ts", ".d.mts") {
if (buildVersionPrefix != "" && isStatic) || endsWith(modulePath, ".d.ts", ".d.mts") {
f, _, e := buildStorage.Get(savePath)
if e != nil && e != storage.ErrNotFound {
return rex.Status(500, "Storage error: "+e.Error())
Expand Down Expand Up @@ -205,7 +220,7 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string
return rex.Status(res.StatusCode, data)
}

if (hasBuildVersionPrefix && isStatic) || endsWith(modulePath, ".d.ts", ".d.mts") {
if (buildVersionPrefix != "" && isStatic) || endsWith(modulePath, ".d.ts", ".d.mts") {
data, err := io.ReadAll(res.Body)
if err != nil {
return rex.Status(500, "Failed to fetch data from the legacy esm.sh server")
Expand Down Expand Up @@ -258,7 +273,7 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, modulePath string
}
}

func splitLegacyESMPath(pathname string) (pkgName string, version string, hasTargetSegment bool, err error) {
func splitLegacyESMPath(pathname string) (pkgName string, version string, subPath string, hasTargetSegment bool, err error) {
if strings.HasPrefix(pathname, "/gh/") {
if !strings.ContainsRune(pathname[4:], '/') {
err = errors.New("invalid path")
Expand All @@ -268,7 +283,7 @@ func splitLegacyESMPath(pathname string) (pkgName string, version string, hasTar
pathname = "/@" + pathname[4:]
}

pkgName, maybeVersion, _, hasTargetSegment := splitEsmPath(pathname)
pkgName, maybeVersion, subPath, hasTargetSegment := splitEsmPath(pathname)
if !validatePackageName(pkgName) {
err = fmt.Errorf("invalid package name '%s'", pkgName)
return
Expand Down
25 changes: 25 additions & 0 deletions test/legacy-routes/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,31 @@ Deno.test("legacy routes", async () => {
assertEquals(res.headers.get("X-TypeScript-Types"), "http://localhost:8080/v135/@types/react-dom@~18.3/index.d.ts");
assertStringIncludes(await res.text(), "/v135/[email protected]/es2022/react-dom.mjs");
}
{
const res = await fetch("http://localhost:8080/stable/react", {
redirect: "manual",
});
res.body?.cancel();
assertEquals(res.status, 302);
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/stable/react@"));
}
{
const res = await fetch("http://localhost:8080/v135/react", {
redirect: "manual",
});
res.body?.cancel();
assertEquals(res.status, 302);
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/v135/react@"));
}
{
const res = await fetch("http://localhost:8080/v135/@emotion/sheet?external=react,react-dom", {
redirect: "manual",
});
res.body?.cancel();
assertEquals(res.status, 302);
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/v135/@emotion/sheet@"));
assert(res.headers.get("Location")?.endsWith("?external=react,react-dom"));
}
{
const res = await fetch("http://localhost:8080/v135/@types/react-dom@~18.3/index.d.ts", {
redirect: "manual",
Expand Down

0 comments on commit f5856ca

Please sign in to comment.