import { z } from "zod"; export const ZFieldValue = z.union([z.string(), z.number(), z.null()]); export type FieldValue = z.infer; export const ZFieldData = z.record(z.string(), ZFieldValue); export type FieldData = z.infer; export type ZodGenericPortalData = z.ZodObject<{ [key: string]: z.ZodObject<{ [x: string]: z.ZodString | z.ZodNumber }>; }>; export type GenericPortalData = z.infer; export type PortalsWithIds = { [key in keyof U]: Array< U[key] & { recordId: string; modId: string; } >; }; export type UpdatePortalsWithIds< U extends GenericPortalData = GenericPortalData > = { [key in keyof U]: Array< U[key] & { recordId: string; modId?: string; } >; }; export const getFMRecordAsZod = < T extends z.AnyZodObject, U extends z.AnyZodObject >({ fieldData, portalData, }: ZInput): z.ZodTypeAny => { const obj = z.object({ fieldData: fieldData, recordId: z.string(), modId: z.string(), }); if (portalData) { const portalObj = z.object({}); Object.keys(portalData).forEach((key) => { portalObj.extend({ [key]: portalData.shape[key] }); }); obj.extend({ portalData: portalObj }).strict(); } return obj; }; export type FMRecord< T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData > = { fieldData: T; recordId: string; modId: string; portalData: PortalsWithIds; }; export type ScriptParams = { script?: string; "script.param"?: string; "script.prerequest"?: string; "script.prerequest.param"?: string; "script.presort"?: string; "script.presort.param"?: string; timeout?: number; }; const ZScriptResponse = z.object({ scriptResult: z.string().optional(), scriptError: z.string().optional(), "scriptResult.prerequest": z.string().optional(), "scriptError.prerequest": z.string().optional(), "scriptResult.presort": z.string().optional(), "scriptError.presort": z.string().optional(), }); export type ScriptResponse = z.infer; export const ZDataInfo = z.object({ database: z.string(), layout: z.string(), table: z.string(), totalRecordCount: z.number(), foundCount: z.number(), returnedCount: z.number(), }); export type DataInfo = z.infer; export type CreateParams = ScriptParams & { portalData?: UpdatePortalsWithIds }; export type CreateResponse = ScriptResponse & { recordId: string; modId: string; }; export type UpdateParams = CreateParams & { modId?: number; }; export type UpdateResponse = ScriptResponse & { modId: string; }; export type DeleteParams = ScriptParams; export type DeleteResponse = ScriptResponse; export type RangeParams = { offset?: number; limit?: number; }; export type PortalRanges = Partial<{ [key in keyof U]: RangeParams }>; export type PortalRangesParams< U extends GenericPortalData = GenericPortalData > = { portalRanges?: PortalRanges; }; export type GetParams = ScriptParams & PortalRangesParams & { "layout.response"?: string; dateformats?: "US" | "file_locale" | "ISO8601"; }; export type Sort = { fieldName: keyof T; sortOrder: "ascend" | "descend" | string; }; export type ListParams< T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData > = GetParams & RangeParams & { sort?: Sort | Array>; }; export type GetResponse< T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData > = ScriptResponse & { data: Array>; dataInfo: DataInfo; }; export type GetResponseOne< T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData > = ScriptResponse & { data: FMRecord; dataInfo: DataInfo; }; type ZInput = { fieldData: T; portalData?: U; }; export const ZGetResponse = < T extends z.AnyZodObject, U extends z.AnyZodObject >({ fieldData, portalData, }: ZInput): z.ZodType< GetResponse, z.infer> // z.ZodTypeDef, // any > => ZScriptResponse.extend({ data: z.array(getFMRecordAsZod({ fieldData, portalData })), dataInfo: ZDataInfo, }); type ZGetResponseReturnType = z.infer>; type SecondLevelKeys = { [K in keyof T]: keyof T[K]; }[keyof T]; export type Query< T extends FieldData = FieldData, U extends GenericPortalData = GenericPortalData > = Partial<{ [key in keyof T]: T[key] | string; }> & Partial<{ [key in SecondLevelKeys]?: string }> & { omit?: boolean; }; export type MetadataResponse = { fieldMetaData: FieldMetaData[]; portalMetaData: { [key: string]: FieldMetaData[] }; valueLists?: ValueList[]; }; export type FieldMetaData = { name: string; type: "normal" | "calculation" | "summary"; displayType: | "editText" | "popupList" | "popupMenu" | "checkBox" | "calendar" | "radioButtons" | "secureText"; result: "text" | "number" | "date" | "time" | "timeStamp" | "container"; global: boolean; autoEnter: boolean; fourDigitYear: boolean; maxRepeat: number; maxCharacters: number; notEmpty: boolean; numeric: boolean; repetitions: number; timeOfDay: boolean; valueList?: string; }; type ValueList = { name: string; // TODO need to test type of value list from other file type: "customList" | "byField"; values: Array<{ value: string; displayValue: string }>; }; /** * Represents the data returned by a call to the Data API `layouts` endpoint. */ export type LayoutsResponse = { /** * A list of `Layout` or `LayoutsFolder` objects. */ layouts: LayoutOrFolder[]; }; /** * Represents a FileMaker layout. */ export type Layout = { /** * The name of the layout */ name: string; /** * If the node is a layout, `table` may contain the name of the table * the layout is associated with. */ table: string; }; /** * Represents a folder of `Layout` or `LayoutsFolder` objects. */ export type LayoutsFolder = { /** * The name of the folder */ name: string; isFolder: boolean; /** * A list of the Layout or LayoutsFolder objects in the folder. */ folderLayoutNames?: LayoutOrFolder[]; }; export type LayoutOrFolder = Layout | LayoutsFolder; /** * Represents the data returned by a call to the Data API `scripts` endpoint. */ export type ScriptsMetadataResponse = { /** * A list of `Layout` or `LayoutsFolder` objects. */ scripts: ScriptOrFolder[]; }; type Script = { name: string; isFolder: false; }; type ScriptFolder = { name: string; isFolder: true; folderScriptNames: ScriptOrFolder[]; }; export type ScriptOrFolder = Script | ScriptFolder; export type RawFMResponse = { response?: T; messages?: [{ code: string }]; };