Skip to content

Commit bcd1d6f

Browse files
authored
Fix Next.js parse endpoint (#218)
* refactor to post endpoint * add todo * fix error response * add more error handling * attempt to fix 405 error * add @onflowser/nodejs to web package.json * attempt to install go via npm * Revert "attempt to install go via npm" This reverts commit 071de76. * add install go script * fix exec usage * fix async usage * fix install url * add go to path, fix rm command * add logging * fix logging * attempt to include bin in final output * remove tree command * fix setup-bin * fix bin path * attempt to fix bin path * update build script * add debug logs * add debug logs * add test find command * add workaround for retrieving project root * add debug calls * final fix * tweaks
1 parent 8b58190 commit bcd1d6f

10 files changed

Lines changed: 145 additions & 37 deletions

File tree

apps/electron/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"main": "./src/main/main.ts",
2828
"scripts": {
2929
"generate-icons": "../../node_modules/.bin/electron-icon-maker --input=./assets/icon.png --output=./generated-icons",
30-
"build": "npm run generate-icons && concurrently \"npm run build:main\" \"npm run build:renderer\"",
30+
"build-electron": "npm run generate-icons && concurrently \"npm run build:main\" \"npm run build:renderer\"",
3131
"build:dll": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
3232
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
3333
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",

apps/web/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"dev": "next dev",
7-
"build": "next build",
6+
"dev": "npm run setup-bin && next dev",
7+
"build-web": "npm run setup-bin && next build",
8+
"setup-bin": "mkdir -p public/bin && cp ../../packages/nodejs/bin/flowser-internal-amd64-linux public/bin/flowser-internal-amd64-linux",
89
"start": "next start",
910
"lint": "next lint"
1011
},
1112
"dependencies": {
1213
"@onflowser/ui": "*",
14+
"@onflowser/nodejs": "*",
1315
"next": "^14.0.4",
1416
"react": "^18",
1517
"react-dom": "^18",
Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
1+
import {GoBindingsService} from "@onflowser/nodejs"
12
import path from "path";
2-
import {GoBindingsService} from "../../../../../../../packages/nodejs/src"
3+
4+
const isDev = process.env.NODE_ENV === "development";
35

46
const goBindingsService = new GoBindingsService({
5-
binDirPath: path.join(
6-
__dirname,
7-
'../../../../../../../..',
8-
'packages',
9-
'nodejs',
10-
'bin',
11-
),
7+
// In dev we can pull the bin directly from the `nodejs/bin` dir in the monorepo.
8+
// While in prod we must use the one that's copied to the current folder with `setup-bin` script.
9+
binDirPath: isDev
10+
? path.join(
11+
__dirname,
12+
'../../../../../../../..',
13+
'packages',
14+
'nodejs',
15+
'bin',
16+
)
17+
// https://github.com/vercel/next.js/issues/8251#issuecomment-657770901
18+
: path.resolve("./public/bin"),
1219
});
1320

14-
export async function GET(request: Request) {
15-
const { searchParams } = new URL(request.url)
16-
const sourceCode = searchParams.get('sourceCode');
21+
export async function POST(request: Request) {
22+
const requestBody = await request.json();
23+
const sourceCode = requestBody?.sourceCode;
1724

18-
if (sourceCode === null) {
19-
throw new Error("Missing `sourceCode` query param")
25+
if (!sourceCode) {
26+
return Response.json({
27+
message: "Missing `sourceCode` field in body"
28+
}, {
29+
status: 400
30+
})
2031
}
2132

22-
const parsedInteraction = await goBindingsService.getParsedInteraction({
23-
sourceCode
24-
})
33+
try {
34+
const parsedInteraction = await goBindingsService.getParsedInteraction({
35+
sourceCode
36+
});
2537

26-
return Response.json(parsedInteraction)
38+
return Response.json(parsedInteraction)
39+
} catch (error: any) {
40+
return Response.json({
41+
message: `Error parsing: ${error.message}`
42+
}, {
43+
status: 500
44+
})
45+
}
2746
}

apps/web/src/app/[chainId]/page.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ class InteractionsService implements IInteractionService {
5858

5959
async parse(sourceCode: string): Promise<ParsedInteractionOrError> {
6060
// It doesn't matter which chain ID we use in URL.
61-
const url = new URL(`${window.location.origin}/flow-emulator/interactions/parse`);
62-
url.searchParams.append("sourceCode", sourceCode);
63-
return fetch(url).then(res => res.json())
61+
return fetch(`${window.location.origin}/flow-emulator/interactions/parse`, {
62+
method: "POST",
63+
body: JSON.stringify({ sourceCode }),
64+
}).then(res => res.json())
6465
}
6566

6667
async sendTransaction(request: SendTransactionRequest): Promise<TransactionOutcome> {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"private": true,
44
"description": "Easily inspect and debug Flow blockchain ⛓",
55
"scripts": {
6-
"build": "turbo run build",
6+
"build-electron": "turbo run build-electron",
7+
"build-web": "turbo run build-web",
78
"dev": "turbo run dev --parallel",
89
"compile": "turbo run compile",
910
"lint": "turbo run lint",
Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
OUT_PATH=bin
22
BIN_PREFIX=flowser-internal
33
SOURCE_PATH=../../internal/main.go
4+
# This is added in case it's run on linux with newly installed go bin using `install-go.js`.
5+
PATH=$PATH:/usr/local/go/bin
6+
7+
echo "Building using go $(go version) from $(which go)"
48

59
# Technically, only 64bit architectures are supported, since
610
# Cadence can't be built for 32bit arch due to constant overflows:
@@ -10,7 +14,7 @@ SOURCE_PATH=../../internal/main.go
1014

1115
# https://freshman.tech/snippets/go/cross-compile-go-programs
1216

13-
rm -r $OUT_PATH
17+
rm -rf $OUT_PATH
1418
mkdir -p $OUT_PATH
1519

1620
function build() {
@@ -21,14 +25,22 @@ function build() {
2125
}
2226

2327
# Windows
24-
build windows amd64 .exe
25-
build windows arm64 .exe
28+
if [[ $* == *--windows* ]]; then
29+
echo "Building for Windows ..."
30+
build windows amd64 .exe
31+
build windows arm64 .exe
32+
fi
2633

2734
# MacOS
28-
build darwin amd64
29-
build darwin arm64
35+
if [[ $* == *--darwin* ]]; then
36+
echo "Building for MacOS ..."
37+
build darwin amd64
38+
build darwin arm64
39+
fi
3040

3141
# Linux
32-
build linux amd64
33-
build linux arm64
34-
42+
if [[ $* == *--linux* ]]; then
43+
echo "Building for Linux ..."
44+
build linux amd64
45+
build linux arm64
46+
fi

packages/nodejs/install-go.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const { exec } = require('child_process');
2+
const https = require('https');
3+
const fs = require('fs');
4+
const os = require('os');
5+
const { promisify } = require('util');
6+
7+
const execAsync = promisify(exec);
8+
9+
async function isGoInstalled() {
10+
try {
11+
const { stdout } = await execAsync('go version');
12+
console.log('Go is already installed:', stdout.trim());
13+
return true;
14+
} catch (error) {
15+
console.log('Go is not installed');
16+
return false;
17+
}
18+
}
19+
20+
async function downloadFile(url, dest) {
21+
const file = fs.createWriteStream(dest);
22+
return new Promise((resolve, reject) => {
23+
https.get(url, (response) => {
24+
response.pipe(file);
25+
file.on('finish', () => {
26+
file.close();
27+
resolve(file);
28+
});
29+
file.on("error", (error) => {
30+
reject(error);
31+
})
32+
});
33+
});
34+
}
35+
36+
function installGo(filePath) {
37+
return new Promise((resolve, reject) => {
38+
exec(`tar -C /usr/local -xzf ${filePath}`, async (error) => {
39+
if (error) {
40+
console.error('Error occurred:', error);
41+
return reject(error);
42+
}
43+
console.log('Go installed successfully');
44+
// Updating PATH to include Go (this will only affect this script's process)
45+
process.env.PATH += ':/usr/local/go/bin';
46+
const { stdout } = await execAsync('go version');
47+
console.log('Installed Go version:', stdout.trim());
48+
resolve();
49+
});
50+
})
51+
}
52+
53+
// We need to install go in our web deployment pipeline on Vercel.
54+
async function main() {
55+
const goInstalled = await isGoInstalled();
56+
if (!goInstalled && os.platform() === "linux") {
57+
const goVersion = '1.19'; // Update this as needed
58+
const platform = 'linux-amd64';
59+
const url = `https://dl.google.com/go/go${goVersion}.${platform}.tar.gz`;
60+
const dest = `/tmp/go${goVersion}.${platform}.tar.gz`;
61+
await downloadFile(url, dest);
62+
await installGo(dest);
63+
}
64+
}
65+
66+
main();

packages/nodejs/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"main": "./src/index.ts",
66
"types": "./src/index.ts",
77
"scripts": {
8-
"dev": "npm run build-bin",
9-
"build": "npm run build-bin",
10-
"build-bin": "sh build-go-bindings.sh",
8+
"dev": "sh build-go-bindings.sh --darwin",
9+
"build-web": "node install-go.js && sh build-go-bindings.sh --linux",
10+
"build-electron": "npm run build-bin --linux --darwin --windows",
1111
"format": "prettier . --write"
1212
},
1313
"keywords": [],

packages/ui/src/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ export function useGetParsedInteraction(
259259
);
260260

261261
useEffect(() => {
262+
// TODO: This will revalidate (trigger a request) by every consumer who uses this hook.
263+
// Since mutate will be triggered within each consumers lifecycle.
262264
// Avoid revalidating up-to-date cache on mount.
263265
if (state.data?.source !== request.code) {
264266
state.mutate();

turbo.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
{
22
"npmClient": "yarn",
33
"pipeline": {
4-
"build": {
4+
"build-electron": {
55
"cache": false,
6-
"dependsOn": ["^build"],
6+
"dependsOn": ["^build-electron"],
7+
"outputs": ["dist/**", "bin/**"]
8+
},
9+
"build-web": {
10+
"cache": false,
11+
"dependsOn": ["^build-web"],
712
"outputs": ["dist/**", "bin/**", ".next/**"]
813
},
914
"compile": {

0 commit comments

Comments
 (0)