Skip to content

Feat/update chars#29

Merged
BretRen merged 6 commits intomainfrom
feat/update-chars
Apr 20, 2026
Merged

Feat/update chars#29
BretRen merged 6 commits intomainfrom
feat/update-chars

Conversation

@BretRen
Copy link
Copy Markdown
Member

@BretRen BretRen commented Apr 20, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added character editing interface where users can modify existing character details including name, description, origin, images, and tags (up to 10 per character). Tag management supports adding via Enter key and removing individual tags.
  • Bug Fixes

    • Improved error message display in character creation to show API errors within the dialog rather than on the main page.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Warning

Rate limit exceeded

@BretRen has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 38 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 48 minutes and 38 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bb5683c9-44d6-471b-bad0-1c0be91b023e

📥 Commits

Reviewing files that changed from the base of the PR and between d9f269c and d4f55a9.

📒 Files selected for processing (3)
  • website/src/routes/create/+page.svelte
  • website/src/routes/edit/characters/[id]/+page.svelte
  • website/src/routes/edit/cps/[id]/+page.svelte
📝 Walkthrough

Walkthrough

This PR introduces an edit character form and refines error handling in the create character form. The create form now displays API errors in a dialog-local field. A new edit form allows authenticated users to update character details including name, description, origin, images, and tags via PocketBase.

Changes

Cohort / File(s) Summary
Create Character Error Handling
website/src/routes/create/+page.svelte
Modified error assignment in createCharacter catch block to write API errors to newCharErrorText (dialog-local) instead of page-level errorText.
Edit Character Form
website/src/routes/edit/characters/[id]/+page.svelte
New page component implementing character update form with authentication enforcement, character data fetching, multi-field editing (name, description, origin), image uploads, tag management with Enter-key addition and 10-tag limit, and error handling via PocketBase API integration.

Sequence Diagram

sequenceDiagram
    participant User
    participant Client as Browser/UI
    participant Auth as Auth Guard
    participant PB as PocketBase API
    participant DB as Database

    User->>Client: Navigate to /edit/characters/[id]
    Client->>Auth: Check authentication on mount
    alt User not authenticated
        Auth-->>Client: Redirect to /login
        Client->>User: Display login page
    else User authenticated
        Auth-->>Client: Allow access
        Client->>PB: Fetch character record by ID
        PB->>DB: Query character data
        DB-->>PB: Return character record
        PB-->>Client: Return character data
        Client->>Client: Initialize form fields & normalize tags
        Client->>User: Display edit form
        User->>Client: Edit fields, images, tags
        User->>Client: Submit form
        Client->>Client: Construct FormData payload
        Client->>PB: PUT /characters/{id}
        PB->>DB: Update character record
        alt Update successful
            DB-->>PB: Confirm update
            PB-->>Client: Success response
            Client->>Client: Navigate to /characters/{id}
        else Update fails
            DB-->>PB: Error response
            PB-->>Client: Error data
            Client->>Client: Extract & display error message
            Client->>User: Show error in dialog
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #16: Modifies the same website/src/routes/create/+page.svelte file and adjusts error-handling logic in the createCharacter function, indicating overlapping concerns around character form error display.

Poem

🐰 Characters now have a home to edit,
With tags and images, we'll never forget it!
Auth guards the gates, PocketBase holds the store,
Create and update—what's not to adore? ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feat/update chars' is partially related to the changeset, referring to a real aspect of the change but being overly vague and abbreviated, lacking clarity about what 'chars' means. Consider revising the title to be more specific and descriptive, such as 'Add character update form with tag and image management' to clearly convey the primary change.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/update-chars

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request fixes a variable assignment error in the character creation page and introduces a new character editing page. The new page allows users to fetch and update character details, including tags and images, using PocketBase. Several improvements were identified: the initial data fetch lacks error handling, redundant operations are performed on a new FormData object, and appending the owner ID during an update could lead to unintended ownership changes. Additionally, the UI should use a form element for better accessibility, and a typo in a name attribute needs to be corrected.

Comment thread website/src/routes/edit/characters/[id]/+page.svelte Outdated
Comment thread website/src/routes/edit/characters/[id]/+page.svelte Outdated
Comment thread website/src/routes/edit/characters/[id]/+page.svelte Outdated
Comment thread website/src/routes/edit/characters/[id]/+page.svelte Outdated
Comment thread website/src/routes/edit/characters/[id]/+page.svelte Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/src/routes/create/+page.svelte (1)

151-159: ⚠️ Potential issue | 🟠 Major

Potential TypeError in the catch handler when err.data.data is undefined.

Line 151 safely accesses err.data.data?.message (optional chaining), but line 153 immediately does Object.keys(err.data.data)[0] without the same guard. If the thrown error doesn't have err.data.data (e.g. network error, non-PocketBase error, or a PB error without field details), this will throw inside the catch block — the friendly fallback message set on line 151 will never render, and an uncaught exception surfaces to the console.

🛡️ Proposed fix
 		} catch (err: any) {
-			newCharErrorText = err.data.data?.message ?? 'Create failed. Please try again.';
-
-			const firstKey = Object.keys(err.data.data)[0];
+			newCharErrorText = err?.data?.data?.message ?? err?.data?.message ?? 'Create failed. Please try again.';
+
+			const fieldErrors = err?.data?.data ?? {};
+			const firstKey = Object.keys(fieldErrors)[0];
 			if (firstKey) {
-				const friendlyMessage = `${firstKey}: ${err.data.data[firstKey].message}`;
+				const friendlyMessage = `${firstKey}: ${fieldErrors[firstKey].message}`;
 				console.error(friendlyMessage);
 				newCharErrorText = friendlyMessage;
 				return;
 			}
 		}

Note: the same pattern also exists in createCP (lines 53-63); consider applying the same guard there.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/routes/create/`+page.svelte around lines 151 - 159, The catch
handler can throw if err.data.data is undefined; update the logic in the create
flow that sets newCharErrorText (and mirror the same change in createCP) to
first check that err?.data?.data is an object before calling Object.keys on it;
if it’s not present, just keep the already-set fallback (err.data.data?.message
?? 'Create failed...') and skip the Object.keys/friendlyMessage branch. Locate
the existing code that references newCharErrorText and the block using
Object.keys(err.data.data) and add an existence/type guard (e.g., if
(err?.data?.data && typeof err.data.data === 'object') { ... }) around the
Object.keys logic so no TypeError occurs for network/non-PocketBase errors.
♻️ Duplicate comments (1)
website/src/routes/edit/characters/[id]/+page.svelte (1)

57-67: ⚠️ Potential issue | 🟠 Major

Same unguarded Object.keys(err.data.data) as in create/+page.svelte.

If err.data.data is undefined (non-PocketBase error, network failure, etc.), line 60 will throw and bypass the friendly message set on line 58. Please apply the same guard suggested in the create/+page.svelte comment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/routes/edit/characters/`[id]/+page.svelte around lines 57 - 67,
The catch block that sets charErrorText uses Object.keys(err.data.data)
unguarded which will throw if err.data or err.data.data is undefined; update the
catch in the function handling the update so you first check that
err?.data?.data is an object (e.g., if (err?.data?.data && typeof err.data.data
=== 'object')) before calling Object.keys, then only build the friendlyMessage
and overwrite charErrorText when that guard passes; otherwise retain the generic
charErrorText already assigned from err.data.data?.message ?? 'Update failed.
Please try again.' (refer to charErrorText, err, and the existing Object.keys
usage).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/src/routes/edit/characters/`[id]/+page.svelte:
- Around line 33-36: The updateCharacter function is missing client-side
required-field validation—before constructing FormData and submitting, check
that newCharName and newCharDescription (and newCharOrigin if required by
schema) are non-empty, set charErrorText to a descriptive message when any are
empty, and abort (return) to avoid sending an invalid request; mirror the same
validation logic used in createCharacter so the UX matches (use the same field
checks and error messages).
- Around line 77-99: The normalization logic around rawTags may fall through and
leave charTags unchanged; update the block around the try/catch that inspects
rawTags so every path assigns a safe default to charTags: after the string/array
handling add an explicit else that sets charTags = rawTags ? [rawTags] : [];
and/or initialize charTags = [] before the try so non-string/non-array values
(including null/undefined) cannot leave the previous value; reference the
variables rawTags and charTags and the existing try/catch that calls JSON.parse
to locate where to add this explicit default assignment.
- Line 52: The form currently always appends owner via formData.append('owner',
pb.authStore.record!.id), which can overwrite ownership on updates; change this
so owner is only added when creating a new character (e.g., wrap the append in a
conditional like if (isNew || !character?.id) or only call it in the create
branch), and remove it from the update flow in +page.svelte so updates never
send owner back to the server.
- Around line 37-50: Remove the no-op formData.delete calls and ensure tag_names
is always sent: drop formData.delete('images') and formData.delete('tag_names'),
keep the existing images append logic (only append files when charPictures is
non-empty), and change the tag handling in the block that uses charTags so that
if charTags.length === 0 you explicitly append a clearing value for tag_names
(e.g. append('tag_names', '[]') or '' depending on your PocketBase backend)
otherwise append each tag as before; test with your PocketBase 0.26.8 to confirm
whether '[]' or '' correctly clears the JSON tag_names field.

---

Outside diff comments:
In `@website/src/routes/create/`+page.svelte:
- Around line 151-159: The catch handler can throw if err.data.data is
undefined; update the logic in the create flow that sets newCharErrorText (and
mirror the same change in createCP) to first check that err?.data?.data is an
object before calling Object.keys on it; if it’s not present, just keep the
already-set fallback (err.data.data?.message ?? 'Create failed...') and skip the
Object.keys/friendlyMessage branch. Locate the existing code that references
newCharErrorText and the block using Object.keys(err.data.data) and add an
existence/type guard (e.g., if (err?.data?.data && typeof err.data.data ===
'object') { ... }) around the Object.keys logic so no TypeError occurs for
network/non-PocketBase errors.

---

Duplicate comments:
In `@website/src/routes/edit/characters/`[id]/+page.svelte:
- Around line 57-67: The catch block that sets charErrorText uses
Object.keys(err.data.data) unguarded which will throw if err.data or
err.data.data is undefined; update the catch in the function handling the update
so you first check that err?.data?.data is an object (e.g., if (err?.data?.data
&& typeof err.data.data === 'object')) before calling Object.keys, then only
build the friendlyMessage and overwrite charErrorText when that guard passes;
otherwise retain the generic charErrorText already assigned from
err.data.data?.message ?? 'Update failed. Please try again.' (refer to
charErrorText, err, and the existing Object.keys usage).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cb1b2e7c-6e7c-44b1-a8fd-8752adf8d1c2

📥 Commits

Reviewing files that changed from the base of the PR and between 0912d25 and d9f269c.

📒 Files selected for processing (2)
  • website/src/routes/create/+page.svelte
  • website/src/routes/edit/characters/[id]/+page.svelte

Comment on lines +33 to +36
const updateCharacter = async () => {
const formData = new FormData();
charErrorText = '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing required-field validation before submit.

Unlike createCharacter (which validates newCharName/newCharDescription/newCharOrigin are non-empty), updateCharacter submits directly. A user who clears the Name or Description field and clicks Update will either get a server-side validation error or successfully persist empty required values, depending on the PocketBase schema. Mirror the create-form validation here for consistent UX.

🛡️ Proposed fix
 	const updateCharacter = async () => {
 		const formData = new FormData();
 		charErrorText = '';
+
+		if (!charName.trim() || !charDescription.trim() || !charOrigin.trim()) {
+			charErrorText = 'All fields must be filled out';
+			return;
+		}
📝 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.

Suggested change
const updateCharacter = async () => {
const formData = new FormData();
charErrorText = '';
const updateCharacter = async () => {
const formData = new FormData();
charErrorText = '';
if (!charName.trim() || !charDescription.trim() || !charOrigin.trim()) {
charErrorText = 'All fields must be filled out';
return;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/routes/edit/characters/`[id]/+page.svelte around lines 33 - 36,
The updateCharacter function is missing client-side required-field
validation—before constructing FormData and submitting, check that newCharName
and newCharDescription (and newCharOrigin if required by schema) are non-empty,
set charErrorText to a descriptive message when any are empty, and abort
(return) to avoid sending an invalid request; mirror the same validation logic
used in createCharacter so the UX matches (use the same field checks and error
messages).

Comment on lines +37 to +50
if (charPictures && charPictures.length !== 0) {
formData.delete('images')
for (let file of charPictures) {
formData.append('images', file);
}
}

formData.append('name', charName);
formData.append('description', charDescription);
formData.append('origin', charOrigin);
formData.delete('tag_names')
charTags.forEach((tag) => {
formData.append('tag_names', tag);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and inspect the file
find . -name "+page.svelte" -path "*/edit/characters/*" -type f

Repository: pdnode-team/cp

Length of output: 112


🏁 Script executed:

# Get the context around lines 37-50 of the file
cat -n "website/src/routes/edit/characters/[id]/+page.svelte" | sed -n '30,55p'

Repository: pdnode-team/cp

Length of output: 966


🏁 Script executed:

# Check if there's any PocketBase version info in the project
find . -name "package.json" -o -name "package-lock.json" -o -name "pocketbase.json" | head -5

Repository: pdnode-team/cp

Length of output: 80


🏁 Script executed:

# Let's check the package.json for dependencies and PocketBase info
cat "package.json" 2>/dev/null || cat "website/package.json" 2>/dev/null || echo "No package.json found in root"

Repository: pdnode-team/cp

Length of output: 1320


🌐 Web query:

PocketBase 0.26.8 update multi-value field empty array relations

💡 Result:

No specific changes or fixes related to multi-value (multiple relation) fields and empty array relations were made in PocketBase v0.26.x series, including any potential v0.26.8 release. The v0.26.x releases (v0.26.0 through v0.26.6 confirmed) focus on dependency updates, minor bug fixes like error serialization and OIDC support, AWS SDK replacement, and timeout adjustments, but nothing mentions relation fields or empty arrays. Multi-value relation fields in PocketBase are stored as JSON arrays of record IDs. Empty relations are represented as empty arrays []. Known past issues with multi-relations (e.g., API rules :length operator not recognizing empty strings as empty arrays, fixed in v0.16.10; multipart form binding fixed in v0.16.6) predate v0.26.x. Official docs confirm standard handling: set to [] for empty, use field+/field- modifiers for append/remove. No evidence of bugs or changes in v0.26.8 specifically addressing "empty array relations". If experiencing issues, check field defaults (toggle single/multiple to normalize), API rules, or client-side sending (e.g., empty array vs empty string).

Citations:


🌐 Web query:

PocketBase FormData update field clearing convention unset

💡 Result:

In PocketBase, record updates via the API (PATCH /api/collections/{collection}/records/{id}) are partial updates: only fields explicitly included in the request body are processed and potentially changed. Fields omitted from the FormData or JSON body retain their existing database values unchanged. To intentionally clear or unset a field during an update (set it to null/empty/zero-value), explicitly include it in the request body with the desired clearing value: - For most scalar fields (text, number, etc.): use empty string "" or null (if the field supports null and is not required). - For file fields: use empty string "" or [] (empty array) when using FormData to clear all files. Examples from official docs: formData.append('documents', '') or { 'documents': [] }. - For JSON fields: send null, empty object {}, or empty array [] as appropriate. - For relations and arrays: use [] for empty, or field- modifier (e.g., 'tags-': ['id1']) to remove specific items. This behavior is confirmed in the RecordUpsert form source code, where only submitted fields (via Load(data)) call record.SetIfFieldExists(k, v), leaving omitted fields untouched. Official file handling docs explicitly state setting file fields to empty string/[] in FormData clears them. JS SDK examples and API reference show update(body) processes only provided fields. Example clearing a text field with FormData: const formData = new FormData; formData.append('title', ''); // clears title formData.append('otherField', 'keep this'); await pb.collection('example').update('RECORD_ID', formData); Omitting 'title' entirely would leave it unchanged.

Citations:


🏁 Script executed:

# Check if there's any local documentation or examples in the repo about PocketBase usage
find . -name "*.md" -o -name "*.txt" | xargs grep -l "pocketbase\|PocketBase" 2>/dev/null | head -5

Repository: pdnode-team/cp

Length of output: 40


🏁 Script executed:

# Look for any other places where FormData is used with PocketBase update calls to see patterns
rg "formData\.(append|delete)" -A 2 -B 2 --type svelte

Repository: pdnode-team/cp

Length of output: 88


🏁 Script executed:

# Look for any backend/schema files that might define field types
find . -name "*.go" -o -name "*.pb" -o -name "schema*" -o -name "*.sql" | head -10

Repository: pdnode-team/cp

Length of output: 421


🏁 Script executed:

# Search for any references to 'tag_names' or 'images' fields to understand their types
rg "tag_names|images" -t svelte -B 3 -A 3 | head -50

Repository: pdnode-team/cp

Length of output: 88


🏁 Script executed:

# Check if there's any documentation about the character collection schema
find . -name "*.md" | xargs grep -l "tag_names\|character.*schema" 2>/dev/null | head -5

Repository: pdnode-team/cp

Length of output: 40


🏁 Script executed:

# Look for any API route handlers or backend setup that might define fields
find . -type f -name "*.ts" -o -name "*.js" | xargs grep -l "characters\|collection" 2>/dev/null | head -10

Repository: pdnode-team/cp

Length of output: 40


🏁 Script executed:

# Examine the character creation migration
cat -n "./migrations/1776132769_created_characters.go"

Repository: pdnode-team/cp

Length of output: 5073


🏁 Script executed:

# Examine the latest character update migration
cat -n "./migrations/1776489282_updated_characters.go"

Repository: pdnode-team/cp

Length of output: 2362


formData.delete(...) calls are no-ops on a freshly constructed FormData.

formData is created on line 34 and nothing is appended to images or tag_names before the delete() calls on lines 38 and 47. Both deletions do nothing. PocketBase performs partial updates—only fields explicitly included in the request are processed; omitted fields retain their existing values.

Current behavior:

  • Uploading no new pictures leaves existing images untouched (likely intentional, but the delete is dead code).
  • Removing all tags (charTags = []) will NOT clear them on the server because tag_names is never appended to FormData when the array is empty, leaving existing tags unchanged.

The tag_names field (JSON type) must always be sent to replace its value on the server. When charTags is empty, explicitly append an empty value to FormData to clear the field:

♻️ Suggested fix
 		if (charPictures && charPictures.length !== 0) {
-            formData.delete('images')
 			for (let file of charPictures) {
 				formData.append('images', file);
 			}
 		}
 
 		formData.append('name', charName);
 		formData.append('description', charDescription);
 		formData.append('origin', charOrigin);
-        formData.delete('tag_names')
-		charTags.forEach((tag) => {
-			formData.append('tag_names', tag);
-		});
+		// Always send tag_names to replace the value, even when empty.
+		if (charTags.length === 0) {
+			formData.append('tag_names', '');
+		} else {
+			charTags.forEach((tag) => formData.append('tag_names', tag));
+		}

Verify with your PocketBase 0.26.8 backend whether an empty string (''), empty JSON array ('[]'), or another format correctly clears the JSON tag_names field during updates.

📝 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.

Suggested change
if (charPictures && charPictures.length !== 0) {
formData.delete('images')
for (let file of charPictures) {
formData.append('images', file);
}
}
formData.append('name', charName);
formData.append('description', charDescription);
formData.append('origin', charOrigin);
formData.delete('tag_names')
charTags.forEach((tag) => {
formData.append('tag_names', tag);
});
if (charPictures && charPictures.length !== 0) {
for (let file of charPictures) {
formData.append('images', file);
}
}
formData.append('name', charName);
formData.append('description', charDescription);
formData.append('origin', charOrigin);
// Always send tag_names to replace the value, even when empty.
if (charTags.length === 0) {
formData.append('tag_names', '');
} else {
charTags.forEach((tag) => formData.append('tag_names', tag));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/routes/edit/characters/`[id]/+page.svelte around lines 37 - 50,
Remove the no-op formData.delete calls and ensure tag_names is always sent: drop
formData.delete('images') and formData.delete('tag_names'), keep the existing
images append logic (only append files when charPictures is non-empty), and
change the tag handling in the block that uses charTags so that if
charTags.length === 0 you explicitly append a clearing value for tag_names (e.g.
append('tag_names', '[]') or '' depending on your PocketBase backend) otherwise
append each tag as before; test with your PocketBase 0.26.8 to confirm whether
'[]' or '' correctly clears the JSON tag_names field.

formData.append('tag_names', tag);
});

formData.append('owner', pb.authStore.record!.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Overwriting owner on every update is risky.

This unconditionally sets owner to the currently authenticated user's id. If a user with edit permission (e.g. an admin or a future shared-edit feature) updates a character they don't own, this silently transfers ownership. Even for the common case where the editor is the owner, sending owner on update is unnecessary and expands the attack surface (a misconfigured update rule on the server could let a non-owner take ownership).

Consider simply not sending owner on update — it should be immutable after creation, enforced by PocketBase collection rules.

-		formData.append('owner', pb.authStore.record!.id);
📝 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.

Suggested change
formData.append('owner', pb.authStore.record!.id);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/routes/edit/characters/`[id]/+page.svelte at line 52, The form
currently always appends owner via formData.append('owner',
pb.authStore.record!.id), which can overwrite ownership on updates; change this
so owner is only added when creating a new character (e.g., wrap the append in a
conditional like if (isNew || !character?.id) or only call it in the create
branch), and remove it from the update flow in +page.svelte so updates never
send owner back to the server.

Comment thread website/src/routes/edit/characters/[id]/+page.svelte
@BretRen BretRen merged commit 930bbb7 into main Apr 20, 2026
1 check passed
@BretRen BretRen deleted the feat/update-chars branch April 20, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant