import { U as Uuid, h as RuleNodeKind, i as RuleUse, g as Timestamp } from './record-C3thPhpR.js'; /** * A rule expression as `custom.rule_eval` ACTUALLY evaluates it — read off the * door's own body, not invented here. A leaf is the node's name carrying its * payload (`{"const": 3}`, `{"field": ""}`); an operator is * `{"op": "eq", "args": [...]}`. * * `field` / `parent_field` name a Field BY ID (REC-17 — the door refuses * `field_name`, `field_key` and `field_label` by name), and `merge_field` is * the resolver's seam, storable today and refused `0A000` until W5-MERGE-B. * * `p_values` is keyed by the Field's KEY: the door resolves the id to a key * (`custom.rule_field_key`) and then reads `p_values -> key`. */ type RuleExpression = { const: unknown; } | { field: Uuid; } | { parent_field: Uuid; } | { merge_field: string; } | { op: RuleNodeKind; args: RuleExpression[]; }; /** REC-15. One Rule, four uses; a Rule may serve more than one. */ interface Rule { id: Uuid; organization_id: Uuid; name: string; kind: string | null; /** The Table this Rule is scoped to. */ scope_table_id: Uuid | null; uses: RuleUse[]; validates: boolean; computes: boolean; defines_membership: boolean; /** * REC-16. An applicability Rule reads the record's own Values and its * parent's, ONE level up, and no further. */ decides_applicability: boolean; applies_to_types: string[]; use_types: string[]; expr: RuleExpression; /** Which Field this Rule's answer is about (REC-17: by id). */ target_field_id: Uuid | null; /** What a person reads when this Rule refuses. */ message: string | null; sort: number | null; created_by: Uuid | null; updated_by: Uuid | null; created_at: Timestamp; updated_at: Timestamp; /** REC-19. Rules have versions, and History knows which one produced a Value. */ version: number; metadata: Record; visibility: string; } /** What the store answers when a Rule is run: the answer and the version that gave it. */ interface RuleAnswer { rule_id: Uuid; rule_name: string; rule_version: number; applies: boolean; answer: unknown; } /** One form as `custom.forms` reports it to its owner. */ interface FormSummary { form_id: string; table_id: string; title: string | null; slug: string; published_at: string | null; closed_at: string | null; submission_cap: number | null; /** Every answer that arrived, rejected ones excluded from `in_table` and `held`. */ responses: number; /** Answers that became records — the only number that means "it is in the table". */ in_table: number; /** Answers waiting for a person, because the form's accept Rule did not clear them. */ held: number; /** Answers the accept Rule or the decoy turned away. */ rejected: number; /** draft · open · closed · full — the store's own word, never derived on a screen. */ state: "draft" | "open" | "closed" | "full"; quarantine_rule_id: string | null; notify_rule_id: string | null; presentation: Record; } /** * THE ROUTE THROUGH A FORM, AS THE STORE WALKED IT (lane TYPEFORM-DUP) — `custom._form_route`, * reached by the owner's preview (`custom.form_preview_route`) and the stranger's page * (`custom.form_public_route`). One row per question in order (`asked` false only when a condition * hid it or a logic jump carried the person past it); the ending reached (null = the thank-you * screen); the score (null when no question carries points). */ interface FormRoute { asks: Array<{ field_key: string; asked: boolean; decided: boolean; said: string | null; }>; ending: string | null; score: number | null; } /** A form's results for its owner — `custom.form_results`. Every number is the store's. */ interface FormResults { form_id: string; /** Visits to the public link (one per page open, counted through the app's own route). */ views: number; /** Visits that answered at least one question. */ starts: number; /** Submissions that arrived (the decoy's excluded). */ completions: number; /** completions / starts, as a percentage with one decimal; null before anybody started. */ completion_rate: number | null; questions: Array<{ field_key: string; /** Visits that were shown this question. */ reached: number; /** Visits whose last question was this one and that never sent: the drop-off. */ left: number; /** Submissions that answered it. */ answered: number; /** The twelve most common answers (a list answer counts each of its parts). */ answers: Array<{ value: string; count: number; }>; }>; endings: Array<{ ending: string | null; count: number; }>; hidden: Array<{ key: string; value: string; count: number; }>; score: { count: number; average: number; min: number; max: number; } | null; } /** * ONE BOOKING PAGE, AS ITS OWNER SEES IT — `custom.bookings` (PRODUCTS row 14). * * A booking page is an `anon_form` whose `presentation -> 'booking'` carries the * availability and the id of a slots Table, so it is the SAME object a form is and * this is the same list `forms()` is, asked for the booking half. The numbers are * the store's own: a screen that counted appointments in the browser would drift * from the index that actually protects a slot. */ interface BookingSummary { form_id: string; /** The Table the appointments land in — a booking is an ordinary record in it. */ table_id: string; title: string | null; slug: string; published_at: string | null; closed_at: string | null; /** How long one appointment is. The offer is the store's, never the browser's. */ slot_minutes: number; /** The organization's own zone, which is what the visitor's times are drawn in. */ timezone: string; /** The ONE slots Table `custom.booking_declare` finds-or-makes for this page. */ slot_table_id: string; booked: number; cancelled: number; /** Booked and still ahead of now — the number that answers "what is coming". */ upcoming: number; /** Slots a visitor is holding right now, before they have given their details. */ held: number; /** The next appointment, or null when there is none. */ next_at: string | null; /** draft · open · closed — the store's own word, never derived on a screen. */ state: string; } /** * ONE WINDOW OF AN ORGANIZATION'S WEEK, in the shape `custom._booking_availability` * normalizes to and `custom._booking_slots` generates from. `weekday` is 0 for Sunday * and 6 for Saturday — the database's own numbering, so a picker and the store cannot * disagree about which day Monday is. A window may name ONE member, which is the "with * whom" of an appointment; naming somebody who is not a member is refused BY NAME. */ interface BookingWindow { weekday: number; /** "09:00" */ from: string; /** "17:00" — later in the day than `from`, or the store refuses it by name. */ to: string; member_user_id?: string | null; } /** * WHAT IS ON OFFER. Every field is the store's to default: a page declared with an * empty availability comes back with the organization's timezone, a 30-minute slot and * Monday-to-Friday nine-to-five, because a booking page that offered nothing would look * broken rather than unconfigured. A screen shows what came BACK, never what it sent. */ interface BookingAvailability { timezone: string; slot_minutes: number; /** Dead time kept after each appointment, so two never touch. */ buffer_minutes: number; /** How far ahead of now the earliest bookable slot is. */ lead_minutes: number; /** Most appointments in one day, across every window. */ max_per_day: number; /** How many days ahead the page offers. */ days: number; windows: BookingWindow[]; /** CD-PAGE-10: places at one time for each host (1 = one person per time; a class or group visit takes more). */ capacity?: number; /** CD-PAGE-10: none, auto (a new meet.jit.si room per booking) or link (the owner's own room in `video_url`). */ video?: "none" | "auto" | "link"; video_url?: string; /** CD-PAGE-10: the owner's private iCal address; its busy times are never offered. Owner-only — never in a public answer. */ busy_feed?: string; /** CD-PAGE-10: when the connected calendar was last read, and why the last read failed (the last good list is kept). */ busy_read_at?: string | null; busy_problem?: string | null; } /** * WHAT `custom.booking_declare` ANSWERS. `availability` is the NORMALIZED offer — * show that, not the draft — and `questions_filled_in` is how many questions the store * took over (`slot`, `status`, `booked_with`), which a visitor is never asked. * * It does NOT publish. `anonPublish` is still the one act that opens the link, exactly * as it is for a form, so there is one act and one word for opening a public surface. */ interface BookingDeclared { form_id: string; slot_table_id: string; availability: BookingAvailability; questions_asked: number; questions_filled_in: number; ms: number; } /** * THE VISITOR'S OWN LINK to a booking page. The page id IS the capability, exactly * as it is for a form; `custom.anon_submission.booking_ref` is the separate secret * that lets ONE visitor manage the appointment they made. */ declare function bookingPath(formId: string): string; /** * THE PUBLIC LINK, and the one place its shape is written down. * * The form's own id IS the capability — 122 bits of UUIDv4, exactly as * Typeform's form id in `/to/` is and as an unguessable meeting slug is * here. There is no second secret to keep, and revoking it is closing the form. */ declare function publicFormPath(formId: string): string; export { bookingPath as h, publicFormPath as p }; export type { BookingAvailability as B, FormSummary as F, RuleExpression as R, BookingDeclared as a, BookingSummary as b, BookingWindow as c, FormResults as d, FormRoute as e, Rule as f, RuleAnswer as g };