Skip to content

fmFetch throws synchronously when window.FileMaker isn't injected yet at startup #288

@atorresnavarro

Description

@atorresnavarro

Summary

fmFetch (via callFMScript) throws synchronously when window.FileMaker is not yet present:

Could not call script, 'GetInitialProps'. 'window.FileMaker' was not available at the time this function was called.

This makes the documented initial props pattern unreliable. FileMaker Pro/Go injects window.FileMaker into the web viewer asynchronously after the HTML/JS bundle has started executing. If fmFetch is called during module load or the first render — which the initial-props docs explicitly recommend ("the fmFetch call fires the moment the web code loads — before the router mounts and before the first route renders") — window.FileMaker can still be undefined, and the call throws instead of waiting.

Environment

  • @proofkit/webviewer: 3.1.0
  • Host: FileMaker Pro / Go web viewer (single-file Vite build, hash-history router)
  • Framework: React 19 + TanStack Router (but not framework-specific)

Source

dist/esm/main.jscallFMScript:

if (!window.FileMaker) {
  throw new Error(
    `Could not call script, '${scriptName}'. 'window.FileMaker' was not available at the time this function was called.`
  );
}

There is no wait/retry — a single synchronous existence check. fmFetch resolves only via window.handleFmWVFetchCallback (called by the FileMaker SendCallBack script), so when the throw is caught upstream the script is never invoked at all.

Reproduction

  1. Scaffold a ProofKit web viewer app (React + TanStack Router hash history).
  2. Follow the initial-props pattern: call fmFetch("GetInitialProps") at startup (module scope / before first render).
  3. Build the single-file HTML and load it in a FileMaker Pro/Go web viewer where the host injects window.FileMaker slightly after the bundle begins executing.
  4. Observe: fmFetch throws the error above; GetInitialProps is never called (confirmed via the FileMaker Script Debugger).

The timing is environment-dependent — on machines/files where window.FileMaker is injected before the bundle runs it works, which makes it an intermittent, hard-to-diagnose failure.

Expected behavior

fmFetch should tolerate window.FileMaker not yet being present at call time, given the docs recommend calling it at startup. Options:

  • Internally poll/await window.FileMaker for a bounded timeout before calling PerformScript, then reject if it never appears.
  • Or expose a readiness primitive (e.g. awaitFileMaker() / whenFileMakerReady()) so callers can await it without hand-rolling a window.FileMaker poll.

Actual behavior

Immediate synchronous throw; the FileMaker script is never performed.

Current workaround

Poll for window.FileMaker before calling fmFetch:

const waitForFileMaker = (timeoutMs = 10_000) =>
  new Promise<void>((resolve, reject) => {
    if (window.FileMaker) return resolve();
    const deadline = Date.now() + timeoutMs;
    const id = setInterval(() => {
      if (window.FileMaker) { clearInterval(id); resolve(); }
      else if (Date.now() >= deadline) { clearInterval(id); reject(new Error("window.FileMaker unavailable")); }
    }, 50);
  });

await waitForFileMaker();
const props = await fmFetch("GetInitialProps", {});

This requires referencing window.FileMaker directly (and declaring its global type), which the package otherwise abstracts away — ideally the package would own this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions