-
Notifications
You must be signed in to change notification settings - Fork 7
feat: add cardano summit token #137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds Cardano token assets and Godot texture/animation, extends Godot project to 4.5, and introduces multiple new frontend “how-to-play” sections, UI inputs, API routes, tx3 template and protocol binding changes to support gather-fuel/gather-token/mine-asteria/quit-game flows and updated move/create ship timing fields. Changes
Sequence Diagram(s)sequenceDiagram
participant FE as Frontend (UI)
participant API as Next.js API
participant Proto as Protocol Client
participant Chain as Remote service/Plutus IR
FE->>API: POST /api/asteria/gather-fuel {player, ship, pelletRef, fuel, blockSlot, network}
API->>API: validate inputs, compute sinceSlot
API->>Proto: gatherFuelTx(payload with pilotName/shipName/pelletRef/sinceSlot/...)
Proto->>Chain: resolve IR -> build tx3 -> sign/resolve
Chain-->>Proto: tx (hex)
Proto-->>API: ResolveResponse { tx }
API-->>FE: 200 { data: { tx } }
Note: the same flow applies for gather-token, mine-asteria, quit-game and move-ship/create-ship with different payload fields (since/until/lastMoveTimestamp or deltaX/deltaY). Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Focus areas for reviewers:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/how-to-play/move-ship/Section.tsx (1)
266-278: Display the correct validation error for “Latest block slot”.This input is bound to
errors.shipNumber, so block-slot validation feedback never appears and ship-number errors show up twice. Wire it toerrors.blockSlotinstead.- error={errors.shipNumber} + error={errors.blockSlot}
🧹 Nitpick comments (5)
frontend/src/components/how-to-play/move-ship/Description.mdx (1)
8-12: Consider minor style improvements for readability.The content is clear, but you may want to address these minor style points:
- "Rules to take into account" could be shortened to "Rules to consider"
- Lines 10-12 begin with "the", which could be varied for better flow
Apply this diff for improved readability:
-#### Rules to take into account: +#### Rules to consider: -- the ship number has to be the one controlled by the pilot token in your wallet. -- the total distance you travel is constrained by the number of slots between your tx validity range (ttl end - ttl start). -- the amount of fuel you pass is proportional to the total distance you travel (deltaX + deltaY). +- The ship number must be controlled by the pilot token in your wallet. +- Total travel distance is constrained by the slot count in your tx validity range (ttl end - ttl start). +- Fuel consumption is proportional to the total distance traveled (deltaX + deltaY).frontend/src/components/how-to-play/quit-game/Description.mdx (1)
8-10: Consider minor style improvement for conciseness.The heading "Rules to take into account" could be shortened to "Rules to consider" for brevity.
Apply this diff:
-#### Rules to take into account: +#### Rules to consider:frontend/src/components/how-to-play/gather-token/Description.mdx (1)
8-12: Consider minor style improvement for conciseness.The heading "Rules to take into account" could be shortened to "Rules to consider" for brevity.
Apply this diff:
-#### Rules to take into account: +#### Rules to consider:frontend/src/components/how-to-play/gather-fuel/Description.mdx (1)
8-12: Consider minor style improvement for conciseness.The heading "Rules to take into account" could be shortened to "Rules to consider" for brevity.
Apply this diff:
-#### Rules to take into account: +#### Rules to consider:frontend/src/components/how-to-play/move-ship/Section.tsx (1)
151-159: Add cleanup for the window message listener.We attach a new
messagehandler but never remove it. Every mount stacks another listener, keeping old closures alive and dispatching duplicatemove_shipcommands. Capture the handler and unregister it in the effect cleanup.- useEffect(() => { - window.addEventListener('message', (event) => { - if (pathname.includes('how-to-play') && window.location.hash === '#move-ship') { - if (event.data.action == 'ship_selected') { - updatePosition(event.data.position.x, event.data.position.y); - } - } - }); - }, []); + useEffect(() => { + const handleMessage = (event: MessageEvent<{ action?: string; position?: { x: number; y: number } }>) => { + if (pathname.includes('how-to-play') && window.location.hash === '#move-ship' && event.data?.action === 'ship_selected' && event.data.position) { + updatePosition(event.data.position.x, event.data.position.y); + } + }; + + window.addEventListener('message', handleMessage); + return () => { + window.removeEventListener('message', handleMessage); + }; + }, []);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
docker/Dockerfile.frontend(1 hunks)frontend/src/components/how-to-play/Menu.tsx(1 hunks)frontend/src/components/how-to-play/create-ship/Description.mdx(1 hunks)frontend/src/components/how-to-play/create-ship/Section.tsx(6 hunks)frontend/src/components/how-to-play/gather-fuel/Description.mdx(1 hunks)frontend/src/components/how-to-play/gather-fuel/Section.tsx(1 hunks)frontend/src/components/how-to-play/gather-token/Description.mdx(1 hunks)frontend/src/components/how-to-play/gather-token/Section.tsx(1 hunks)frontend/src/components/how-to-play/mine-asteria/Description.mdx(1 hunks)frontend/src/components/how-to-play/mine-asteria/Section.tsx(1 hunks)frontend/src/components/how-to-play/move-ship/Description.mdx(1 hunks)frontend/src/components/how-to-play/move-ship/Section.tsx(6 hunks)frontend/src/components/how-to-play/quit-game/Description.mdx(1 hunks)frontend/src/components/how-to-play/quit-game/Section.tsx(1 hunks)frontend/src/components/ui/Input.tsx(1 hunks)frontend/src/components/ui/NavBar.tsx(1 hunks)frontend/src/pages/api/asteria/create-ship.ts(1 hunks)frontend/src/pages/api/asteria/gather-fuel.ts(1 hunks)frontend/src/pages/api/asteria/gather-token.ts(1 hunks)frontend/src/pages/api/asteria/mine-asteria.ts(1 hunks)frontend/src/pages/api/asteria/move-ship.ts(1 hunks)frontend/src/pages/api/asteria/quit-game.ts(1 hunks)frontend/src/pages/how-to-play/index.tsx(2 hunks)frontend/src/pages/index.tsx(1 hunks)frontend/tx3/bindings/protocol.ts(3 hunks)frontend/tx3/main.tx3(10 hunks)godot-visualizer/project.godot(1 hunks)godot-visualizer/scripts/map.gd(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (13)
frontend/src/pages/api/asteria/quit-game.ts (2)
frontend/src/pages/api/asteria/gather-fuel.ts (2)
ResponseData(6-9)handler(11-75)frontend/src/utils/cli-protocol.ts (1)
getProtocol(3-11)
frontend/src/pages/api/asteria/gather-token.ts (2)
frontend/src/pages/api/asteria/gather-fuel.ts (2)
ResponseData(6-9)handler(11-75)frontend/src/utils/cli-protocol.ts (1)
getProtocol(3-11)
frontend/src/components/how-to-play/gather-fuel/Section.tsx (8)
frontend/src/stores/challenge.ts (1)
useChallengeStore(203-208)frontend/src/pages/api/asteria/gather-fuel.ts (1)
ResponseData(6-9)frontend/src/hooks/useCardano.ts (1)
ConnectedWallet(11-15)frontend/src/components/how-to-play/Tabs.tsx (2)
Tabs(25-114)Tab(21-23)frontend/src/components/ui/ConnectWallet.tsx (1)
ConnectWallet(10-50)frontend/src/components/ui/Alert.tsx (1)
Alert(11-82)frontend/src/components/ui/CopyButton.tsx (1)
CopyButton(3-23)frontend/src/components/ui/CodeBlock.tsx (1)
CodeBlock(11-23)
frontend/src/pages/index.tsx (1)
frontend/src/components/home/HeroSection.tsx (1)
HeroSection(8-53)
frontend/src/pages/api/asteria/mine-asteria.ts (1)
frontend/src/utils/cli-protocol.ts (1)
getProtocol(3-11)
frontend/src/components/how-to-play/gather-token/Section.tsx (8)
frontend/src/stores/challenge.ts (1)
useChallengeStore(203-208)frontend/src/pages/api/asteria/gather-token.ts (1)
ResponseData(6-9)frontend/src/hooks/useCardano.ts (1)
ConnectedWallet(11-15)frontend/src/components/how-to-play/Tabs.tsx (2)
Tabs(25-114)Tab(21-23)frontend/src/components/ui/ConnectWallet.tsx (1)
ConnectWallet(10-50)frontend/src/components/ui/Alert.tsx (1)
Alert(11-82)frontend/src/components/ui/CopyButton.tsx (1)
CopyButton(3-23)frontend/src/components/ui/CodeBlock.tsx (1)
CodeBlock(11-23)
frontend/src/pages/how-to-play/index.tsx (1)
frontend/src/components/how-to-play/Section.tsx (1)
Section(10-22)
frontend/src/components/how-to-play/create-ship/Section.tsx (1)
frontend/src/components/how-to-play/Tabs.tsx (1)
Tab(21-23)
frontend/src/components/how-to-play/mine-asteria/Section.tsx (8)
frontend/src/stores/challenge.ts (1)
useChallengeStore(203-208)frontend/src/pages/api/asteria/mine-asteria.ts (1)
ResponseData(6-9)frontend/src/hooks/useCardano.ts (1)
ConnectedWallet(11-15)frontend/src/components/how-to-play/Tabs.tsx (2)
Tabs(25-114)Tab(21-23)frontend/src/components/ui/ConnectWallet.tsx (1)
ConnectWallet(10-50)frontend/src/components/ui/Alert.tsx (1)
Alert(11-82)frontend/src/components/ui/CopyButton.tsx (1)
CopyButton(3-23)frontend/src/components/ui/CodeBlock.tsx (1)
CodeBlock(11-23)
frontend/src/components/how-to-play/move-ship/Section.tsx (2)
frontend/src/hooks/useCardano.ts (1)
ConnectedWallet(11-15)frontend/src/components/how-to-play/Tabs.tsx (1)
Tab(21-23)
frontend/src/pages/api/asteria/gather-fuel.ts (1)
frontend/src/utils/cli-protocol.ts (1)
getProtocol(3-11)
frontend/src/components/how-to-play/quit-game/Section.tsx (8)
frontend/src/stores/challenge.ts (1)
useChallengeStore(203-208)frontend/src/pages/api/asteria/quit-game.ts (1)
ResponseData(6-9)frontend/src/hooks/useCardano.ts (1)
ConnectedWallet(11-15)frontend/src/components/how-to-play/Tabs.tsx (2)
Tabs(25-114)Tab(21-23)frontend/src/components/ui/ConnectWallet.tsx (1)
ConnectWallet(10-50)frontend/src/components/ui/Alert.tsx (1)
Alert(11-82)frontend/src/components/ui/CopyButton.tsx (1)
CopyButton(3-23)frontend/src/components/ui/CodeBlock.tsx (1)
CodeBlock(11-23)
frontend/src/pages/api/asteria/move-ship.ts (1)
frontend/src/utils/cli-protocol.ts (1)
getProtocol(3-11)
🪛 LanguageTool
frontend/src/components/how-to-play/create-ship/Description.mdx
[style] ~4-~4: Consider a more concise word here.
Context: ...; #### This is the first step in order to play the game. This transaction create...
(IN_ORDER_TO_PREMIUM)
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...E_FEE` paid by the user. #### Rules to take into account: - the ship number has to be exactly +...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
frontend/src/components/how-to-play/gather-fuel/Description.mdx
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...kens held in the pellet. #### Rules to take into account: - the ship number has to be the one c...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
frontend/src/components/how-to-play/quit-game/Description.mdx
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...e remaining fuel tokens. #### Rules to take into account: - the ship number has to be the one c...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
frontend/src/components/how-to-play/mine-asteria/Description.mdx
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...g fuel tokens are burnt. #### Rules to take into account: - the ship number has to be the one c...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
frontend/src/components/how-to-play/gather-token/Description.mdx
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...kens held in the pellet. #### Rules to take into account: - the ship number has to be the one c...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
frontend/src/components/how-to-play/move-ship/Description.mdx
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...range latest posix time. #### Rules to take into account: - the ship number has to be the one c...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
[style] ~12-~12: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...validity range (ttl end - ttl start). - the amount of fuel you pass is proportional...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (7)
godot-visualizer/scripts/map.gd (1)
206-209: Verify platform compatibility assumption and refine JSON escaping approach.The review raises two concerns, but the proposed fix requires refinement:
Platform check validity: The codebase has no
OS.has_featurechecks anywhere—JavaScriptBridge is called directly throughout main.gd (lines 96-97, 118-125, 145-151, 154) without guards. This appears to be an architectural assumption rather than a per-call issue. Verify whether this code is only intended for web exports.JSON escaping limitation: The suggested
.replace("\\", "\\\\").replace("'", "\\'")is incomplete. Proper escaping would need to handle all JavaScript escape sequences (newlines, carriage returns, unicode, etc.). A better approach would be usingJSON.stringify()in JavaScript or restructuring the message format to avoid string interpolation altogether.Note: The same pattern exists at lines 98-101 (map_click). Both should be addressed consistently.
godot-visualizer/project.godot (1)
15-15: Version upgrade is consistent with no conflicting references found, but runtime verification required.The change updates
config/featuresfrom 4.4 to 4.5 and is the only Godot version reference in the codebase—no conflicting version strings detected. However, upgrading between minor versions can introduce subtle compatibility issues that require testing.Follow the 4.5 migration checklist before merging:
- Open the project with Godot 4.5
- Review the editor's conversion log for errors/warnings
- Validate Resource files and packed scenes (common source of issues)
- Test all scenes, especially physics and input handling
- Verify rendering (new settings like specular-occlusion may affect appearance)
See the official Godot 4.5 release notes for the complete breaking changes list.
frontend/src/pages/api/asteria/create-ship.ts (1)
56-57: LGTM! New timing field added.The addition of
lastMoveTimestampalongside the existingtipSlotextends the transaction with dual timing mechanisms (slot-based and timestamp-based). This aligns with the protocol binding upgrades described in the PR summary.frontend/src/components/ui/NavBar.tsx (1)
33-36: LGTM! Navigation item activated.The "How to play" link is now properly activated with correct styling and separator, consistent with other navigation items.
frontend/src/pages/how-to-play/index.tsx (2)
10-13: LGTM! New section imports added.The imports for GatherFuel, GatherToken, MineAsteria, and QuitGame sections are properly structured.
70-84: LGTM! New sections integrated correctly.The four new sections (GATHER FUEL, GATHER TOKEN, MINE ASTERIA, QUIT GAME) are properly integrated into the render tree with correct
isActivebindings and id attributes for scroll navigation.frontend/src/pages/api/asteria/mine-asteria.ts (1)
48-62: LGTM! Transaction generation logic is correct.The mine-asteria transaction generation follows the established pattern from other API routes, with proper validation, encoding, and error handling.
| This transaction creates a `ShipState` UTxO locking min ada, a `ShipToken` (minted in this tx) and an `INITIAL_FUEL` amount of fuel tokens (minted in this tx), specifying in the datum the initial `pos_x` and `pos_y` coordinates of the ship, the ship and pilot token names and the `last_move_latest_time` as the upper bound of the transaction's validity range (posix time). Also adds to the `AsteriaUTxO` value the `SHIP_MINT_LOVELACE_FEE` paid by the user. | ||
|
|
||
| #### Rules to take into account: | ||
|
|
||
| - the ship number has to be exactly +1 of the last ship minted | ||
| - the tip slot must be recent because it's used during validation of the tx | ||
| - the start position has to be at a certain distance ([manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry)) of coordinates (0,0). For the mainnet challenge the minimum distance is `50`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix outdated datum field name.
The Create Ship flow now sets the datum field to last_move_timestamp, but the doc still refers to last_move_latest_time. This mismatch will trip anyone copying the guidance into the updated tx template—please update the wording to match the current field name.
🧰 Tools
🪛 LanguageTool
[style] ~8-~8: ‘take into account’ might be wordy. Consider a shorter alternative.
Context: ...E_FEE` paid by the user. #### Rules to take into account: - the ship number has to be exactly +...
(EN_WORDINESS_PREMIUM_TAKE_INTO_ACCOUNT)
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/create-ship/Description.mdx around lines
6 to 12, the documentation references the outdated datum field name
`last_move_latest_time`; update all occurrences in this block to the current
field name `last_move_timestamp` so the text matches the updated Create Ship
flow and the transaction template (i.e., replace the phrase "the
`last_move_latest_time` as the upper bound" with "the `last_move_timestamp` as
the upper bound" and ensure any other mentions in these lines use
`last_move_timestamp`).
| error={errors.shipNumber} | ||
| disabled={submitting} | ||
| button="fetch last" | ||
| onClickButton={handleFetchLastSlot} | ||
| value={tipSlot} | ||
| onChange={updateTipSlot} | ||
| required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wire the block-slot field to its own errors and keep the input controlled.
The block-slot input currently shows errors.shipNumber, so the user never sees block-slot validation issues. It also passes raw undefined, which flips the field from uncontrolled to controlled once a value arrives and triggers React warnings. Point the field at errors.blockSlot and normalise the value.
- error={errors.shipNumber}
+ error={errors.blockSlot}
disabled={submitting}
button="fetch last"
onClickButton={handleFetchLastSlot}
- value={tipSlot}
+ value={tipSlot ?? ''}
onChange={updateTipSlot}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| error={errors.shipNumber} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| error={errors.blockSlot} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot ?? ''} | |
| onChange={updateTipSlot} | |
| required |
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/gather-fuel/Section.tsx around lines 228
to 234, the block-slot input is incorrectly wired to errors.shipNumber and is
passing raw undefined which toggles the input between uncontrolled and
controlled; change the error prop to errors.blockSlot and normalize the value so
it is always a string (e.g. use tipSlot ?? '' or String(tipSlot || '')) to keep
the input controlled and ensure block-slot validation messages display
correctly.
| name="blockSlot" | ||
| type="number" | ||
| placeholder="Latest block slot" | ||
| containerClassName="flex-1" | ||
| label="Latest block slot" | ||
| error={errors.shipNumber} | ||
| disabled={submitting} | ||
| button="fetch last" | ||
| onClickButton={handleFetchLastSlot} | ||
| value={tipSlot} | ||
| onChange={updateTipSlot} | ||
| required | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix block slot error binding.
error={errors.shipNumber} prevents block-slot validation messages from ever showing, so users won’t learn why submission fails when that field is invalid. Please point the input at the blockSlot error key instead.
- error={errors.shipNumber}
+ error={errors.blockSlot}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.shipNumber} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> | |
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.blockSlot} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> |
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/gather-token/Section.tsx around lines 233
to 245, the block slot input is incorrectly wired to errors.shipNumber; change
the error binding to errors.blockSlot so validation messages for the blockSlot
field are displayed (i.e., replace the error prop value with the blockSlot error
key and ensure the form schema/key matches if necessary).
| name="blockSlot" | ||
| type="number" | ||
| placeholder="Latest block slot" | ||
| containerClassName="flex-1" | ||
| label="Latest block slot" | ||
| error={errors.shipNumber} | ||
| disabled={submitting} | ||
| button="fetch last" | ||
| onClickButton={handleFetchLastSlot} | ||
| value={tipSlot} | ||
| onChange={updateTipSlot} | ||
| required | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bind the block slot input to its own error key.
The block-slot field pumps errors.shipNumber, so users never see validation feedback for block-slot issues. Please wire it to errors.blockSlot.
- error={errors.shipNumber}
+ error={errors.blockSlot}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.shipNumber} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> | |
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.blockSlot} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> |
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/mine-asteria/Section.tsx around lines 236
to 248, the block-slot input is incorrectly using errors.shipNumber so
validation feedback for the block-slot never appears; change the input's error
prop to errors.blockSlot (and ensure that the form validation/schema produces a
blockSlot error key) so the field shows its own validation messages.
| const updateDeltaX = (event: ChangeEvent<HTMLInputElement>) => { | ||
| updateDelta(parseInt(event.target.value), delta ? delta.y : 0); | ||
| } | ||
|
|
||
| const updatePositionY = (event: ChangeEvent<HTMLInputElement>) => { | ||
| updatePosition(position ? position.x : 0, parseInt(event.target.value)); | ||
| const updateDeltaY = (event: ChangeEvent<HTMLInputElement>) => { | ||
| updateDelta(delta ? delta.x : 0, parseInt(event.target.value)); | ||
| } | ||
|
|
||
| const updatePosition = (x: number, y: number) => { | ||
| setPosition({ x, y }); | ||
| console.log({ x, y, shipNumber }); | ||
| window.GODOT_BRIDGE?.send({ action: 'select_ship', shipNumber }); | ||
| window.GODOT_BRIDGE?.send({ action: 'move_ship', x, y }); | ||
|
|
||
| const updateDelta = (x: number, y: number) => { | ||
| setDelta({ x, y }); | ||
| window.GODOT_BRIDGE?.send({ | ||
| action: 'move_ship', | ||
| x: x + (position ? position.x : 0), | ||
| y: y + (position ? position.y : 0) | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent NaN deltas from hitting Godot and the API.
When the user clears or types an intermediate value, parseInt produces NaN, which we then store in state and forward over the bridge—Godot receives { x: NaN, y: … }, and the controlled inputs display “NaN”. That breaks previews and sends invalid payloads to /api/asteria/move-ship. Please guard the conversion so we only call updateDelta with finite numbers.
- const updateDeltaX = (event: ChangeEvent<HTMLInputElement>) => {
- updateDelta(parseInt(event.target.value), delta ? delta.y : 0);
- }
-
- const updateDeltaY = (event: ChangeEvent<HTMLInputElement>) => {
- updateDelta(delta ? delta.x : 0, parseInt(event.target.value));
- }
+ const updateDeltaX = (event: ChangeEvent<HTMLInputElement>) => {
+ const parsed = Number(event.target.value);
+ if (Number.isNaN(parsed)) {
+ return;
+ }
+ updateDelta(parsed, delta ? delta.y : 0);
+ };
+
+ const updateDeltaY = (event: ChangeEvent<HTMLInputElement>) => {
+ const parsed = Number(event.target.value);
+ if (Number.isNaN(parsed)) {
+ return;
+ }
+ updateDelta(delta ? delta.x : 0, parsed);
+ };📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const updateDeltaX = (event: ChangeEvent<HTMLInputElement>) => { | |
| updateDelta(parseInt(event.target.value), delta ? delta.y : 0); | |
| } | |
| const updatePositionY = (event: ChangeEvent<HTMLInputElement>) => { | |
| updatePosition(position ? position.x : 0, parseInt(event.target.value)); | |
| const updateDeltaY = (event: ChangeEvent<HTMLInputElement>) => { | |
| updateDelta(delta ? delta.x : 0, parseInt(event.target.value)); | |
| } | |
| const updatePosition = (x: number, y: number) => { | |
| setPosition({ x, y }); | |
| console.log({ x, y, shipNumber }); | |
| window.GODOT_BRIDGE?.send({ action: 'select_ship', shipNumber }); | |
| window.GODOT_BRIDGE?.send({ action: 'move_ship', x, y }); | |
| const updateDelta = (x: number, y: number) => { | |
| setDelta({ x, y }); | |
| window.GODOT_BRIDGE?.send({ | |
| action: 'move_ship', | |
| x: x + (position ? position.x : 0), | |
| y: y + (position ? position.y : 0) | |
| }); | |
| const updateDeltaX = (event: ChangeEvent<HTMLInputElement>) => { | |
| const parsed = Number(event.target.value); | |
| if (Number.isNaN(parsed)) { | |
| return; | |
| } | |
| updateDelta(parsed, delta ? delta.y : 0); | |
| }; | |
| const updateDeltaY = (event: ChangeEvent<HTMLInputElement>) => { | |
| const parsed = Number(event.target.value); | |
| if (Number.isNaN(parsed)) { | |
| return; | |
| } | |
| updateDelta(delta ? delta.x : 0, parsed); | |
| }; | |
| const updateDelta = (x: number, y: number) => { | |
| setDelta({ x, y }); | |
| window.GODOT_BRIDGE?.send({ | |
| action: 'move_ship', | |
| x: x + (position ? position.x : 0), | |
| y: y + (position ? position.y : 0) | |
| }); |
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/move-ship/Section.tsx around lines
165-179, the handlers and updateDelta currently let parseInt produce NaN which
is stored/sent; change the input handlers to parse the value, check
Number.isFinite(parsed) and only call updateDelta when parsed is a finite number
(otherwise return early), and also harden updateDelta to coerce its x and y
params to finite numbers (fallback to 0) before setDelta and before sending to
window.GODOT_BRIDGE so no NaN can be stored or forwarded.
| name="blockSlot" | ||
| type="number" | ||
| placeholder="Latest block slot" | ||
| containerClassName="flex-1" | ||
| label="Latest block slot" | ||
| error={errors.shipNumber} | ||
| disabled={submitting} | ||
| button="fetch last" | ||
| onClickButton={handleFetchLastSlot} | ||
| value={tipSlot} | ||
| onChange={updateTipSlot} | ||
| required | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Show block-slot validation errors on the correct field.
Same as the other sections: the block-slot input references errors.shipNumber, so it hides its own validation errors. Point it at errors.blockSlot.
- error={errors.shipNumber}
+ error={errors.blockSlot}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.shipNumber} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> | |
| name="blockSlot" | |
| type="number" | |
| placeholder="Latest block slot" | |
| containerClassName="flex-1" | |
| label="Latest block slot" | |
| error={errors.blockSlot} | |
| disabled={submitting} | |
| button="fetch last" | |
| onClickButton={handleFetchLastSlot} | |
| value={tipSlot} | |
| onChange={updateTipSlot} | |
| required | |
| /> |
🤖 Prompt for AI Agents
In frontend/src/components/how-to-play/quit-game/Section.tsx around lines 215 to
227 the block-slot input incorrectly uses errors.shipNumber for its error prop;
change that prop to errors.blockSlot so the block-slot field displays its own
validation errors (update any related prop references or types if necessary and
run typechecks/tests).
| if (Object.keys(errors).length > 0) { | ||
| return { errors }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a 400 response when validation fails.
return { errors }; never sends an HTTP response, so clients hang waiting for a reply. We need to write the 400 status and JSON body through res (as with every other branch).
- if (Object.keys(errors).length > 0) {
- return { errors };
- }
+ if (Object.keys(errors).length > 0) {
+ return res.status(400).json({ errors });
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Object.keys(errors).length > 0) { | |
| return { errors }; | |
| } | |
| if (Object.keys(errors).length > 0) { | |
| return res.status(400).json({ errors }); | |
| } |
🤖 Prompt for AI Agents
In frontend/src/pages/api/asteria/gather-fuel.ts around lines 41 to 43, the
handler returns an object ({ errors }) instead of sending an HTTP response when
validation fails; update this branch to write a 400 status and JSON body via the
Next.js API response object (res.status(400).json({ errors })) so the client
receives the error and the request completes.
| if (Object.keys(errors).length > 0) { | ||
| return { errors }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Send a 400 response on validation errors.
Just like the other API route, returning { errors } leaves the HTTP response open and causes the fetcher to hang. Respond via res.status(400).json(...).
- if (Object.keys(errors).length > 0) {
- return { errors };
- }
+ if (Object.keys(errors).length > 0) {
+ return res.status(400).json({ errors });
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Object.keys(errors).length > 0) { | |
| return { errors }; | |
| } | |
| if (Object.keys(errors).length > 0) { | |
| return res.status(400).json({ errors }); | |
| } |
🤖 Prompt for AI Agents
In frontend/src/pages/api/asteria/gather-token.ts around lines 50 to 52, the
handler currently returns an object when validation fails which leaves the HTTP
response open; instead set the HTTP status to 400 and send a JSON response.
Replace the plain return with res.status(400).json({ errors }) so the route
terminates the request properly and the client receives the validation errors.
| if (Object.keys(errors).length > 0) { | ||
| return { errors }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix missing response method call.
Line 45 returns a plain object instead of an HTTP response. This will cause the API endpoint to fail when validation errors occur.
Apply this diff to fix:
if (Object.keys(errors).length > 0) {
- return { errors };
+ return res.json({ errors });
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Object.keys(errors).length > 0) { | |
| return { errors }; | |
| } | |
| if (Object.keys(errors).length > 0) { | |
| return res.json({ errors }); | |
| } |
🤖 Prompt for AI Agents
In frontend/src/pages/api/asteria/mine-asteria.ts around lines 44 to 46, the
code returns a plain object ({ errors }) instead of sending an HTTP response;
replace that return with sending a proper HTTP response, e.g. call
res.status(400).json({ errors }) (and return after calling it) so the API
endpoint responds with a 400 and the validation errors.
| if (Object.keys(errors).length > 0) { | ||
| return { errors }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Respond with an HTTP error instead of returning a plain object.
When validation fails, the handler returns { errors } without writing to res, so Next.js logs “API resolved without sending a response” and the client fetch never receives an error payload. Please send an explicit 400 response.
- if (Object.keys(errors).length > 0) {
- return { errors };
- }
+ if (Object.keys(errors).length > 0) {
+ return res.status(400).json({ errors });
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (Object.keys(errors).length > 0) { | |
| return { errors }; | |
| } | |
| if (Object.keys(errors).length > 0) { | |
| return res.status(400).json({ errors }); | |
| } |
🤖 Prompt for AI Agents
In frontend/src/pages/api/asteria/quit-game.ts around lines 39 to 41, the
handler currently returns a plain object when validation fails which prevents
writing an HTTP response and triggers Next.js "API resolved without sending a
response"; change this to send an explicit 400 response by calling
res.status(400).json({ errors }) and then return to stop further execution so
the client receives the error payload.
Summary by CodeRabbit
New Features
UX