UNPKG

@proofkit/fmodata

Version:

FileMaker OData API client

438 lines (340 loc) 11.9 kB
--- name: typegen-fmodata description: > ENTRY POINT for @proofkit/fmodata projects. Generate TypeScript table schemas with entity IDs from FileMaker OData metadata using @proofkit/typegen. Covers proofkit-typegen-config.jsonc for OData mode, npx @proofkit/typegen setup, fmTableOccurrence generation, entity IDs (FMFID/FMTID), generated output structure, field exclusion, type overrides, InferTableSchema, env var configuration, OData prerequisites, fmodata privilege, and why typegen is required for entity ID correctness. metadata: type: core library: proofkit library_version: "0.1.2" sources: - "proofsh/proofkit:packages/typegen/src/cli.ts" - "proofsh/proofkit:packages/typegen/src/fmodata/typegen.ts" - "proofsh/proofkit:apps/docs/content/docs/typegen/*.mdx" - "proofsh/proofkit:apps/docs/content/docs/fmodata/quick-start.mdx" --- > **ALWAYS use `@proofkit/typegen` to set up an @proofkit/fmodata project.** > Typegen generates `fmTableOccurrence` definitions with correct field types > and entity IDs (`FMFID`/`FMTID`) from FileMaker metadata. These entity IDs > are opaque identifiers that cannot be guessed — they MUST come from typegen. > Without typegen, queries using `useEntityIds: true` will silently fail or > return wrong data. Before writing any fmodata query code, run typegen first. ## Prerequisites - **FileMaker Server 22.0.4+** accessible via port 443 - **OttoFMS 4.11+** installed on the FM server (only required for API key auth) - **FileMaker account** with the `fmodata` extended privilege enabled - **OData API enabled** on the FileMaker server ## Setup ### 1. Install the runtime package ```bash npm add @proofkit/fmodata ``` ### 2. Set environment variables ```bash # .env FM_SERVER=https://your-server.com # must start with https:// FM_DATABASE=MyFile.fmp12 # must end with .fmp12 # Option A: API key auth (requires OttoFMS 4.11+) OTTO_API_KEY=dk_123456...789 # Option B: username/password auth FM_USERNAME=admin FM_PASSWORD=password ``` ### 3. Initialize and run typegen ```bash npx @proofkit/typegen@beta init ``` This creates `proofkit-typegen-config.jsonc`. Configure for OData mode: ```jsonc { "$schema": "https://proofkit.proof.sh/typegen-config-schema.json", "config": { "type": "fmodata", "path": "schema/odata", "tables": [ { "tableName": "Customers", "fields": [ { "fieldName": "InternalID", "exclude": true }, { "fieldName": "Status", "typeOverride": "boolean" } ] }, { "tableName": "Orders", "variableName": "OrdersTable" } ] } } ``` Run typegen to generate schemas: ```bash npx @proofkit/typegen@beta ``` Add a convenience script to `package.json`: ```json { "scripts": { "typegen": "npx @proofkit/typegen@beta" "typegen:ui": "npm run tyepgen ui" } } ``` ### 4. Create a server connection ```ts import { FMServerConnection } from "@proofkit/fmodata"; export const connection = new FMServerConnection({ serverUrl: process.env.FM_SERVER, auth: { apiKey: process.env.OTTO_API_KEY, }, }); ``` ### 5. First query ```ts import { connection } from "./connection"; import { Customers } from "./schema/odata/generated/Customers"; const db = connection.database(process.env.FM_DATABASE); const { data, error } = await db.from(Customers).list().execute(); if (error) { console.error(error); } else { console.log(data); } ``` ## Core Patterns ### Generated output structure For OData configs (`"type": "fmodata"`), typegen generates `fmTableOccurrence` definitions: ```text schema/odata/ generated/ # Auto-generated. NEVER edit fields or entity IDs. Customers.ts # fmTableOccurrence with fields, entity IDs from FM metadata Orders.ts ``` ### What typegen generates Each generated file exports a `fmTableOccurrence` with: - Field definitions with correct types (`textField()`, `numberField()`, etc.) - Entity IDs (`FMFID`/`FMTID`) from FileMaker metadata - Primary key designation - Read-only markers for auto-enter fields ```ts // schema/odata/generated/Customers.ts — generated by typegen, do NOT edit import { fmTableOccurrence, textField, numberField, timestampField } from "@proofkit/fmodata"; export const Customers = fmTableOccurrence( "Customers", { id: textField().primaryKey().entityId("FMFID:1039485"), name: textField().notNull().entityId("FMFID:3432343"), email: textField().notNull().entityId("FMFID:1223242"), age: numberField().entityId("FMFID:4323435"), createdAt: timestampField().readOnly().entityId("FMFID:5938271"), }, { entityId: "FMTID:1243253", defaultSelect: "schema", }, ); ``` ### Safe customizations on generated schemas You may add or edit these options on generated schemas — they will NOT be overwritten by typegen: - `readValidator` — transform data on read (e.g., `z.coerce.boolean()`) - `writeValidator` — transform data on write - `defaultSelect` — control default field selection - `navigationPaths` — define relationship navigation ```ts // Safe to add to generated file: active: numberField() .readValidator(z.coerce.boolean()) .writeValidator(z.boolean().transform((v) => (v ? 1 : 0))) .entityId("FMFID:6"), ``` Do NOT manually add new fields or change entity IDs — these must come from typegen. ### Type inference Use `InferTableSchema` to extract row types from generated tables: ```ts import type { InferTableSchema } from "@proofkit/fmodata"; import { Customers } from "./schema/odata/generated/Customers"; type CustomerRow = InferTableSchema<typeof Customers>; ``` ### Custom env variable names ```jsonc { "config": { "type": "fmodata", "envNames": { "server": "MY_FM_SERVER", "db": "MY_FM_DATABASE", "auth": { "apiKey": "MY_OTTO_KEY" } }, "tables": [ { "tableName": "Customers" } ] } } ``` ### Multiple configs The `config` key can be an array mixing `fmdapi` and `fmodata` entries, each with its own `path` and `envNames`. ### Config options for OData tables ```jsonc { "config": { "type": "fmodata", "path": "schema/odata", "reduceMetadata": true, "tables": [ { "tableName": "Customers", "variableName": "CustomersTable", "fields": [ { "fieldName": "InternalID", "exclude": true }, { "fieldName": "Status", "typeOverride": "boolean" }, { "fieldName": "Notes", "typeOverride": "string" } ] } ] } } ``` - `variableName` — custom export name (default: table name) - `fields[].exclude` — omit field from generated schema - `fields[].typeOverride` — override the inferred field type ## Common Mistakes ### CRITICAL: Inventing entity IDs or guessing field names Wrong: ```ts // Agent adds a field with a guessed entity ID const contacts = fmTableOccurrence("contacts", { ...existingFields, newField: textField().entityId("FMFID:99"), // guessed ID — will silently fail }); ``` Entity IDs (`FMFID`/`FMTID`) are opaque and MUST come from FileMaker metadata via typegen. Guessed entity IDs cause silent query failures — wrong data or empty results with no error. To add new fields, use the fmodata CLI to discover real field names programmatically, then add them to the `tables[].fields` array in `proofkit-typegen-config.jsonc`, and re-run typegen to generate the correct definitions with entity IDs: ```bash # 1. Discover available fields via the CLI npx @proofkit/fmodata@beta metadata fields --table <TableName> # Add --details for field types, nullability, etc. # 2. Edit proofkit-typegen-config.jsonc to include the new field(s) # 3. Re-run typegen to regenerate schemas with correct entity IDs npx @proofkit/typegen@beta ``` Never manually edit entity IDs or field definitions in generated files — always re-run typegen after config changes. Source: packages/typegen/src/fmodata/typegen.ts ### CRITICAL: Manually redefining types instead of using generated/inferred types Wrong: ```ts interface Customer { name: string; email: string; phone: string; } ``` Correct: ```ts import type { InferTableSchema } from "@proofkit/fmodata"; import { Customers } from "./schema/odata/generated/Customers"; type CustomerRow = InferTableSchema<typeof Customers>; ``` fmodata infers all types from `fmTableOccurrence` definitions. Use `InferTableSchema<typeof table>` if you need an explicit type alias. Source: packages/typegen/src/buildSchema.ts ### CRITICAL: Writing fmTableOccurrence from scratch without typegen Wrong: ```ts // Manually defining schema without entity IDs const users = fmTableOccurrence("users", { id: textField().primaryKey(), name: textField().notNull(), email: textField().notNull(), }); ``` Correct: ```bash npx @proofkit/typegen@beta ``` Manual schemas lack entity IDs, meaning `useEntityIds: true` (the recommended database option) won't work. Queries will use field names instead of stable IDs, breaking silently when fields are renamed in FileMaker. Always generate schemas with typegen. Source: apps/docs/content/docs/fmodata/entity-ids.mdx ### HIGH: Omitting type discriminator for OData config Wrong: ```jsonc { "config": { "tables": [ { "tableName": "Customers" } ] } } ``` Correct: ```jsonc { "config": { "type": "fmodata", "tables": [ { "tableName": "Customers" } ] } } ``` Without `"type": "fmodata"`, the config defaults to `"fmdapi"` and expects a `layouts` array instead of `tables`, causing a validation error. Source: packages/typegen/src/types.ts:238-243 ### HIGH: Not running typegen after FileMaker schema changes or config edits Wrong: ```ts // Manually editing a generated file to add a new field // OR editing proofkit-typegen-config.jsonc without re-running typegen ``` Correct: ```bash npx @proofkit/typegen@beta ``` After changing table schemas in FileMaker or editing `proofkit-typegen-config.jsonc`, re-run typegen to regenerate types. The generated schemas are the source of truth for field names, types, and entity IDs. Source: packages/typegen/src/fmodata/typegen.ts ### CRITICAL: Putting env var values instead of names in config Wrong: ```jsonc { "envNames": { "server": "https://my-server.com", "auth": { "apiKey": "dk_abc123secret" } } } ``` Correct: ```jsonc { "envNames": { "server": "MY_FM_SERVER", "auth": { "apiKey": "MY_OTTO_KEY" } } } ``` `envNames` expects the names of environment variables, not their secret values; typegen reads the actual values from the environment at runtime. Source: apps/docs/content/docs/typegen/config.mdx ### HIGH: Mixing Zod v3 and v4 in the same project Use one Zod version consistently (v4 recommended). Zod v3 and v4 have incompatible APIs; mixing them causes runtime validation failures. Source: apps/docs/content/docs/typegen/config.mdx ### CRITICAL: FM_SERVER without https:// prefix Wrong: ```bash FM_SERVER=filemaker.example.com ``` Correct: ```bash FM_SERVER=https://filemaker.example.com ``` `@proofkit/fmodata` expects `FM_SERVER` to be a full URL including the `https://` protocol prefix. Source: apps/docs/content/docs/fmdapi/quick-start.mdx ### CRITICAL: Missing fmodata privilege on FM account The OData API requires the `fmodata` extended privilege on the FileMaker account. Without it, all API calls return authorization errors. Enable via File > Manage > Security > Privilege Sets > Extended Privileges. Source: apps/docs/content/docs/cli/guides/getting-started.mdx ## References - **fmodata-client**: After generating schemas with typegen, see the fmodata-client skill for full query builder usage, CRUD operations, filter operators, relationships, batch operations, and error handling. - **odata-query-optimization**: Performance patterns for fmodata queries — defaultSelect, pagination, batch operations, and entity ID usage.