Skip to content

Add Web Viewer container uploads - #300

Merged
eluce2 merged 4 commits into
mainfrom
feature/webviewer-container-upload
Aug 10, 2026
Merged

Add Web Viewer container uploads#300
eluce2 merged 4 commits into
mainfrom
feature/webviewer-container-upload

Conversation

@eluce2

@eluce2 eluce2 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Implement containerUpload in WebViewerAdapter with Base64 encoding and configurable script options.
  • Add size, timeout, filename, repetition, and FileMaker error handling.
  • Add comprehensive container upload tests and documentation.
  • Add PK_container_upload FileMaker script contract.

Testing

  • Added adapter tests for uploads, custom scripts, size limits, timeouts, repetitions, filenames, and errors.
  • pnpm run ci not run.

Summary by CodeRabbit

  • New Features

    • Added support for uploading files to FileMaker container fields from Web Viewer apps.
    • Added configurable upload scripts, timeouts, and maximum file sizes.
    • Added validation for filenames, file repetitions, file size, and upload responses.
  • Documentation

    • Added comprehensive guidance for reading, displaying, and uploading container data.
    • Documented native FileMaker and OttoFMS upload workflows, security considerations, and compatibility requirements.
    • Added the Containers guide to Web Viewer documentation navigation.

- Document container read and write workflows
- Add upload limits, timeout, and script configuration
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
proofkit-docs Ready Ready Preview Aug 10, 2026 4:42pm

Request Review

@changeset-bot

changeset-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b4dbd5b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@proofkit/webviewer Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Aug 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@proofkit/better-auth

pnpm add https://pkg.pr.new/@proofkit/better-auth@300

@proofkit/fmdapi

pnpm add https://pkg.pr.new/@proofkit/fmdapi@300

@proofkit/fmodata

pnpm add https://pkg.pr.new/@proofkit/fmodata@300

@proofkit/typegen

pnpm add https://pkg.pr.new/@proofkit/typegen@300

@proofkit/webviewer

pnpm add https://pkg.pr.new/@proofkit/webviewer@300

commit: f167648

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds configurable Base64 container uploads to WebViewerAdapter, defines the PK_container_upload FileMaker script contract, adds validation and timeout tests, and documents container read, write, rendering, native FileMaker, and OttoFMS workflows.

Changes

Container upload support

Layer / File(s) Summary
FileMaker upload script contract
packages/webviewer/specs/container-upload-script.md
Defines upload envelopes, record navigation, container writes, callbacks, cleanup, error codes, found-set handling, unresolved questions, and test cases.
Adapter upload implementation
packages/webviewer/src/adapter.ts
Adds configurable script, timeout, and file-size options. The adapter validates inputs, encodes files, invokes the FileMaker script, handles timeouts, and validates responses.
Upload behavior validation and release metadata
packages/webviewer/tests/adapter.test.ts, .changeset/webviewer-container-upload.md
Tests payload construction, script selection, FileMaker failures, local validation, size limits, and timeout handling. The changeset documents the minor release.
Container workflows documentation
apps/docs/content/docs/webviewer/containers.mdx, apps/docs/content/docs/webviewer/meta.json, apps/docs/content/docs/webviewer/runtime-under-the-hood.mdx
Documents container uploads, reads, rendering, custom writes, native FileMaker workflows, OttoFMS uploads, sizing, caching, and navigation links.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WebViewerApp
  participant WebViewerAdapter
  participant PK_container_upload
  WebViewerApp->>WebViewerAdapter: Call containerUpload with file and record metadata
  WebViewerAdapter->>WebViewerAdapter: Validate and encode the file
  WebViewerAdapter->>PK_container_upload: Send record metadata and Base64 payload
  PK_container_upload-->>WebViewerAdapter: Return success or FileMaker error
  WebViewerAdapter-->>WebViewerApp: Resolve or reject the upload
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding container upload support to the Web Viewer.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/webviewer-container-upload

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (4)
packages/webviewer/src/adapter.ts (1)

90-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use arrow functions for the short helper functions.

Convert containerTimeoutMessage, blobToBase64, getUploadFileName, resolveContainerRepetition, and resolveContainerOptions to const arrow functions.

As per coding guidelines, use arrow functions for callbacks and short functions.

Also applies to: 113-162

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 90 - 92, Convert the short
helper functions containerTimeoutMessage, blobToBase64, getUploadFileName,
resolveContainerRepetition, and resolveContainerOptions from function
declarations to const-assigned arrow functions, preserving their parameters,
return types, and existing behavior.

Source: Coding guidelines

apps/docs/content/docs/webviewer/containers.mdx (2)

202-209: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Replace the indexed loop in the sample.

The coding guidelines prefer for...of over indexed for loops. Uint8Array.from removes the loop entirely and keeps the sample shorter.

♻️ Proposed refactor
 export function base64ToBlobUrl(base64: string, mimeType: string) {
   const binary = atob(base64);
-  const bytes = new Uint8Array(binary.length);
-  for (let index = 0; index < binary.length; index++) {
-    bytes[index] = binary.charCodeAt(index);
-  }
+  const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
   return URL.createObjectURL(new Blob([bytes], { type: mimeType }));
 }

As per coding guidelines: "Prefer for...of loops over .forEach() and indexed for loops".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/content/docs/webviewer/containers.mdx` around lines 202 - 209,
Update base64ToBlobUrl to remove the indexed loop by constructing the Uint8Array
with Uint8Array.from over the decoded binary string, preserving the existing
byte conversion and Blob URL behavior.

Source: Coding guidelines


58-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Scope the table rows to container.*.

scriptName is also a top-level Data API option. Prefix the rows with container.. The adapter defaults and 0 semantics match the documented values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/content/docs/webviewer/containers.mdx` around lines 58 - 62, Update
the option names in the table to use the container namespace: rename scriptName,
timeoutMs, and maxFileBytes to container.scriptName, container.timeoutMs, and
container.maxFileBytes while preserving their existing defaults and notes.
packages/webviewer/tests/adapter.test.ts (1)

817-831: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Extract the container timeout into a named constant.

beforeEach already enables fake timers. Use a timeoutMs constant for both the adapter configuration and vi.advanceTimersByTimeAsync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/tests/adapter.test.ts` around lines 817 - 831, Define a
named timeoutMs constant within the “times out with an add-on upgrade hint when
the script never calls back” test, then reuse it for the adapter’s
container.timeoutMs configuration and vi.advanceTimersByTimeAsync call instead
of duplicating the literal value.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/webviewer-container-upload.md:
- Line 2: Run pnpm run ci from the repository root before completing the
changes, and resolve any formatting, lint, or TypeScript type-check failures
reported for the webviewer and documentation updates.

In `@apps/docs/content/docs/webviewer/containers.mdx`:
- Around line 262-268: Update the sample script’s success branch after Set Field
so Get ( LastError ) is captured immediately before Commit Records/Requests, and
use that captured value to determine ok and error. Preserve the not-found
branch, and emit the error field only when the captured error is nonzero rather
than setting it to 0 on success.
- Around line 311-330: Declare or import OTTO_DATA_API_KEY in the otto-upload.ts
sample before uploadViaOttoFMS, showing that it is supplied through the
application’s public configuration or initial props. Keep the existing fetch
authorization usage unchanged and ensure copied code does not reference an
undefined value.
- Line 332: Update the OttoFMS upload description to use the storage pattern
Data/Documents/otto/:channel/:uuid/filename, remove the claim that uploads are
deleted after 24 hours, and extend the uploaded_files entry fields with
filename, fieldname, encoding, and destination while preserving the valid
OttoReceiver, existing fields, and file-insertion guidance.

In `@packages/webviewer/specs/container-upload-script.md`:
- Line 100: Update the fenced code block in the container upload script
documentation to specify the text language identifier, resolving the
markdownlint warning while preserving the existing FileMaker pseudocode content.
- Around line 103-127: Complete the script flow around the envelope parsing and
callback construction by extracting and validating modId and repetition,
resolving the empty webViewerName fallback, and assigning $result with code "0"
only after successful navigation, field write, and commit; otherwise build the
documented failure envelope. Ensure every failure path closes the temporary
window before invoking SendCallBack, and preserve the callback contract expected
by WebViewerAdapter.handleDataApiResponse().

In `@packages/webviewer/src/adapter.ts`:
- Around line 126-134: Update getUploadFileName to require a nonempty extension
after the filename’s final dot before returning fileName. Reject names without a
final dot or with no characters after it, while preserving the existing
validation for missing or blank filenames and its error behavior.
- Around line 665-669: Update the timeout handling in the containerUpload flow
around withTimeout so a local timeout reports an unknown upload outcome rather
than claiming the FileMaker script did not respond, while preserving the
existing timeout behavior. In
packages/webviewer/specs/container-upload-script.md:155-159, define a request
identity with idempotency or status lookup semantics so delayed completion can
be reconciled and callers do not retry unsafely; update both sites as part of
the same contract.

---

Nitpick comments:
In `@apps/docs/content/docs/webviewer/containers.mdx`:
- Around line 202-209: Update base64ToBlobUrl to remove the indexed loop by
constructing the Uint8Array with Uint8Array.from over the decoded binary string,
preserving the existing byte conversion and Blob URL behavior.
- Around line 58-62: Update the option names in the table to use the container
namespace: rename scriptName, timeoutMs, and maxFileBytes to
container.scriptName, container.timeoutMs, and container.maxFileBytes while
preserving their existing defaults and notes.

In `@packages/webviewer/src/adapter.ts`:
- Around line 90-92: Convert the short helper functions containerTimeoutMessage,
blobToBase64, getUploadFileName, resolveContainerRepetition, and
resolveContainerOptions from function declarations to const-assigned arrow
functions, preserving their parameters, return types, and existing behavior.

In `@packages/webviewer/tests/adapter.test.ts`:
- Around line 817-831: Define a named timeoutMs constant within the “times out
with an add-on upgrade hint when the script never calls back” test, then reuse
it for the adapter’s container.timeoutMs configuration and
vi.advanceTimersByTimeAsync call instead of duplicating the literal value.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 42272634-5c91-4930-87e4-d3bb281eea8a

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba2d6d and 81d5f15.

📒 Files selected for processing (7)
  • .changeset/webviewer-container-upload.md
  • apps/docs/content/docs/webviewer/containers.mdx
  • apps/docs/content/docs/webviewer/meta.json
  • apps/docs/content/docs/webviewer/runtime-under-the-hood.mdx
  • packages/webviewer/specs/container-upload-script.md
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts

Comment thread .changeset/webviewer-container-upload.md
Comment on lines +262 to +268
If [ Get ( FoundCount ) = 0 ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; "Record not found" ; JSONString ] ) ]
Else
Set Field [ Customers::Photo ; Base64Decode ( $base64 ; $fileName ) ]
Commit Records/Requests [ With dialog: Off ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; Get ( LastError ) = 0 ; JSONBoolean ] ; [ "error" ; Get ( LastError ) ; JSONNumber ] ) ]
End If

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The sample script reports success when Set Field fails.

The script captures Get ( LastError ) only after Commit Records/Requests. If Base64Decode or the Set Field step fails, the commit can still return 0, so the script returns ok: true. Capture the error right after Set Field.

The script also sets error to 0 on success. Set error only on failure so the documented error?: number | string type stays meaningful.

🐛 Proposed fix for the sample script
 If [ Get ( FoundCount ) = 0 ]
   Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; "Record not found" ; JSONString ] ) ]
 Else
   Set Field [ Customers::Photo ; Base64Decode ( $base64 ; $fileName ) ]
+  Set Variable [ $error ; Value: Get ( LastError ) ]
   Commit Records/Requests [ With dialog: Off ]
-  Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; Get ( LastError ) = 0 ; JSONBoolean ] ; [ "error" ; Get ( LastError ) ; JSONNumber ] ) ]
+  If [ $error = 0 ]
+    Set Variable [ $error ; Value: Get ( LastError ) ]
+  End If
+  If [ $error = 0 ]
+    Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; True ; JSONBoolean ] ) ]
+  Else
+    Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; $error ; JSONNumber ] ) ]
+  End If
 End If
📝 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 [ Get ( FoundCount ) = 0 ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; "Record not found" ; JSONString ] ) ]
Else
Set Field [ Customers::Photo ; Base64Decode ( $base64 ; $fileName ) ]
Commit Records/Requests [ With dialog: Off ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; Get ( LastError ) = 0 ; JSONBoolean ] ; [ "error" ; Get ( LastError ) ; JSONNumber ] ) ]
End If
If [ Get ( FoundCount ) = 0 ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; "Record not found" ; JSONString ] ) ]
Else
Set Field [ Customers::Photo ; Base64Decode ( $base64 ; $fileName ) ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Commit Records/Requests [ With dialog: Off ]
If [ $error = 0 ]
Set Variable [ $error ; Value: Get ( LastError ) ]
End If
If [ $error = 0 ]
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; True ; JSONBoolean ] ) ]
Else
Set Variable [ $result ; Value: JSONSetElement ( "" ; [ "ok" ; False ; JSONBoolean ] ; [ "error" ; $error ; JSONNumber ] ) ]
End If
End If
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/content/docs/webviewer/containers.mdx` around lines 262 - 268,
Update the sample script’s success branch after Set Field so Get ( LastError )
is captured immediately before Commit Records/Requests, and use that captured
value to determine ok and error. Preserve the not-found branch, and emit the
error field only when the captured error is nonzero rather than setting it to 0
on success.

Comment thread apps/docs/content/docs/webviewer/containers.mdx
}
```

OttoFMS saves the upload under the server's `Documents/otto/{uuid}/` folder and runs your `OttoReceiver` script with an `uploaded_files` array in the payload. Each entry carries `originalname`, `mimetype`, `size`, and `path`. The script uses `path` to pull the file into a container with `Insert File` or `Insert PDF`. Uploads are deleted after 24 hours, so move the file into the solution on receipt.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

OttoFMS webhook file receiver uploaded_files path retention

💡 Result:

In OttoFMS, when files are uploaded via the file receiver endpoint, they are stored in the FileMaker Server's document directory at the following path: fms-server-path/Data/Documents/otto/:channel/:uuid/filename [1]. Regarding file retention, OttoFMS does not provide built-in automated cleanup or expiration policies for files uploaded to this specific directory [1]. Because these files are saved to the server's filesystem, they will remain there indefinitely unless they are manually managed or programmatically deleted by your own processes [1]. It is recommended practice to process these files immediately after the webhook is received—typically by using a script to import the file into a FileMaker container field—and then remove the file from the server's filesystem once the import is complete to prevent the server's storage from filling up [1].

Citations:


🌐 Web query:

site:v3.ottofms.com/docs/otto/working-with-otto/receiving-web-hooks OttoReceiver uploaded_files originalname mimetype size path

💡 Result:

OttoReceiver is a component of Otto, a tool by Proof+Geist designed for Claris FileMaker, used for managing webhooks and file uploads [1]. When files are uploaded via a webhook in Otto, the system automatically adds an uploaded_files array to the webhook payload [1]. This array contains metadata for each file processed, including the following properties [1]: - originalname: The original name of the file as it was uploaded [1]. - mimetype: The MIME type of the uploaded file (e.g., text/markdown) [1]. - size: The size of the file in bytes [1]. - path: The full file system path where the uploaded file is stored on the server [1]. - filename: The name of the file as saved in the destination directory [1]. - fieldname: The name of the form field used to upload the file [1]. - encoding: The encoding type of the file [1]. - destination: The directory path where the file was saved [1]. Developers typically use this information within FileMaker scripts to import the files from the specified path into container fields [1].

Citations:


Correct the OttoFMS file receiver details.

Use Data/Documents/otto/:channel/:uuid/filename for the storage path. Remove the 24-hour deletion claim because OttoFMS does not automatically expire these files. OttoReceiver and the listed uploaded_files fields are valid; the payload also includes filename, fieldname, encoding, and destination.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/content/docs/webviewer/containers.mdx` at line 332, Update the
OttoFMS upload description to use the storage pattern
Data/Documents/otto/:channel/:uuid/filename, remove the claim that uploads are
deleted after 24 hours, and extend the uploaded_files entry fields with
filename, fieldname, encoding, and destination while preserving the valid
OttoReceiver, existing fields, and file-insertion guidance.

Comment thread packages/webviewer/specs/container-upload-script.md Outdated
Comment on lines +103 to +127
# 1. Parse the envelope
Set Variable [ $json ; Value: Get ( ScriptParameter ) ]
Set Variable [ $callback ; Value: JSONGetElement ( $json ; "callback" ) ]
Set Variable [ $data ; Value: JSONGetElement ( $json ; "data" ) ]
Set Variable [ $webViewerName ; Value: JSONGetElement ( $callback ; "webViewerName" ) ]
Set Variable [ $layout ; Value: JSONGetElement ( $data ; "layout" ) ]
Set Variable [ $recordId ; Value: JSONGetElement ( $data ; "recordId" ) ]
Set Variable [ $fieldName ; Value: JSONGetElement ( $data ; "containerFieldName" ) ]
Set Variable [ $fileName ; Value: JSONGetElement ( $data ; "fileName" ) ]
Set Variable [ $base64 ; Value: JSONGetElement ( $data ; "base64" ) ]

# 2. Navigate by record ID, in a new window
Go to List of Records [ List of record IDs: $recordId ; Using layout: $layout ; Show in new window: On ; Animation: None ]

# 3. Verify, then write
Set Variable [ $fullFieldName ; Value: Get ( LayoutTableName ) & "::" & $fieldName ]
Set Field By Name [ $fullFieldName ; Base64Decode ( $base64 ; $fileName ) ]
Commit Records/Requests [ With dialog: Off ]

# 4. Close the window, then call back
Close Window [ Current Window ]
Set Variable [ $callback ; Value: JSONSetElement ( $callback ;
[ "result" ; $result ; JSONObject ] ;
[ "webViewerName" ; $webViewerName ; JSONString ] ) ]
Perform Script [ Specified: From list ; "SendCallBack" ; Parameter: $callback ]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Complete the script flow before using this contract.

The flow never assigns $result. WebViewerAdapter.handleDataApiResponse() requires messages[0].code to equal "0", so a successful write based on this flow still rejects in JavaScript.

Parse and validate modId and repetition. Check navigation, field-write, and commit errors. Build the documented success or failure envelope in $result. Resolve the empty webViewerName fallback before SendCallBack. Route every failure through window cleanup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/specs/container-upload-script.md` around lines 103 - 127,
Complete the script flow around the envelope parsing and callback construction
by extracting and validating modId and repetition, resolving the empty
webViewerName fallback, and assigning $result with code "0" only after
successful navigation, field write, and commit; otherwise build the documented
failure envelope. Ensure every failure path closes the temporary window before
invoking SendCallBack, and preserve the callback contract expected by
WebViewerAdapter.handleDataApiResponse().

Comment thread packages/webviewer/src/adapter.ts Outdated
Comment thread packages/webviewer/src/adapter.ts
- Report unknown outcomes with ContainerUploadTimeoutError
- Tighten file-name validation and document retry behavior
- Clarify built-in uploads and custom reads
- Streamline FileMaker and browser examples
- Document version requirements and container handling

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/docs/content/docs/webviewer/containers.mdx`:
- Around line 30-38: Update the warning text in the containerUpload
prerequisites to replace the inaccurate quoted older-add-on error with the
actual WebViewerAdapter behavior: older add-ons reject with
ContainerUploadTimeoutError after the configured timeout. Keep the
`@proofkit/webviewer` 3.3.0 and FileMaker Pro 22.0 requirements unchanged.

In `@packages/webviewer/specs/container-upload-script.md`:
- Around line 141-145: Update the upload error-handling flow around Set Field By
Name and Commit Records/Requests to capture Get ( LastErrorText ) immediately
after the field update, preserve it through the commit, and replace it with the
commit error text if the commit fails. Pass the captured error message to
PK_error instead of an empty string.
- Around line 123-128: Update the error handling after “Go to List of Records”
to preserve navigation error codes: return 105 with “Layout is missing” when
$error is 105, return 101 with “Record is missing” only when the found set is
empty or the record is missing, and pass through all other nonzero navigation
errors using their actual codes and messages.
- Around line 136-145: Update the upload flow around Set Field By Name to decode
Base64 into a variable before modifying the container. Reject decoded values
equal to “?” or empty by setting result to PK_error with code 500, and only
execute Set Field By Name and Commit Records/Requests for valid decoded data;
preserve the existing post-commit error handling for valid inputs.
- Around line 118-119: Update the repetition parsing near $repetition to reject
invalid values and values greater than 1 before navigation instead of clamping
them with Max ( 1 ; ... ). Preserve repetition 1 for supported requests, and
ensure invalid or unsupported input exits through the script’s existing
rejection path; do not append a repetition qualifier unless implementing full
repetition support in $fullFieldName.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a1d2182b-74b4-481a-b072-58c5c084d84b

📥 Commits

Reviewing files that changed from the base of the PR and between 81d5f15 and f167648.

📒 Files selected for processing (5)
  • .changeset/webviewer-container-upload.md
  • apps/docs/content/docs/webviewer/containers.mdx
  • packages/webviewer/specs/container-upload-script.md
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .changeset/webviewer-container-upload.md
  • packages/webviewer/tests/adapter.test.ts
  • packages/webviewer/src/adapter.ts

Comment thread apps/docs/content/docs/webviewer/containers.mdx Outdated
Comment thread packages/webviewer/specs/container-upload-script.md Outdated
Comment thread packages/webviewer/specs/container-upload-script.md Outdated
Comment thread packages/webviewer/specs/container-upload-script.md Outdated
Comment thread packages/webviewer/specs/container-upload-script.md Outdated
- Validate repetition and decode failures
- Preserve FileMaker error details
- Update container upload docs and tests
@eluce2
eluce2 merged commit c94b338 into main Aug 10, 2026
13 of 15 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/webviewer/specs/container-upload-script.md (2)

139-142: 🗄️ Data Integrity & Integration | 🟠 Major

Map a no-match navigation result to code 101.

Go to List of Records can return 401 when the requested record ID is missing. The $error ≠ 0 branch runs before the FoundCount = 0 check, so the script can return 401 instead of the contract’s 101 missing-record response.

Check FoundCount = 0 for the documented missing-record results before generic error pass-through. Preserve 105 and other genuine navigation errors. (help.claris.com)

Suggested correction
-  Else If [ $error ≠ 0 ]
-    Set Variable [ $result ; Value: PK_error ( $error ; $errorMessage ) ]
-  Else If [ Get ( FoundCount ) = 0 ]
+  Else If [ Get ( FoundCount ) = 0 and ( $error = 0 or $error = 401 ) ]
     Set Variable [ $result ; Value: PK_error ( 101 ; "Record is missing" ) ]
+  Else If [ $error ≠ 0 ]
+    Set Variable [ $result ; Value: PK_error ( $error ; $errorMessage ) ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/specs/container-upload-script.md` around lines 139 - 142,
Reorder the result handling so the Get ( FoundCount ) = 0 check maps
missing-record navigation results, including error 401, to PK_error ( 101 ;
"Record is missing" ) before the generic $error ≠ 0 pass-through. Preserve 105
and other genuine navigation errors by only applying the 101 mapping to the
documented no-match result.

Source: MCP tools


143-143: 🗄️ Data Integrity & Integration | 🟠 Major

Reject malformed modId values before comparison.

GetAsNumber ( $modId ) removes non-numeric characters. A value such as "1abc" can become 1 and pass the modification check when the current modification count is 1.

Require a JSON number with the contract’s integer semantics before comparing it. Return an invalid-request error for malformed values. Claris documents this coercion behavior. (help.claris.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/specs/container-upload-script.md` at line 143, Validate
the `modId` extracted by `JSONGetElement` as a contract-compliant JSON integer
before the `Get ( RecordModificationCount )` comparison in the upload-script
conditional. Reject malformed or non-integer values with the existing
invalid-request error path, and only call `GetAsNumber ( $modId )` after
validation so strings such as `"1abc"` cannot be accepted.

Source: MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/webviewer/specs/container-upload-script.md`:
- Around line 118-120: Update the repetition validation around $repetitionInput,
$repetitionType, and $repetitionIsValid to detect whether the “repetition” key
exists using JSONListKeys instead of treating JSONGetElementType error text as
absence. Accept an omitted key, while requiring present values to have
JSONNumber type and numeric value 1.

---

Duplicate comments:
In `@packages/webviewer/specs/container-upload-script.md`:
- Around line 139-142: Reorder the result handling so the Get ( FoundCount ) = 0
check maps missing-record navigation results, including error 401, to PK_error (
101 ; "Record is missing" ) before the generic $error ≠ 0 pass-through. Preserve
105 and other genuine navigation errors by only applying the 101 mapping to the
documented no-match result.
- Line 143: Validate the `modId` extracted by `JSONGetElement` as a
contract-compliant JSON integer before the `Get ( RecordModificationCount )`
comparison in the upload-script conditional. Reject malformed or non-integer
values with the existing invalid-request error path, and only call `GetAsNumber
( $modId )` after validation so strings such as `"1abc"` cannot be accepted.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 122e7c26-5f2a-4553-aad2-33da62919601

📥 Commits

Reviewing files that changed from the base of the PR and between f167648 and b4dbd5b.

📒 Files selected for processing (4)
  • apps/docs/content/docs/webviewer/containers.mdx
  • packages/webviewer/specs/container-upload-script.md
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/webviewer/tests/adapter.test.ts
  • packages/webviewer/src/adapter.ts
  • apps/docs/content/docs/webviewer/containers.mdx

Comment on lines +118 to +120
Set Variable [ $repetitionInput ; Value: JSONGetElement ( $data ; "repetition" ) ]
Set Variable [ $repetitionType ; Value: JSONGetElementType ( $data ; "repetition" ) ]
Set Variable [ $repetitionIsValid ; Value: ( IsEmpty ( $repetitionInput ) and IsEmpty ( $repetitionType ) ) or ( $repetitionType = JSONNumber and GetAsNumber ( $repetitionInput ) = 1 ) ]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target lines ---'
sed -n '100,135p' packages/webviewer/specs/container-upload-script.md
printf '%s\n' '--- relevant function usage ---'
rg -n -C 3 'JSONGetElementType|JSONListKeys|repetitionIsValid|repetitionPresent|Go to List of Records|modId|Modification' packages/webviewer/specs/container-upload-script.md
printf '%s\n' '--- repository references ---'
rg -n -i 'JSONGetElementType|JSONListKeys|repetition' packages/webviewer/specs --glob '*.md'

Repository: proofsh/proofkit

Length of output: 10537


🌐 Web query:

Claris FileMaker Pro JSONGetElementType missing path error text JSONListKeys key presence documentation

💡 Result:

In Claris FileMaker Pro, the behavior of JSON functions when encountering missing or invalid paths is standardized as follows: JSONGetElementType Error Behavior When you use the JSONGetElementType function, if the provided key, index, or path does not exist in the JSON data, the function returns the error text: "? Incorrect key, index, or path" [1][2][3]. JSONListKeys and Key Presence The JSONListKeys function does not explicitly return an error text when a path is missing; instead, if the path is invalid or does not exist, it typically returns an empty string. To determine if a specific key or path exists before performing operations, the best practice is to use JSONGetElementType [4]. By checking the return value of JSONGetElementType against your expected data type (e.g., JSONObject, JSONString), you can programmatically verify the presence of a key [4]. Technical Documentation Notes - Path Notation: The keyOrIndexOrPath parameter supports object names, array indexes, or dot/bracket notation (e.g., "bakery.product.id") [1][5][6]. - Error Handling: If the main JSON input is invalid (i.e., not valid JSON), FileMaker JSON functions will return "?" followed by a specific error message from the JSON parser [4]. - Empty Path: Providing an empty string ("") as the keyOrIndexOrPath parameter targets the root of the JSON structure [7][4][5]. For robust development, always validate the path using JSONGetElementType before relying on subsequent functions like JSONGetElement or JSONListKeys to prevent unexpected results [4].

Citations:


Handle an omitted repetition as absent.

JSONGetElementType ( $data ; "repetition" ) returns error text for a missing path. Therefore, Line 120 rejects the omitted optional field instead of using the default value.

Detect key presence separately with JSONListKeys. Then accept omission or require JSON number 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/specs/container-upload-script.md` around lines 118 - 120,
Update the repetition validation around $repetitionInput, $repetitionType, and
$repetitionIsValid to detect whether the “repetition” key exists using
JSONListKeys instead of treating JSONGetElementType error text as absence.
Accept an omitted key, while requiring present values to have JSONNumber type
and numeric value 1.

Source: MCP tools

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