Loading...
Loading...
Type-safe FileMaker OData client with Drizzle-inspired ORM and TypeScript code generation. Use when working with FileMaker databases in TypeScript projects, querying FM data, defining typed schemas, generating types from FM layouts, or troubleshooting fmodata/typegen issues. Triggers on FileMaker + TypeScript integration tasks.
npx skill4agent add proofgeist/proofkit proofkit-fmodatahttps://proofkit.dev/llms/fmodatahttps://proofkit.dev/llms/typegenhttps://proofkit.dev/llms-full.txt# 1. Install packages
pnpm add @proofkit/fmodata@beta @proofkit/typegen
# 2. Create config (proofkit-typegen.config.jsonc)
npx @proofkit/typegen init
# 3. Set env vars
FM_SERVER=https://your-server.com
FM_DATABASE=YourDatabase.fmp12
OTTO_API_KEY=your-api-key # or FM_USERNAME/FM_PASSWORD
# 4. Generate types
npx @proofkit/typegen generate
# 5. Or use interactive UI
npx @proofkit/typegen uiimport { fmTableOccurrence, textField, numberField, timestampField } from "@proofkit/fmodata";
import { z } from "zod";
export const Users = fmTableOccurrence("Users", {
id: textField().primaryKey().entityId("FMFID:100001"),
name: textField().notNull(),
email: textField().notNull(),
active: numberField()
.readValidator(z.coerce.boolean())
.writeValidator(z.boolean().transform(v => v ? 1 : 0)),
createdAt: timestampField().readOnly(),
}, {
entityId: "FMTID:1000001",
navigationPaths: ["Contacts", "Orders"],
});import { FMServerConnection, eq, and, gt, asc, contains } from "@proofkit/fmodata";
const connection = new FMServerConnection({
serverUrl: process.env.FM_SERVER,
auth: { apiKey: process.env.OTTO_API_KEY }
});
const db = connection.database("MyDatabase.fmp12");
// List with filters
const result = await db.from(Users).list()
.where(and(eq(Users.active, true), gt(Users.age, 18)))
.orderBy(asc(Users.name))
.top(10)
.execute();
// Get single record
const user = await db.from(Users).get("user-123").execute();
// Select specific fields
const result = await db.from(Users).list()
.select({ userId: Users.id, userName: Users.name })
.execute();
// String filters
.where(contains(Users.email, "@example.com"))
.where(startsWith(Users.name, "John"))// Insert
const result = await db.from(Users)
.insert({ name: "John", email: "john@example.com" })
.execute();
// Update
const result = await db.from(Users)
.update({ name: "Jane" })
.byId("user-123")
.execute();
// Delete
const result = await db.from(Users)
.delete()
.byId("user-123")
.execute();
// Batch operations (atomic)
const result = await db.batch([
db.from(Users).list().top(10),
db.from(Users).insert({ name: "Alice", email: "alice@example.com" }),
]).execute();// Expand related records
const result = await db.from(Users).list()
.expand(Contacts, (b) =>
b.select({ name: Contacts.name })
.where(eq(Contacts.active, true))
)
.execute();
// Navigate from a record
const result = await db.from(Contacts).get("contact-123")
.navigate(Users)
.select({ username: Users.username })
.execute();import { isHTTPError, ValidationError, TimeoutError } from "@proofkit/fmodata";
const result = await db.from(Users).list().execute();
if (result.error) {
if (isHTTPError(result.error)) {
if (result.error.isNotFound()) console.log("Not found");
if (result.error.is5xx()) console.log("Server error");
} else if (result.error instanceof ValidationError) {
console.log("Validation failed:", result.error.issues);
} else if (result.error instanceof TimeoutError) {
console.log("Request timed out");
}
}OTTO_API_KEYFM_USERNAMEFM_PASSWORDfmodata.fmp12npx @proofkit/typegen ui--env-pathnpx @proofkit/typegen generate--reset-overridesfmTableOccurrenceentityIdreadValidatorwriteValidator.catch("").nullable().top(n).select()