@marktiderman/genesis-core 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/{chunk-5NHR6ZXS.js → chunk-LG6TUBVM.js} +2 -2
- package/dist/chunk-LG6TUBVM.js.map +1 -0
- package/dist/{chunk-Y3SCYMNN.js → chunk-SQR4GFRM.js} +3 -3
- package/dist/{chunk-Y3SCYMNN.js.map → chunk-SQR4GFRM.js.map} +1 -1
- package/dist/{chunk-Y475Z7BM.js → chunk-XKLYDAT5.js} +4 -3
- package/dist/chunk-XKLYDAT5.js.map +1 -0
- package/dist/hooks/index.js +2 -2
- package/dist/hooks/use-resource-form.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/provider/index.d.ts +6 -5
- package/dist/provider/index.js +2 -2
- package/dist/{read-outcome-C_9HbXvb.d.ts → read-outcome-B6nACXZ7.d.ts} +4 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-5NHR6ZXS.js.map +0 -1
- package/dist/chunk-Y475Z7BM.js.map +0 -1
package/README.md
CHANGED
|
@@ -117,6 +117,7 @@ try {
|
|
|
117
117
|
case "forbidden": /* hide the control, say why */ break;
|
|
118
118
|
case "gone": /* close the record, refresh the list */ break;
|
|
119
119
|
case "invalid": /* show error.message by the form */ break;
|
|
120
|
+
case "duplicate": /* adopt the existing row, or show error.fields by the form */ break;
|
|
120
121
|
case "unauthenticated": /* send to sign-in */ break;
|
|
121
122
|
default: /* show error.message */
|
|
122
123
|
}
|
|
@@ -27,5 +27,5 @@ function isDataWriteError(error) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export { DataWriteError, isDataWriteError };
|
|
30
|
-
//# sourceMappingURL=chunk-
|
|
31
|
-
//# sourceMappingURL=chunk-
|
|
30
|
+
//# sourceMappingURL=chunk-LG6TUBVM.js.map
|
|
31
|
+
//# sourceMappingURL=chunk-LG6TUBVM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema/write-outcome.ts"],"names":[],"mappings":";AA2DO,IAAM,cAAA,GAAN,cAA6B,KAAA,CAAM;AAAA,EAC/B,OAAA;AAAA,EACA,OAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAEA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA;AAAA,EAET,WAAA,CAAY,OAAA,EAAuB,OAAA,EAAiB,OAAA,GAAiC,EAAC,EAAG;AACvF,IAAA,KAAA,CAAM,OAAA,EAAS,QAAQ,KAAA,KAAU,MAAA,GAAY,SAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,CAAA;AACjF,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,OAAA,CAAQ,cAAA;AAC9B,IAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,IAAA,CAAK,OAAO,OAAA,CAAQ,IAAA;AACpD,IAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,CAAO,IAAA,CAAK,QAAQ,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5D,MAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA,CAAO,EAAE,GAAG,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACnD;AAAA,EACF;AACF;AAMO,SAAS,iBAAiB,KAAA,EAAyC;AACxE,EAAA,OACE,iBAAiB,KAAA,IACjB,KAAA,CAAM,SAAS,gBAAA,IACf,OAAQ,MAAgC,OAAA,KAAY,QAAA;AAExD","file":"chunk-LG6TUBVM.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Why a write did not save (DATA-STUDIO.md \"Write safety\")\n//\n// A write that changes nothing is never reported as \"permission denied\" by\n// assumption. The provider re-reads the row and says what actually happened.\n// ---------------------------------------------------------------------------\n\nimport type { DataRow } from \"./types\";\n\n/**\n * - `conflict`: someone else changed the row since it was read. `current`\n * carries the row as it is now.\n * - `gone`: the row was deleted, or is no longer visible to this user. The\n * two cannot be told apart without a privileged look at the table, which\n * would show this user a fact about a row they cannot see.\n * - `forbidden`: the row is visible and unchanged, but the app or the\n * database does not let this user make this change. Only reported when\n * that is proven, never assumed from \"zero rows changed\".\n * - `duplicate`: a row with the same unique key already exists (`23505`).\n * A caller keeping \"one live row per key\" (a draft, a natural-key upsert)\n * adopts the existing row instead; `fields` still names the clashing field.\n * - `invalid`: the store rejected the value (type, constraint, not-null).\n * - `audit_failed`: the audit entry could not be written, so the edit was\n * rolled back with it.\n * - `unauthenticated`: no signed-in user, or the session expired.\n * - `error`: anything else. The edit did not commit.\n */\nexport type WriteOutcome =\n | \"conflict\"\n | \"gone\"\n | \"forbidden\"\n | \"duplicate\"\n | \"invalid\"\n | \"audit_failed\"\n | \"unauthenticated\"\n | \"error\";\n\nexport interface DataWriteErrorOptions {\n /** The row as it is now, for a `conflict`. Only fields the user may read. */\n current?: DataRow;\n /** The row's current version token, for a `conflict`. */\n currentVersion?: string | null;\n /**\n * The store's own error code, when it gave one (a Postgres SQLSTATE such as\n * `23505`, or a PostgREST code such as `PGRST301`).\n */\n code?: string;\n /**\n * Per-field messages, keyed by field (column) name, for a write the store\n * rejected because of particular values. Each message is safe to show next\n * to its input: plain words, never the store's raw text or the value.\n * `useResourceForm` puts each one on its field.\n */\n fields?: Record<string, string>;\n /** The underlying error, kept for logging. */\n cause?: unknown;\n}\n\n/** Thrown by a provider when a write did not commit. */\nexport class DataWriteError extends Error {\n readonly outcome: WriteOutcome;\n readonly current?: DataRow;\n readonly currentVersion?: string | null;\n /** The store's own error code, when it gave one. */\n readonly code?: string;\n /**\n * Per-field messages (field name → safe message), when the store said which\n * values it rejected. See `DataWriteErrorOptions.fields`.\n */\n readonly fields?: Readonly<Record<string, string>>;\n\n constructor(outcome: WriteOutcome, message: string, options: DataWriteErrorOptions = {}) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = \"DataWriteError\";\n this.outcome = outcome;\n this.current = options.current;\n this.currentVersion = options.currentVersion;\n if (options.code !== undefined) this.code = options.code;\n if (options.fields && Object.keys(options.fields).length > 0) {\n this.fields = Object.freeze({ ...options.fields });\n }\n }\n}\n\n/**\n * `instanceof` fails when two copies of this package are installed, so check\n * the shape instead.\n */\nexport function isDataWriteError(error: unknown): error is DataWriteError {\n return (\n error instanceof Error &&\n error.name === \"DataWriteError\" &&\n typeof (error as { outcome?: unknown }).outcome === \"string\"\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isDataWriteError } from './chunk-
|
|
1
|
+
import { isDataWriteError } from './chunk-LG6TUBVM.js';
|
|
2
2
|
import { useOne } from './chunk-ZKMAU6NN.js';
|
|
3
3
|
import { useUnsavedChangesGuard } from './chunk-XQO4OH2N.js';
|
|
4
4
|
import { titleCase } from './chunk-RYEXWQFD.js';
|
|
@@ -493,5 +493,5 @@ function useResourceForm(options) {
|
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
export { buildArrayItemDefaults, useResourceForm };
|
|
496
|
-
//# sourceMappingURL=chunk-
|
|
497
|
-
//# sourceMappingURL=chunk-
|
|
496
|
+
//# sourceMappingURL=chunk-SQR4GFRM.js.map
|
|
497
|
+
//# sourceMappingURL=chunk-SQR4GFRM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-resource-form.ts"],"names":[],"mappings":"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","file":"chunk-Y3SCYMNN.js","sourcesContent":["import { useMemo, useCallback, useEffect, useRef, useState } from \"react\";\nimport { useForm, type UseFormReturn, type Resolver } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { z } from \"zod\";\nimport { useOne } from \"./use-one\";\nimport { useDataProvider, useStorage } from \"../provider/context\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { titleCase } from \"../utils\";\nimport type { ResourceFormFieldDef, FieldType } from \"../form-types\";\nimport type { BaseRecord, InvalidationKey } from \"../provider/types\";\nimport { relatedKeys } from \"./related-keys\";\nimport { isDataWriteError } from \"../schema/write-outcome\";\nimport {\n cachedRecord,\n executeWrite,\n invalidateResource,\n sameValue,\n type MutationModeOptions,\n} from \"./mutation-mode\";\nimport { useUnsavedChangesGuard } from \"./use-unsaved-changes-guard\";\n\n/** A deep copy where the platform allows one (form values are plain data). */\nfunction structuredCloneSafe<T>(value: T): T {\n try {\n return typeof structuredClone === \"function\" ? structuredClone(value) : value;\n } catch {\n return value;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseResourceFormOptions extends MutationModeOptions {\n resource: string;\n action: \"create\" | \"edit\";\n id?: string;\n initialData?: Record<string, unknown>;\n fields?: ResourceFormFieldDef[];\n /** Full dataset used to auto-detect select fields from unique values. */\n listData?: Record<string, unknown>[];\n /**\n * The form is done. After the save in `pessimistic` mode (with the stored\n * row); at once in `optimistic` and `undoable` modes (with the submitted\n * values over the record, and no `id` for a create).\n */\n onSuccess?: (data: Record<string, unknown>) => void;\n /**\n * The save failed. In `optimistic` and `undoable` modes the form may be\n * gone by then, so show the error from here (genesis-ui's ResourceForm\n * toasts it when no `onError` is given).\n */\n onError?: (error: Error) => void;\n /**\n * Warn before unsaved changes are lost. Default false. While the form is\n * dirty, closing or reloading the tab shows the browser's prompt, and\n * `confirmLeave()` asks before in-app navigation (wire it to a router\n * blocker; see SKILL.md \"Unsaved changes\").\n */\n warnWhenUnsaved?: boolean | { message?: string };\n /**\n * Whether the form is on screen. Default true. Pass false while it is\n * hidden but still mounted (a closed dialog). An optimistic or undoable\n * save that fails later is put back on the form (field errors, unsaved\n * again) only while the form is mounted, visible and still holds the\n * values it saved; otherwise the failure only reaches `onError`.\n */\n visible?: boolean;\n /**\n * Pre-fill create form defaults from URL query params: a param named like a\n * field (`?status=draft`) becomes that field's starting value. Default true.\n * Pass false for a form that should not read the page's URL, e.g. one\n * opened from a list whose own filters live in the query string.\n */\n prefillFromUrl?: boolean;\n /**\n * Generate a placeholder (\"Enter name\", \"name@example.com\") for a field\n * whose `placeholder` is unset. Default true. A placeholder that only\n * repeats the label adds noise without information, so `ResourceForm`\n * turns this off unless asked.\n */\n autoPlaceholder?: boolean;\n /** Validation trigger mode. Default \"onBlur\". */\n validationMode?: \"onBlur\" | \"onChange\" | \"onSubmit\";\n /** Enable autosave drafts to localStorage for create mode. */\n autosave?: boolean | { debounceMs?: number };\n /**\n * Other query keys to invalidate after a save, on top of `[resource]` and\n * the provider's own `invalidates`.\n */\n invalidates?: InvalidationKey[];\n}\n\nexport interface UseResourceFormReturn {\n form: UseFormReturn<Record<string, unknown>>;\n resolvedFields: ResourceFormFieldDef[];\n onSubmit: (e?: { preventDefault?: () => void }) => Promise<void>;\n /** Raw save handler — use with form.handleSubmit(handleSave, onInvalid). */\n handleSave: (data: Record<string, unknown>) => Promise<void>;\n isSaving: boolean;\n isLoading: boolean;\n /**\n * The form has changes that have not been saved. False again once a save\n * succeeds (or, in optimistic / undoable modes, is handed off).\n */\n isDirty: boolean;\n /**\n * For in-app navigation: true when it is fine to leave (nothing unsaved,\n * `warnWhenUnsaved` off, or the user confirmed). Asks with\n * `window.confirm` otherwise.\n */\n confirmLeave: () => boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Infer a field type from a value */\nfunction inferFieldType(value: unknown): FieldType {\n if (typeof value === \"boolean\") return \"switch\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"string\") {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(value)) return \"date\";\n if (value.includes(\"@\") && value.includes(\".\")) return \"email\";\n if (/^https?:\\/\\//.test(value)) return \"url\";\n if (value.length > 100) return \"textarea\";\n }\n return \"text\";\n}\n\n/** Try to infer a select field from unique values across the full dataset */\nfunction inferSelectFromData(\n key: string,\n allData: Record<string, unknown>[] | undefined,\n): { type: \"select\"; options: { value: string; label: string }[] } | null {\n if (!allData || allData.length === 0) return null;\n const uniqueValues = new Set<string>();\n for (const row of allData) {\n const v = row[key];\n if (typeof v === \"string\" && v.length > 0) uniqueValues.add(v);\n }\n if (uniqueValues.size > 0 && uniqueValues.size <= 10) {\n return {\n type: \"select\" as const,\n options: Array.from(uniqueValues)\n .sort()\n .map((v) => ({ value: v, label: v })),\n };\n }\n return null;\n}\n\n/** Generate a sensible placeholder for an auto-inferred field */\nfunction defaultPlaceholder(key: string, type: FieldType): string {\n switch (type) {\n case \"email\": return \"name@example.com\";\n case \"url\": return \"https://...\";\n case \"number\": return \"0\";\n case \"date\": return \"YYYY-MM-DD\";\n case \"textarea\": return `Enter ${titleCase(key).toLowerCase()}...`;\n default: return `Enter ${titleCase(key).toLowerCase()}`;\n }\n}\n\n/** Resolve fields from data keys when none provided */\nfunction resolveFields(\n fields: ResourceFormFieldDef[] | undefined,\n data: Record<string, unknown> | undefined,\n allData?: Record<string, unknown>[],\n autoPlaceholder = true,\n): ResourceFormFieldDef[] {\n const placeholderFor = (key: string, type: FieldType): string | undefined =>\n autoPlaceholder ? defaultPlaceholder(key, type) : undefined;\n if (fields && fields.length > 0) {\n return fields.map((f) => {\n const inferred = f.type ?? (data ? inferFieldType(data[f.key]) : \"text\");\n return {\n ...f,\n label: f.label ?? titleCase(f.key),\n type: inferred,\n placeholder: f.placeholder ?? placeholderFor(f.key, inferred),\n required: f.required ?? (inferred !== \"switch\" && inferred !== \"checkbox\" && inferred !== \"hidden\"),\n };\n });\n }\n\n if (!data) return [];\n\n return Object.keys(data)\n .filter((key) => key !== \"id\" && key !== \"created_at\" && key !== \"updated_at\")\n .map((key) => {\n // Check for select-like field first (string with few unique values)\n if (typeof data[key] === \"string\") {\n const selectInfo = inferSelectFromData(key, allData);\n if (selectInfo) {\n return {\n key,\n label: titleCase(key),\n type: selectInfo.type,\n options: selectInfo.options,\n placeholder: autoPlaceholder\n ? `Select ${titleCase(key).toLowerCase()}...`\n : undefined,\n required: true,\n };\n }\n }\n\n const inferred = inferFieldType(data[key]);\n return {\n key,\n label: titleCase(key),\n type: inferred,\n placeholder: placeholderFor(key, inferred),\n required: inferred !== \"switch\" && inferred !== \"checkbox\" && inferred !== \"hidden\",\n };\n });\n}\n\n/** Build a zod schema from resolved fields */\nfunction buildSchema(fields: ResourceFormFieldDef[]) {\n const shape: Record<string, z.ZodTypeAny> = {};\n\n for (const field of fields) {\n const fieldType = field.type ?? \"text\";\n\n if (field.hidden || fieldType === \"hidden\") continue;\n\n // File/image fields store File objects — z.any() is intentional here because\n // the File API shape varies by platform (browser File, React Native asset, etc.)\n // and form libraries may wrap files differently.\n if (fieldType === \"file\" || fieldType === \"image\") {\n shape[field.key] = field.required !== false ? z.unknown().refine((v) => v != null, { message: `${field.label ?? titleCase(field.key)} is required` }) : z.unknown().optional();\n continue;\n }\n\n switch (fieldType) {\n case \"number\": {\n let schema = z.coerce.number({ message: \"Must be a number\" });\n if (field.min != null) schema = schema.min(field.min);\n if (field.max != null) schema = schema.max(field.max);\n shape[field.key] = field.required !== false\n ? schema\n : schema.optional();\n break;\n }\n case \"array\": {\n if (field.arrayFields) {\n const itemShape: Record<string, z.ZodTypeAny> = {};\n for (const sub of field.arrayFields) {\n const subType = sub.type ?? \"text\";\n if (subType === \"number\") {\n let s = z.coerce.number({ message: \"Must be a number\" });\n if (sub.min != null) s = s.min(sub.min);\n if (sub.max != null) s = s.max(sub.max);\n itemShape[sub.key] = sub.required !== false ? s : s.optional();\n } else if (subType === \"switch\" || subType === \"checkbox\") {\n itemShape[sub.key] = z.boolean().optional();\n } else {\n let s = z.string();\n if (sub.required !== false) {\n s = s.min(1, `${sub.label ?? titleCase(sub.key)} is required`);\n }\n if (subType === \"email\") s = s.email(\"Invalid email address\");\n if (subType === \"url\") s = s.url(\"Invalid URL\");\n if (sub.maxLength != null) {\n s = s.max(\n sub.maxLength,\n `${sub.label ?? titleCase(sub.key)} must be ${sub.maxLength} characters or fewer`,\n );\n }\n itemShape[sub.key] = sub.required === false ? s.optional().or(z.literal(\"\")) : s;\n }\n }\n let arraySchema: z.ZodTypeAny = z.array(z.object(itemShape));\n if (field.arrayMin != null) arraySchema = (arraySchema as z.ZodArray<z.ZodTypeAny>).min(field.arrayMin, `Minimum ${field.arrayMin} items required`);\n if (field.arrayMax != null) arraySchema = (arraySchema as z.ZodArray<z.ZodTypeAny>).max(field.arrayMax, `Maximum ${field.arrayMax} items allowed`);\n shape[field.key] = arraySchema;\n }\n break;\n }\n case \"switch\":\n case \"checkbox\": {\n shape[field.key] = z.boolean().optional();\n break;\n }\n default: {\n // text, email, url, textarea, date, select\n let schema = z.string();\n if (field.required !== false) {\n schema = schema.min(1, `${field.label ?? titleCase(field.key)} is required`);\n }\n if (fieldType === \"email\") {\n schema = schema.email(\"Invalid email address\");\n }\n if (fieldType === \"url\") {\n schema = schema.url(\"Invalid URL\");\n }\n if (field.maxLength != null) {\n schema = schema.max(\n field.maxLength,\n `${field.label ?? titleCase(field.key)} must be ${field.maxLength} characters or fewer`,\n );\n }\n shape[field.key] = field.required === false\n ? schema.optional().or(z.literal(\"\"))\n : schema;\n break;\n }\n }\n }\n\n return z.object(shape).passthrough();\n}\n\n/** Build default values for a single array item from its sub-field definitions */\nexport function buildArrayItemDefaults(\n arrayFields: ResourceFormFieldDef[],\n): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n for (const sub of arrayFields) {\n const subType = sub.type ?? \"text\";\n if (subType === \"number\") defaults[sub.key] = undefined;\n else if (subType === \"switch\" || subType === \"checkbox\") defaults[sub.key] = false;\n else defaults[sub.key] = sub.defaultValue ?? \"\";\n }\n return defaults;\n}\n\n/** Build default values from fields and existing data */\nfunction buildDefaults(\n fields: ResourceFormFieldDef[],\n data: Record<string, unknown> | undefined,\n action: \"create\" | \"edit\",\n prefillFromUrl: boolean,\n): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n for (const field of fields) {\n if (data && field.key in data) {\n defaults[field.key] = data[field.key];\n } else if (field.defaultValue !== undefined) {\n defaults[field.key] = field.defaultValue;\n } else {\n const fieldType = field.type ?? \"text\";\n switch (fieldType) {\n case \"array\":\n defaults[field.key] = field.arrayMin\n ? Array.from({ length: field.arrayMin }, () =>\n buildArrayItemDefaults(field.arrayFields ?? []),\n )\n : [];\n break;\n case \"number\":\n defaults[field.key] = undefined;\n break;\n case \"switch\":\n case \"checkbox\":\n defaults[field.key] = false;\n break;\n default:\n defaults[field.key] = \"\";\n break;\n }\n }\n }\n\n // URL pre-fill for create mode\n if (typeof window !== \"undefined\" && typeof window.location !== \"undefined\" && typeof window.location.search === \"string\" && action === \"create\" && prefillFromUrl !== false) {\n const params = new URLSearchParams(window.location.search);\n for (const field of fields) {\n const val = params.get(field.key);\n if (val != null) {\n defaults[field.key] = field.type === \"number\" ? Number(val) : val;\n }\n }\n }\n\n return defaults;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport function useResourceForm(options: UseResourceFormOptions): UseResourceFormReturn {\n const {\n resource,\n action,\n id,\n initialData,\n fields: fieldsProp,\n listData,\n onSuccess,\n onError,\n prefillFromUrl = true,\n autoPlaceholder = true,\n validationMode,\n autosave,\n invalidates,\n warnWhenUnsaved = false,\n mutationMode = \"pessimistic\",\n undoDelayMs,\n onUndoable,\n visible = true,\n } = options;\n\n const autosaveEnabled = !!autosave;\n const debounceMs = typeof autosave === \"object\" ? autosave.debounceMs ?? 1000 : 1000;\n\n const provider = useDataProvider();\n const storage = useStorage();\n const queryClient = useQueryClient();\n\n // Fetch record for edit mode when no initialData\n const needsFetch = action === \"edit\" && !initialData && !!id;\n const fetchResult = useOne(\n resource,\n needsFetch ? id : undefined,\n { enabled: needsFetch },\n );\n\n const fetchedData = fetchResult.data ?? undefined;\n const effectiveData = initialData ?? fetchedData;\n const isLoading = needsFetch && fetchResult.isLoading;\n\n // In edit mode the form starts from the provider's form shape of the row\n // (`DataProvider.toFormValues`), for a resource whose form differs from\n // its table. The record id still comes from the row itself.\n const formSource = useMemo(\n () =>\n action === \"edit\" && effectiveData && provider.toFormValues\n ? provider.toFormValues(resource, effectiveData)\n : effectiveData,\n [action, effectiveData, provider, resource],\n );\n\n // Resolve fields\n const resolvedFields = useMemo(\n () => resolveFields(fieldsProp, formSource, listData, autoPlaceholder),\n [fieldsProp, formSource, listData, autoPlaceholder],\n );\n\n // Build schema\n const schema = useMemo(\n () => buildSchema(resolvedFields),\n [resolvedFields],\n );\n\n // Build defaults (with optional draft restoration)\n const defaultValues = useMemo(() => {\n const defaults = buildDefaults(resolvedFields, formSource, action, prefillFromUrl);\n if (autosaveEnabled && action === \"create\") {\n const key = `genesis-draft:${resource}:new`;\n const saved = storage.getItem(key);\n if (saved) {\n try {\n const draft = JSON.parse(saved);\n if (draft && typeof draft === \"object\" && !Array.isArray(draft)) {\n // Only restore keys that exist in the field definitions\n const validKeys = new Set(resolvedFields.map((f) => f.key));\n for (const k of Object.keys(draft)) {\n if (validKeys.has(k)) {\n defaults[k] = draft[k];\n }\n }\n } else {\n console.warn(`[useResourceForm] Draft for \"${resource}\" has unexpected shape, removing`);\n storage.removeItem(key);\n }\n } catch {\n console.warn(`[useResourceForm] Corrupt draft for \"${resource}\", removing`);\n storage.removeItem(key);\n }\n }\n }\n return defaults;\n }, [resolvedFields, formSource, action, prefillFromUrl, autosaveEnabled, resource, storage]);\n\n // Form\n // Cast the resolver because zod v4's passthrough() produces `unknown` for input,\n // but react-hook-form expects FieldValues (Record<string, any>).\n const resolver = useMemo(\n () => zodResolver(schema) as unknown as Resolver<Record<string, unknown>>,\n [schema],\n );\n\n const form = useForm<Record<string, unknown>>({\n resolver,\n defaultValues,\n values: action === \"edit\" ? defaultValues : undefined,\n mode: validationMode ?? \"onBlur\",\n reValidateMode: \"onChange\",\n shouldUnregister: true,\n });\n\n // Autosave effect — persist form values to storage for create mode\n useEffect(() => {\n if (!autosaveEnabled || action !== \"create\") return;\n const key = `genesis-draft:${resource}:new`;\n let timer: ReturnType<typeof setTimeout>;\n\n const subscription = form.watch((values) => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n try {\n storage.setItem(key, JSON.stringify(values));\n } catch (err) {\n console.warn(`[useResourceForm] Autosave failed for \"${resource}\":`, err instanceof Error ? err.message : String(err));\n }\n }, debounceMs);\n });\n\n return () => {\n clearTimeout(timer);\n subscription.unsubscribe();\n };\n }, [autosaveEnabled, resource, action, form, debounceMs, storage]);\n\n // Unsaved changes: RHF's isDirty, cleared by a successful save until the\n // next edit (a create form keeps its values after saving, so RHF alone\n // would still call it dirty).\n const rhfDirty = form.formState.isDirty;\n const [savedClean, setSavedClean] = useState(false);\n const savedCleanRef = useRef(false);\n useEffect(() => {\n const subscription = form.watch((_values, info) => {\n // `watch` also reports resets (no field name); only an edit dirties.\n if (!info.name) return;\n savedCleanRef.current = false;\n setSavedClean(false);\n });\n return () => subscription.unsubscribe();\n }, [form]);\n const isDirty = rhfDirty && !savedClean;\n const warn = !!warnWhenUnsaved;\n const { confirmLeave: guardConfirm } = useUnsavedChangesGuard({\n when: warn && isDirty,\n message: typeof warnWhenUnsaved === \"object\" ? warnWhenUnsaved.message : undefined,\n });\n const confirmLeave = useCallback(\n // The ref, not state: a router blocker may ask in the same tick as the\n // save's onSuccess navigates, before a re-render.\n () => (!warn || savedCleanRef.current ? true : guardConfirm()),\n [warn, guardConfirm],\n );\n const markSaved = useCallback(() => {\n savedCleanRef.current = true;\n setSavedClean(true);\n }, []);\n\n // A save that fails after it was handed off only comes back to the form\n // while the user can still see it.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n const visibleRef = useRef(visible);\n visibleRef.current = visible;\n\n /** A failed save, on the form: per-field messages and a root summary. */\n const showError = useCallback(\n (error: Error) => {\n const fieldErrors = isDataWriteError(error) ? error.fields : undefined;\n const known = new Set(resolvedFields.map((f) => f.key));\n let first: string | undefined;\n if (fieldErrors) {\n for (const [field, message] of Object.entries(fieldErrors)) {\n if (!known.has(field)) continue;\n form.setError(field, { type: \"server\", message });\n first ??= field;\n }\n }\n form.setError(\"root\", { type: \"server\", message: error.message });\n if (first) {\n try {\n form.setFocus(first);\n } catch {\n // Not rendered (hidden or custom renderForm): the summary still says it.\n }\n }\n },\n [form, resolvedFields],\n );\n\n const reportError = useCallback(\n (error: Error, handedOff?: Record<string, unknown>) => {\n // A save handed off optimistically and then refused is unsaved again,\n // if the form still shows what it saved; a closed, hidden or reset\n // form is left alone.\n const onForm =\n !handedOff ||\n (mountedRef.current && visibleRef.current && sameValue(form.getValues(), handedOff));\n if (onForm) {\n savedCleanRef.current = false;\n setSavedClean(false);\n showError(error);\n }\n if (onError) {\n onError(error);\n } else {\n console.error(`[useResourceForm] ${action} failed for \"${resource}\":`, error);\n }\n },\n [form, showError, onError, action, resource],\n );\n\n // Submit handler\n const handleSubmit = useCallback(\n async (formData: Record<string, unknown>) => {\n // What the form shows as this save goes out (raw input values, before\n // any resolver coercion), to tell later whether it still does.\n const shown = structuredCloneSafe(form.getValues());\n try {\n let recordId: string | number | undefined;\n if (action === \"edit\") {\n recordId = id ?? String((effectiveData as Record<string, unknown>)?.id ?? \"\");\n if (!recordId) {\n throw new Error(\"Cannot update record: no ID available. Provide an id prop or ensure the record has an id field.\");\n }\n }\n const before = recordId != null ? cachedRecord(queryClient, resource, recordId) : undefined;\n const outcome = await executeWrite<BaseRecord>({\n queryClient,\n provider,\n resource,\n kind: action === \"create\" ? \"create\" : \"update\",\n id: recordId,\n // The cache holds rows; patch it only when the form's values are\n // row-shaped (no provider.toFormValues reshaping this record).\n data: formSource === effectiveData ? formData : undefined,\n mode: mutationMode,\n undoDelayMs,\n onUndoable,\n send: async (ctx) => {\n const keepalive = ctx.keepalive ? { keepalive: true } : {};\n const res =\n action === \"create\"\n ? await provider.create(resource, { data: formData, ...keepalive })\n : await provider.update(resource, { id: recordId!, data: ctx.data ?? formData, ...keepalive });\n return { record: res.data, audit: res.audit };\n },\n committed: async (result) => {\n // Clear draft on successful save\n if (autosaveEnabled && action === \"create\") {\n try {\n storage.removeItem(`genesis-draft:${resource}:new`);\n } catch (err) {\n console.warn(`[useResourceForm] Draft cleanup failed for \"${resource}\":`, err instanceof Error ? err.message : String(err));\n }\n }\n // Invalidate queries to refresh data: the resource's own, then any\n // related keys the provider or the caller named.\n await invalidateResource(queryClient, resource);\n const related = relatedKeys(\n provider,\n {\n resource,\n kind: action === \"create\" ? \"create\" : \"update\",\n id: (recordId ?? result.id) as string | number,\n record: result,\n },\n invalidates,\n );\n await Promise.all(related.map((queryKey) => queryClient.invalidateQueries({ queryKey: [...queryKey] })));\n },\n failedLater: (error) => reportError(error, shown),\n });\n markSaved();\n if (outcome.status === \"committed\") {\n onSuccess?.(outcome.record);\n } else {\n onSuccess?.(\n action === \"edit\"\n ? { ...(before ?? effectiveData ?? {}), ...formData, id: recordId }\n : { ...formData },\n );\n }\n } catch (err) {\n reportError(err instanceof Error ? err : new Error(String(err)));\n }\n },\n [form, action, provider, resource, id, effectiveData, formSource, queryClient, onSuccess, autosaveEnabled, storage, invalidates, mutationMode, undoDelayMs, onUndoable, reportError, markSaved],\n );\n\n const onSubmit = useCallback(\n (e?: { preventDefault?: () => void }) => form.handleSubmit(handleSubmit)(e as React.BaseSyntheticEvent),\n [form, handleSubmit],\n );\n\n const isSaving = form.formState.isSubmitting;\n\n return {\n form,\n resolvedFields,\n onSubmit,\n handleSave: handleSubmit,\n isSaving,\n isLoading,\n isDirty,\n confirmLeave,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-resource-form.ts"],"names":[],"mappings":"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","file":"chunk-SQR4GFRM.js","sourcesContent":["import { useMemo, useCallback, useEffect, useRef, useState } from \"react\";\nimport { useForm, type UseFormReturn, type Resolver } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { z } from \"zod\";\nimport { useOne } from \"./use-one\";\nimport { useDataProvider, useStorage } from \"../provider/context\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { titleCase } from \"../utils\";\nimport type { ResourceFormFieldDef, FieldType } from \"../form-types\";\nimport type { BaseRecord, InvalidationKey } from \"../provider/types\";\nimport { relatedKeys } from \"./related-keys\";\nimport { isDataWriteError } from \"../schema/write-outcome\";\nimport {\n cachedRecord,\n executeWrite,\n invalidateResource,\n sameValue,\n type MutationModeOptions,\n} from \"./mutation-mode\";\nimport { useUnsavedChangesGuard } from \"./use-unsaved-changes-guard\";\n\n/** A deep copy where the platform allows one (form values are plain data). */\nfunction structuredCloneSafe<T>(value: T): T {\n try {\n return typeof structuredClone === \"function\" ? structuredClone(value) : value;\n } catch {\n return value;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseResourceFormOptions extends MutationModeOptions {\n resource: string;\n action: \"create\" | \"edit\";\n id?: string;\n initialData?: Record<string, unknown>;\n fields?: ResourceFormFieldDef[];\n /** Full dataset used to auto-detect select fields from unique values. */\n listData?: Record<string, unknown>[];\n /**\n * The form is done. After the save in `pessimistic` mode (with the stored\n * row); at once in `optimistic` and `undoable` modes (with the submitted\n * values over the record, and no `id` for a create).\n */\n onSuccess?: (data: Record<string, unknown>) => void;\n /**\n * The save failed. In `optimistic` and `undoable` modes the form may be\n * gone by then, so show the error from here (genesis-ui's ResourceForm\n * toasts it when no `onError` is given).\n */\n onError?: (error: Error) => void;\n /**\n * Warn before unsaved changes are lost. Default false. While the form is\n * dirty, closing or reloading the tab shows the browser's prompt, and\n * `confirmLeave()` asks before in-app navigation (wire it to a router\n * blocker; see SKILL.md \"Unsaved changes\").\n */\n warnWhenUnsaved?: boolean | { message?: string };\n /**\n * Whether the form is on screen. Default true. Pass false while it is\n * hidden but still mounted (a closed dialog). An optimistic or undoable\n * save that fails later is put back on the form (field errors, unsaved\n * again) only while the form is mounted, visible and still holds the\n * values it saved; otherwise the failure only reaches `onError`.\n */\n visible?: boolean;\n /**\n * Pre-fill create form defaults from URL query params: a param named like a\n * field (`?status=draft`) becomes that field's starting value. Default true.\n * Pass false for a form that should not read the page's URL, e.g. one\n * opened from a list whose own filters live in the query string.\n */\n prefillFromUrl?: boolean;\n /**\n * Generate a placeholder (\"Enter name\", \"name@example.com\") for a field\n * whose `placeholder` is unset. Default true. A placeholder that only\n * repeats the label adds noise without information, so `ResourceForm`\n * turns this off unless asked.\n */\n autoPlaceholder?: boolean;\n /** Validation trigger mode. Default \"onBlur\". */\n validationMode?: \"onBlur\" | \"onChange\" | \"onSubmit\";\n /** Enable autosave drafts to localStorage for create mode. */\n autosave?: boolean | { debounceMs?: number };\n /**\n * Other query keys to invalidate after a save, on top of `[resource]` and\n * the provider's own `invalidates`.\n */\n invalidates?: InvalidationKey[];\n}\n\nexport interface UseResourceFormReturn {\n form: UseFormReturn<Record<string, unknown>>;\n resolvedFields: ResourceFormFieldDef[];\n onSubmit: (e?: { preventDefault?: () => void }) => Promise<void>;\n /** Raw save handler — use with form.handleSubmit(handleSave, onInvalid). */\n handleSave: (data: Record<string, unknown>) => Promise<void>;\n isSaving: boolean;\n isLoading: boolean;\n /**\n * The form has changes that have not been saved. False again once a save\n * succeeds (or, in optimistic / undoable modes, is handed off).\n */\n isDirty: boolean;\n /**\n * For in-app navigation: true when it is fine to leave (nothing unsaved,\n * `warnWhenUnsaved` off, or the user confirmed). Asks with\n * `window.confirm` otherwise.\n */\n confirmLeave: () => boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Infer a field type from a value */\nfunction inferFieldType(value: unknown): FieldType {\n if (typeof value === \"boolean\") return \"switch\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"string\") {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(value)) return \"date\";\n if (value.includes(\"@\") && value.includes(\".\")) return \"email\";\n if (/^https?:\\/\\//.test(value)) return \"url\";\n if (value.length > 100) return \"textarea\";\n }\n return \"text\";\n}\n\n/** Try to infer a select field from unique values across the full dataset */\nfunction inferSelectFromData(\n key: string,\n allData: Record<string, unknown>[] | undefined,\n): { type: \"select\"; options: { value: string; label: string }[] } | null {\n if (!allData || allData.length === 0) return null;\n const uniqueValues = new Set<string>();\n for (const row of allData) {\n const v = row[key];\n if (typeof v === \"string\" && v.length > 0) uniqueValues.add(v);\n }\n if (uniqueValues.size > 0 && uniqueValues.size <= 10) {\n return {\n type: \"select\" as const,\n options: Array.from(uniqueValues)\n .sort()\n .map((v) => ({ value: v, label: v })),\n };\n }\n return null;\n}\n\n/** Generate a sensible placeholder for an auto-inferred field */\nfunction defaultPlaceholder(key: string, type: FieldType): string {\n switch (type) {\n case \"email\": return \"name@example.com\";\n case \"url\": return \"https://...\";\n case \"number\": return \"0\";\n case \"date\": return \"YYYY-MM-DD\";\n case \"textarea\": return `Enter ${titleCase(key).toLowerCase()}...`;\n default: return `Enter ${titleCase(key).toLowerCase()}`;\n }\n}\n\n/** Resolve fields from data keys when none provided */\nfunction resolveFields(\n fields: ResourceFormFieldDef[] | undefined,\n data: Record<string, unknown> | undefined,\n allData?: Record<string, unknown>[],\n autoPlaceholder = true,\n): ResourceFormFieldDef[] {\n const placeholderFor = (key: string, type: FieldType): string | undefined =>\n autoPlaceholder ? defaultPlaceholder(key, type) : undefined;\n if (fields && fields.length > 0) {\n return fields.map((f) => {\n const inferred = f.type ?? (data ? inferFieldType(data[f.key]) : \"text\");\n return {\n ...f,\n label: f.label ?? titleCase(f.key),\n type: inferred,\n placeholder: f.placeholder ?? placeholderFor(f.key, inferred),\n required: f.required ?? (inferred !== \"switch\" && inferred !== \"checkbox\" && inferred !== \"hidden\"),\n };\n });\n }\n\n if (!data) return [];\n\n return Object.keys(data)\n .filter((key) => key !== \"id\" && key !== \"created_at\" && key !== \"updated_at\")\n .map((key) => {\n // Check for select-like field first (string with few unique values)\n if (typeof data[key] === \"string\") {\n const selectInfo = inferSelectFromData(key, allData);\n if (selectInfo) {\n return {\n key,\n label: titleCase(key),\n type: selectInfo.type,\n options: selectInfo.options,\n placeholder: autoPlaceholder\n ? `Select ${titleCase(key).toLowerCase()}...`\n : undefined,\n required: true,\n };\n }\n }\n\n const inferred = inferFieldType(data[key]);\n return {\n key,\n label: titleCase(key),\n type: inferred,\n placeholder: placeholderFor(key, inferred),\n required: inferred !== \"switch\" && inferred !== \"checkbox\" && inferred !== \"hidden\",\n };\n });\n}\n\n/** Build a zod schema from resolved fields */\nfunction buildSchema(fields: ResourceFormFieldDef[]) {\n const shape: Record<string, z.ZodTypeAny> = {};\n\n for (const field of fields) {\n const fieldType = field.type ?? \"text\";\n\n if (field.hidden || fieldType === \"hidden\") continue;\n\n // File/image fields store File objects — z.any() is intentional here because\n // the File API shape varies by platform (browser File, React Native asset, etc.)\n // and form libraries may wrap files differently.\n if (fieldType === \"file\" || fieldType === \"image\") {\n shape[field.key] = field.required !== false ? z.unknown().refine((v) => v != null, { message: `${field.label ?? titleCase(field.key)} is required` }) : z.unknown().optional();\n continue;\n }\n\n switch (fieldType) {\n case \"number\": {\n let schema = z.coerce.number({ message: \"Must be a number\" });\n if (field.min != null) schema = schema.min(field.min);\n if (field.max != null) schema = schema.max(field.max);\n shape[field.key] = field.required !== false\n ? schema\n : schema.optional();\n break;\n }\n case \"array\": {\n if (field.arrayFields) {\n const itemShape: Record<string, z.ZodTypeAny> = {};\n for (const sub of field.arrayFields) {\n const subType = sub.type ?? \"text\";\n if (subType === \"number\") {\n let s = z.coerce.number({ message: \"Must be a number\" });\n if (sub.min != null) s = s.min(sub.min);\n if (sub.max != null) s = s.max(sub.max);\n itemShape[sub.key] = sub.required !== false ? s : s.optional();\n } else if (subType === \"switch\" || subType === \"checkbox\") {\n itemShape[sub.key] = z.boolean().optional();\n } else {\n let s = z.string();\n if (sub.required !== false) {\n s = s.min(1, `${sub.label ?? titleCase(sub.key)} is required`);\n }\n if (subType === \"email\") s = s.email(\"Invalid email address\");\n if (subType === \"url\") s = s.url(\"Invalid URL\");\n if (sub.maxLength != null) {\n s = s.max(\n sub.maxLength,\n `${sub.label ?? titleCase(sub.key)} must be ${sub.maxLength} characters or fewer`,\n );\n }\n itemShape[sub.key] = sub.required === false ? s.optional().or(z.literal(\"\")) : s;\n }\n }\n let arraySchema: z.ZodTypeAny = z.array(z.object(itemShape));\n if (field.arrayMin != null) arraySchema = (arraySchema as z.ZodArray<z.ZodTypeAny>).min(field.arrayMin, `Minimum ${field.arrayMin} items required`);\n if (field.arrayMax != null) arraySchema = (arraySchema as z.ZodArray<z.ZodTypeAny>).max(field.arrayMax, `Maximum ${field.arrayMax} items allowed`);\n shape[field.key] = arraySchema;\n }\n break;\n }\n case \"switch\":\n case \"checkbox\": {\n shape[field.key] = z.boolean().optional();\n break;\n }\n default: {\n // text, email, url, textarea, date, select\n let schema = z.string();\n if (field.required !== false) {\n schema = schema.min(1, `${field.label ?? titleCase(field.key)} is required`);\n }\n if (fieldType === \"email\") {\n schema = schema.email(\"Invalid email address\");\n }\n if (fieldType === \"url\") {\n schema = schema.url(\"Invalid URL\");\n }\n if (field.maxLength != null) {\n schema = schema.max(\n field.maxLength,\n `${field.label ?? titleCase(field.key)} must be ${field.maxLength} characters or fewer`,\n );\n }\n shape[field.key] = field.required === false\n ? schema.optional().or(z.literal(\"\"))\n : schema;\n break;\n }\n }\n }\n\n return z.object(shape).passthrough();\n}\n\n/** Build default values for a single array item from its sub-field definitions */\nexport function buildArrayItemDefaults(\n arrayFields: ResourceFormFieldDef[],\n): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n for (const sub of arrayFields) {\n const subType = sub.type ?? \"text\";\n if (subType === \"number\") defaults[sub.key] = undefined;\n else if (subType === \"switch\" || subType === \"checkbox\") defaults[sub.key] = false;\n else defaults[sub.key] = sub.defaultValue ?? \"\";\n }\n return defaults;\n}\n\n/** Build default values from fields and existing data */\nfunction buildDefaults(\n fields: ResourceFormFieldDef[],\n data: Record<string, unknown> | undefined,\n action: \"create\" | \"edit\",\n prefillFromUrl: boolean,\n): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n for (const field of fields) {\n if (data && field.key in data) {\n defaults[field.key] = data[field.key];\n } else if (field.defaultValue !== undefined) {\n defaults[field.key] = field.defaultValue;\n } else {\n const fieldType = field.type ?? \"text\";\n switch (fieldType) {\n case \"array\":\n defaults[field.key] = field.arrayMin\n ? Array.from({ length: field.arrayMin }, () =>\n buildArrayItemDefaults(field.arrayFields ?? []),\n )\n : [];\n break;\n case \"number\":\n defaults[field.key] = undefined;\n break;\n case \"switch\":\n case \"checkbox\":\n defaults[field.key] = false;\n break;\n default:\n defaults[field.key] = \"\";\n break;\n }\n }\n }\n\n // URL pre-fill for create mode\n if (typeof window !== \"undefined\" && typeof window.location !== \"undefined\" && typeof window.location.search === \"string\" && action === \"create\" && prefillFromUrl !== false) {\n const params = new URLSearchParams(window.location.search);\n for (const field of fields) {\n const val = params.get(field.key);\n if (val != null) {\n defaults[field.key] = field.type === \"number\" ? Number(val) : val;\n }\n }\n }\n\n return defaults;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport function useResourceForm(options: UseResourceFormOptions): UseResourceFormReturn {\n const {\n resource,\n action,\n id,\n initialData,\n fields: fieldsProp,\n listData,\n onSuccess,\n onError,\n prefillFromUrl = true,\n autoPlaceholder = true,\n validationMode,\n autosave,\n invalidates,\n warnWhenUnsaved = false,\n mutationMode = \"pessimistic\",\n undoDelayMs,\n onUndoable,\n visible = true,\n } = options;\n\n const autosaveEnabled = !!autosave;\n const debounceMs = typeof autosave === \"object\" ? autosave.debounceMs ?? 1000 : 1000;\n\n const provider = useDataProvider();\n const storage = useStorage();\n const queryClient = useQueryClient();\n\n // Fetch record for edit mode when no initialData\n const needsFetch = action === \"edit\" && !initialData && !!id;\n const fetchResult = useOne(\n resource,\n needsFetch ? id : undefined,\n { enabled: needsFetch },\n );\n\n const fetchedData = fetchResult.data ?? undefined;\n const effectiveData = initialData ?? fetchedData;\n const isLoading = needsFetch && fetchResult.isLoading;\n\n // In edit mode the form starts from the provider's form shape of the row\n // (`DataProvider.toFormValues`), for a resource whose form differs from\n // its table. The record id still comes from the row itself.\n const formSource = useMemo(\n () =>\n action === \"edit\" && effectiveData && provider.toFormValues\n ? provider.toFormValues(resource, effectiveData)\n : effectiveData,\n [action, effectiveData, provider, resource],\n );\n\n // Resolve fields\n const resolvedFields = useMemo(\n () => resolveFields(fieldsProp, formSource, listData, autoPlaceholder),\n [fieldsProp, formSource, listData, autoPlaceholder],\n );\n\n // Build schema\n const schema = useMemo(\n () => buildSchema(resolvedFields),\n [resolvedFields],\n );\n\n // Build defaults (with optional draft restoration)\n const defaultValues = useMemo(() => {\n const defaults = buildDefaults(resolvedFields, formSource, action, prefillFromUrl);\n if (autosaveEnabled && action === \"create\") {\n const key = `genesis-draft:${resource}:new`;\n const saved = storage.getItem(key);\n if (saved) {\n try {\n const draft = JSON.parse(saved);\n if (draft && typeof draft === \"object\" && !Array.isArray(draft)) {\n // Only restore keys that exist in the field definitions\n const validKeys = new Set(resolvedFields.map((f) => f.key));\n for (const k of Object.keys(draft)) {\n if (validKeys.has(k)) {\n defaults[k] = draft[k];\n }\n }\n } else {\n console.warn(`[useResourceForm] Draft for \"${resource}\" has unexpected shape, removing`);\n storage.removeItem(key);\n }\n } catch {\n console.warn(`[useResourceForm] Corrupt draft for \"${resource}\", removing`);\n storage.removeItem(key);\n }\n }\n }\n return defaults;\n }, [resolvedFields, formSource, action, prefillFromUrl, autosaveEnabled, resource, storage]);\n\n // Form\n // Cast the resolver because zod v4's passthrough() produces `unknown` for input,\n // but react-hook-form expects FieldValues (Record<string, any>).\n const resolver = useMemo(\n () => zodResolver(schema) as unknown as Resolver<Record<string, unknown>>,\n [schema],\n );\n\n const form = useForm<Record<string, unknown>>({\n resolver,\n defaultValues,\n values: action === \"edit\" ? defaultValues : undefined,\n mode: validationMode ?? \"onBlur\",\n reValidateMode: \"onChange\",\n shouldUnregister: true,\n });\n\n // Autosave effect — persist form values to storage for create mode\n useEffect(() => {\n if (!autosaveEnabled || action !== \"create\") return;\n const key = `genesis-draft:${resource}:new`;\n let timer: ReturnType<typeof setTimeout>;\n\n const subscription = form.watch((values) => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n try {\n storage.setItem(key, JSON.stringify(values));\n } catch (err) {\n console.warn(`[useResourceForm] Autosave failed for \"${resource}\":`, err instanceof Error ? err.message : String(err));\n }\n }, debounceMs);\n });\n\n return () => {\n clearTimeout(timer);\n subscription.unsubscribe();\n };\n }, [autosaveEnabled, resource, action, form, debounceMs, storage]);\n\n // Unsaved changes: RHF's isDirty, cleared by a successful save until the\n // next edit (a create form keeps its values after saving, so RHF alone\n // would still call it dirty).\n const rhfDirty = form.formState.isDirty;\n const [savedClean, setSavedClean] = useState(false);\n const savedCleanRef = useRef(false);\n useEffect(() => {\n const subscription = form.watch((_values, info) => {\n // `watch` also reports resets (no field name); only an edit dirties.\n if (!info.name) return;\n savedCleanRef.current = false;\n setSavedClean(false);\n });\n return () => subscription.unsubscribe();\n }, [form]);\n const isDirty = rhfDirty && !savedClean;\n const warn = !!warnWhenUnsaved;\n const { confirmLeave: guardConfirm } = useUnsavedChangesGuard({\n when: warn && isDirty,\n message: typeof warnWhenUnsaved === \"object\" ? warnWhenUnsaved.message : undefined,\n });\n const confirmLeave = useCallback(\n // The ref, not state: a router blocker may ask in the same tick as the\n // save's onSuccess navigates, before a re-render.\n () => (!warn || savedCleanRef.current ? true : guardConfirm()),\n [warn, guardConfirm],\n );\n const markSaved = useCallback(() => {\n savedCleanRef.current = true;\n setSavedClean(true);\n }, []);\n\n // A save that fails after it was handed off only comes back to the form\n // while the user can still see it.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n const visibleRef = useRef(visible);\n visibleRef.current = visible;\n\n /** A failed save, on the form: per-field messages and a root summary. */\n const showError = useCallback(\n (error: Error) => {\n const fieldErrors = isDataWriteError(error) ? error.fields : undefined;\n const known = new Set(resolvedFields.map((f) => f.key));\n let first: string | undefined;\n if (fieldErrors) {\n for (const [field, message] of Object.entries(fieldErrors)) {\n if (!known.has(field)) continue;\n form.setError(field, { type: \"server\", message });\n first ??= field;\n }\n }\n form.setError(\"root\", { type: \"server\", message: error.message });\n if (first) {\n try {\n form.setFocus(first);\n } catch {\n // Not rendered (hidden or custom renderForm): the summary still says it.\n }\n }\n },\n [form, resolvedFields],\n );\n\n const reportError = useCallback(\n (error: Error, handedOff?: Record<string, unknown>) => {\n // A save handed off optimistically and then refused is unsaved again,\n // if the form still shows what it saved; a closed, hidden or reset\n // form is left alone.\n const onForm =\n !handedOff ||\n (mountedRef.current && visibleRef.current && sameValue(form.getValues(), handedOff));\n if (onForm) {\n savedCleanRef.current = false;\n setSavedClean(false);\n showError(error);\n }\n if (onError) {\n onError(error);\n } else {\n console.error(`[useResourceForm] ${action} failed for \"${resource}\":`, error);\n }\n },\n [form, showError, onError, action, resource],\n );\n\n // Submit handler\n const handleSubmit = useCallback(\n async (formData: Record<string, unknown>) => {\n // What the form shows as this save goes out (raw input values, before\n // any resolver coercion), to tell later whether it still does.\n const shown = structuredCloneSafe(form.getValues());\n try {\n let recordId: string | number | undefined;\n if (action === \"edit\") {\n recordId = id ?? String((effectiveData as Record<string, unknown>)?.id ?? \"\");\n if (!recordId) {\n throw new Error(\"Cannot update record: no ID available. Provide an id prop or ensure the record has an id field.\");\n }\n }\n const before = recordId != null ? cachedRecord(queryClient, resource, recordId) : undefined;\n const outcome = await executeWrite<BaseRecord>({\n queryClient,\n provider,\n resource,\n kind: action === \"create\" ? \"create\" : \"update\",\n id: recordId,\n // The cache holds rows; patch it only when the form's values are\n // row-shaped (no provider.toFormValues reshaping this record).\n data: formSource === effectiveData ? formData : undefined,\n mode: mutationMode,\n undoDelayMs,\n onUndoable,\n send: async (ctx) => {\n const keepalive = ctx.keepalive ? { keepalive: true } : {};\n const res =\n action === \"create\"\n ? await provider.create(resource, { data: formData, ...keepalive })\n : await provider.update(resource, { id: recordId!, data: ctx.data ?? formData, ...keepalive });\n return { record: res.data, audit: res.audit };\n },\n committed: async (result) => {\n // Clear draft on successful save\n if (autosaveEnabled && action === \"create\") {\n try {\n storage.removeItem(`genesis-draft:${resource}:new`);\n } catch (err) {\n console.warn(`[useResourceForm] Draft cleanup failed for \"${resource}\":`, err instanceof Error ? err.message : String(err));\n }\n }\n // Invalidate queries to refresh data: the resource's own, then any\n // related keys the provider or the caller named.\n await invalidateResource(queryClient, resource);\n const related = relatedKeys(\n provider,\n {\n resource,\n kind: action === \"create\" ? \"create\" : \"update\",\n id: (recordId ?? result.id) as string | number,\n record: result,\n },\n invalidates,\n );\n await Promise.all(related.map((queryKey) => queryClient.invalidateQueries({ queryKey: [...queryKey] })));\n },\n failedLater: (error) => reportError(error, shown),\n });\n markSaved();\n if (outcome.status === \"committed\") {\n onSuccess?.(outcome.record);\n } else {\n onSuccess?.(\n action === \"edit\"\n ? { ...(before ?? effectiveData ?? {}), ...formData, id: recordId }\n : { ...formData },\n );\n }\n } catch (err) {\n reportError(err instanceof Error ? err : new Error(String(err)));\n }\n },\n [form, action, provider, resource, id, effectiveData, formSource, queryClient, onSuccess, autosaveEnabled, storage, invalidates, mutationMode, undoDelayMs, onUndoable, reportError, markSaved],\n );\n\n const onSubmit = useCallback(\n (e?: { preventDefault?: () => void }) => form.handleSubmit(handleSubmit)(e as React.BaseSyntheticEvent),\n [form, handleSubmit],\n );\n\n const isSaving = form.formState.isSubmitting;\n\n return {\n form,\n resolvedFields,\n onSubmit,\n handleSave: handleSubmit,\n isSaving,\n isLoading,\n isDirty,\n confirmLeave,\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataReadError, readFailureMessage } from './chunk-HUNGCTRA.js';
|
|
2
|
-
import { isDataWriteError, DataWriteError } from './chunk-
|
|
2
|
+
import { isDataWriteError, DataWriteError } from './chunk-LG6TUBVM.js';
|
|
3
3
|
import { titleCase } from './chunk-RYEXWQFD.js';
|
|
4
4
|
|
|
5
5
|
// src/provider/postgrest-errors.ts
|
|
@@ -17,6 +17,7 @@ function writeOutcomeFromCode(code) {
|
|
|
17
17
|
if (code === "PGRST116") return "gone";
|
|
18
18
|
if (code === "PGRST301" || code === "PGRST302" || code === "PGRST303") return "unauthenticated";
|
|
19
19
|
if (code === "28000" || code === "28P01") return "unauthenticated";
|
|
20
|
+
if (code === "23505") return "duplicate";
|
|
20
21
|
if (/^2[23][0-9A-Z]{3}$/.test(code)) return "invalid";
|
|
21
22
|
return "error";
|
|
22
23
|
}
|
|
@@ -665,5 +666,5 @@ function createSupabaseProvider(client, options = {}) {
|
|
|
665
666
|
}
|
|
666
667
|
|
|
667
668
|
export { createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, writeOutcomeFromCode };
|
|
668
|
-
//# sourceMappingURL=chunk-
|
|
669
|
-
//# sourceMappingURL=chunk-
|
|
669
|
+
//# sourceMappingURL=chunk-XKLYDAT5.js.map
|
|
670
|
+
//# sourceMappingURL=chunk-XKLYDAT5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provider/postgrest-errors.ts","../src/provider/supabase-provider.ts"],"names":["ties","run","from"],"mappings":"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","file":"chunk-XKLYDAT5.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Postgres / PostgREST error codes → Genesis write outcomes\n// ---------------------------------------------------------------------------\n\nimport {\n DataWriteError,\n isDataWriteError,\n type WriteOutcome,\n} from \"../schema/write-outcome\";\nimport type { ReadOutcome } from \"../schema/read-outcome\";\nimport { titleCase } from \"../utils\";\n\n/**\n * Maps a store error code to the read outcome it means: the write mapping,\n * with `22***` and PostgREST request errors (`PGRST1**` other than PGRST116,\n * `42703` unknown column, `42P01` unknown table) read as `invalid`.\n */\nexport function readOutcomeFromCode(code: string | null | undefined): ReadOutcome {\n if (!code) return \"error\";\n if (code === \"42703\" || code === \"42P01\" || (/^PGRST1\\d\\d$/.test(code) && code !== \"PGRST116\")) {\n return \"invalid\";\n }\n const write = writeOutcomeFromCode(code);\n return write === \"forbidden\" || write === \"gone\" || write === \"unauthenticated\" || write === \"invalid\"\n ? write\n : \"error\";\n}\n\n/**\n * Maps a Postgres SQLSTATE or PostgREST error code to the write outcome it\n * means. Anything not listed is `error`: a code is only read as a refusal or\n * a bad value when it says so.\n *\n * - `42501` (insufficient privilege, including \"new row violates row-level\n * security policy\") → `forbidden`\n * - `23505` (unique violation) → `duplicate`\n * - `22***` (data exception: bad type, out of range) and the other `23***`\n * (integrity constraint: `23503` foreign key, `23502` not null, `23514`\n * check) → `invalid`\n * - `PGRST301`–`PGRST303` (JWT missing, expired or rejected), `28000`,\n * `28P01` → `unauthenticated`\n * - `PGRST116` (one row was asked for and none came back) → `gone`\n */\nexport function writeOutcomeFromCode(code: string | null | undefined): WriteOutcome {\n if (!code) return \"error\";\n if (code === \"42501\") return \"forbidden\";\n if (code === \"PGRST116\") return \"gone\";\n if (code === \"PGRST301\" || code === \"PGRST302\" || code === \"PGRST303\") return \"unauthenticated\";\n if (code === \"28000\" || code === \"28P01\") return \"unauthenticated\";\n if (code === \"23505\") return \"duplicate\";\n if (/^2[23][0-9A-Z]{3}$/.test(code)) return \"invalid\";\n return \"error\";\n}\n\n/** A column name as Postgres reports it unquoted; anything else is not mapped. */\nconst COLUMN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/**\n * One index expression as Postgres prints it: a plain column, or one column\n * wrapped in a function, optionally cast (`lower(email::text)`,\n * `lower((email)::text)`). Anything else is not mapped.\n */\nconst WRAPPED_COLUMN = /^[A-Za-z_][A-Za-z0-9_]*\\(\\(?([A-Za-z_][A-Za-z0-9_]*)\\)?(?:::[A-Za-z_][A-Za-z0-9_ ]*)?\\)$/;\n\nfunction columnOf(expression: string): string | undefined {\n if (COLUMN.test(expression)) return expression;\n return WRAPPED_COLUMN.exec(expression)?.[1];\n}\n\n/**\n * The columns of a `Key (a, b)=(...)` detail line, or none when any is not a\n * plain column (or one column in a simple expression index). The key list is\n * read with its parentheses balanced, so an expression index such as\n * `Key (lower(email::text))=(…)` is recognised.\n */\nfunction keyColumns(details: string, tail: RegExp): string[] {\n if (!details.startsWith(\"Key (\") || !tail.test(details)) return [];\n let depth = 1;\n let end = -1;\n for (let i = \"Key (\".length; i < details.length; i++) {\n const ch = details[i];\n if (ch === \"(\") depth++;\n else if (ch === \")\" && --depth === 0) {\n end = i;\n break;\n }\n }\n if (end < 0 || details.slice(end + 1, end + 3) !== \"=(\") return [];\n const parts: string[] = [];\n let level = 0;\n let current = \"\";\n for (const ch of details.slice(\"Key (\".length, end)) {\n if (ch === \"(\") level++;\n else if (ch === \")\") level--;\n if (ch === \",\" && level === 0) {\n parts.push(current.trim());\n current = \"\";\n } else {\n current += ch;\n }\n }\n parts.push(current.trim());\n const columns = parts.map(columnOf);\n return columns.length > 0 && columns.every((c): c is string => !!c) ? columns : [];\n}\n\nfunction listLabels(columns: string[]): string {\n const labels = columns.map((c) => titleCase(c));\n if (labels.length === 1) return labels[0]!;\n return `${labels.slice(0, -1).join(\", \")} and ${labels[labels.length - 1]}`;\n}\n\n/** Field errors read from a store error, with the safe sentence that sums them up. */\nexport interface PostgrestFieldErrors {\n /** Column name → safe message for that input. */\n fields: Record<string, string>;\n /** One safe sentence for the whole error, to replace the store's raw text. */\n message: string;\n}\n\n/**\n * Reads which columns a Postgres constraint error is about, from PostgREST's\n * `message` / `details`, and gives safe messages for them. Only plain column\n * names are taken from the store's text; the values it echoes are never\n * used. A unique violation whose columns cannot be read (a complex\n * expression index, no details), or an insert/update foreign-key violation\n * whose key is an expression, gets the safe sentence with no `fields`, so the\n * store's raw text (constraint name, echoed value) never reaches the user.\n * Returns `undefined` for anything else.\n *\n * - `23505` unique violation, `Key (email)=(…) already exists.` → each\n * column: \"This value is already in use.\" (several columns: \"This\n * combination is already in use.\")\n * - `23502` not-null, `null value in column \"title\" …` → \"This field is\n * required.\"\n * - `23503` foreign key on insert/update, `Key (owner_id)=(…) is not present\n * in table …` → \"The selected item doesn't exist.\"\n */\nexport function fieldErrorsFromPostgrest(error: {\n code?: unknown;\n message?: unknown;\n details?: unknown;\n}): PostgrestFieldErrors | undefined {\n const code = typeof error.code === \"string\" ? error.code : undefined;\n const details = typeof error.details === \"string\" ? error.details.trim() : \"\";\n const message = typeof error.message === \"string\" ? error.message : \"\";\n if (code === \"23505\") {\n const columns = keyColumns(details, /\\) already exists\\.?$/);\n // Not mappable to a column: still never show the store's raw text (it\n // names the constraint and echoes the value).\n if (columns.length === 0) return { fields: {}, message: \"This value is already in use.\" };\n const each = columns.length === 1 ? \"This value is already in use.\" : \"This combination is already in use.\";\n return {\n fields: Object.fromEntries(columns.map((c) => [c, each])),\n message:\n columns.length === 1\n ? `${listLabels(columns)} is already in use.`\n : `This combination of ${listLabels(columns)} is already in use.`,\n };\n }\n if (code === \"23502\") {\n const column = /^null value in column \"([A-Za-z_][A-Za-z0-9_]*)\"(?: |$)/.exec(message)?.[1];\n if (!column || !COLUMN.test(column)) return undefined;\n return {\n fields: { [column]: \"This field is required.\" },\n message: `${titleCase(column)} is required.`,\n };\n }\n if (code === \"23503\") {\n const tail = /\\) is not present in table \"[^\"]*\"\\.?$/;\n if (!tail.test(details)) return undefined;\n const columns = keyColumns(details, tail);\n if (columns.length === 0) return { fields: {}, message: \"The selected item doesn't exist.\" };\n return {\n fields: Object.fromEntries(columns.map((c) => [c, \"The selected item doesn't exist.\"])),\n message: `${listLabels(columns)}: the selected item doesn't exist.`,\n };\n }\n return undefined;\n}\n\n/**\n * Turns anything a write threw, or the `{ message, code }` error a Supabase\n * client returned, into a `DataWriteError`. A `DataWriteError` passes through\n * unchanged; anything else keeps its message and `code`, and is kept as the\n * `cause`.\n *\n * When the error names the columns it is about (`fieldErrorsFromPostgrest`:\n * unique, not-null and foreign-key violations), the result carries `fields`\n * and its message is replaced with a safe sentence; the raw text stays on\n * the `cause`.\n */\nexport function toDataWriteError(error: unknown): DataWriteError {\n if (isDataWriteError(error)) return error;\n const shape = (typeof error === \"object\" && error !== null ? error : {}) as {\n message?: unknown;\n code?: unknown;\n details?: unknown;\n };\n const code = typeof shape.code === \"string\" ? shape.code : undefined;\n const mapped = fieldErrorsFromPostgrest(shape);\n if (mapped) {\n return new DataWriteError(writeOutcomeFromCode(code), mapped.message, {\n code,\n fields: Object.keys(mapped.fields).length > 0 ? mapped.fields : undefined,\n cause: error,\n });\n }\n const message =\n typeof shape.message === \"string\" && shape.message\n ? shape.message\n : error instanceof Error\n ? error.message\n : String(error);\n return new DataWriteError(writeOutcomeFromCode(code), message, { code, cause: error });\n}\n","import type {\n BaseRecord,\n DataProvider,\n FilterParam,\n Identifier,\n InvalidationKey,\n ListParams,\n ResourceChangeEvent,\n WriteEvent,\n} from \"./types\";\nimport { DataWriteError } from \"../schema/write-outcome\";\nimport { DataReadError, readFailureMessage } from \"../schema/read-outcome\";\nimport type { FilterOperator, ProviderCapabilities } from \"../schema/types\";\nimport { readOutcomeFromCode, toDataWriteError } from \"./postgrest-errors\";\n\n// ---------------------------------------------------------------------------\n// Minimal Supabase client shape — no hard dependency on @supabase/supabase-js\n// ---------------------------------------------------------------------------\n\n/** A chainable query builder returned by `client.from(table)`. */\ninterface SupabaseQueryBuilder {\n select(\n columns?: string,\n options?: { count?: \"exact\" | \"planned\" | \"estimated\" },\n ): SupabaseQueryBuilder;\n insert(data: Record<string, unknown> | Record<string, unknown>[]): SupabaseQueryBuilder;\n update(data: Record<string, unknown>): SupabaseQueryBuilder;\n delete(): SupabaseQueryBuilder;\n eq(column: string, value: unknown): SupabaseQueryBuilder;\n neq(column: string, value: unknown): SupabaseQueryBuilder;\n gt(column: string, value: unknown): SupabaseQueryBuilder;\n lt(column: string, value: unknown): SupabaseQueryBuilder;\n gte(column: string, value: unknown): SupabaseQueryBuilder;\n lte(column: string, value: unknown): SupabaseQueryBuilder;\n ilike(column: string, value: string): SupabaseQueryBuilder;\n in(column: string, values: unknown[]): SupabaseQueryBuilder;\n is(column: string, value: null): SupabaseQueryBuilder;\n not(column: string, operator: string, value: unknown): SupabaseQueryBuilder;\n or(filters: string): SupabaseQueryBuilder;\n order(column: string, options?: { ascending?: boolean; nullsFirst?: boolean }): SupabaseQueryBuilder;\n range(from: number, to: number): SupabaseQueryBuilder;\n single(): SupabaseQueryBuilder;\n then: Promise<{ data: unknown; error: unknown; count?: number | null }>[\"then\"];\n}\n\n/**\n * Minimal Supabase client interface — the public shape this package has\n * always exposed for a caller that wants to type its own client or a\n * wrapper around one. Unchanged: `from()` still returns `SupabaseQueryBuilder`\n * so existing consumers that annotate a variable with this type and chain\n * off it keep type-checking exactly as before.\n */\nexport interface SupabaseClient {\n from(table: string): SupabaseQueryBuilder;\n /** Supabase Realtime; needed only for `subscribe` (see `SupabaseProviderOptions.realtime`). */\n channel?(name: string): SupabaseRealtimeChannel;\n /** Releases a channel made by `channel()`. */\n removeChannel?(channel: SupabaseRealtimeChannel): unknown;\n}\n\n/**\n * One `postgres_changes` message, as Supabase Realtime sends it. Only the\n * fields the provider reads; a real payload has more.\n */\nexport interface SupabaseRealtimePayload {\n eventType: \"INSERT\" | \"UPDATE\" | \"DELETE\";\n /** The row after an insert or update (empty for a delete). */\n new?: Record<string, unknown>;\n /** For a delete or update: the old row's key (all of it with `REPLICA IDENTITY FULL`). */\n old?: Record<string, unknown>;\n}\n\n/**\n * The part of a Supabase `RealtimeChannel` the provider uses. A real\n * `@supabase/supabase-js` channel satisfies it.\n */\nexport interface SupabaseRealtimeChannel {\n on(\n type: \"postgres_changes\",\n filter: {\n event: \"*\" | \"INSERT\" | \"UPDATE\" | \"DELETE\";\n schema: string;\n table: string;\n filter?: string;\n },\n callback: (payload: SupabaseRealtimePayload) => void,\n ): SupabaseRealtimeChannel;\n subscribe(callback?: (status: string, error?: unknown) => void): SupabaseRealtimeChannel;\n unsubscribe?(): unknown;\n}\n\n/**\n * What `createSupabaseProvider` actually requires from its `client` argument\n * — deliberately looser than the public `SupabaseClient` above, and used\n * ONLY for that one parameter. A real `@supabase/supabase-js` client's\n * `from()` returns a generic, table-typed `PostgrestQueryBuilder` whose chain\n * methods don't structurally match `SupabaseQueryBuilder`, which used to\n * force callers to pass their client through `as never`. Since `unknown` is\n * a supertype of everything, any real client's `from(table: string)`\n * satisfies THIS shape without a cast; `createSupabaseProvider` narrows to\n * `SupabaseQueryBuilder` internally, once, right after each `from()` call.\n * Loosening only the input here — rather than `SupabaseClient` itself —\n * means a caller relying on `SupabaseClient`'s stricter return type for\n * their own chaining is unaffected.\n */\nexport interface SupabaseClientInput {\n from(table: string): unknown;\n /** Supabase Realtime, for `subscribe`. Any real client's `channel` fits. */\n channel?(name: string): unknown;\n removeChannel?(channel: unknown): unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Provider factory\n// ---------------------------------------------------------------------------\n\n/** What a write hook is told about the write it is part of. */\nexport interface SupabaseWriteContext {\n resource: string;\n action: \"create\" | \"update\";\n /** The row's id, for an update. */\n id?: Identifier;\n}\n\n/** Per-resource rules for `createSupabaseProvider`. Every field is optional. */\nexport interface SupabaseResourceConfig {\n /** Singular noun for failure messages, e.g. \"project\". Defaults to \"record\". */\n noun?: string;\n /** Plural for list messages, when it isn't `noun` + \"s\" (\"categories\"). */\n nounPlural?: string;\n /**\n * The columns a search covers. `[]` means the resource can't be searched,\n * and `capabilities(resource).search` reports false so a UI hides the box.\n * Set, they replace the caller's `search.fields`; omitted, those are used\n * as given.\n */\n searchFields?: readonly string[];\n /**\n * The column a sorted list orders by last, so rows with equal sort values\n * keep one order from page to page (none repeats, none is skipped).\n * Default `\"id\"`; `false` for a table or view without one. With the\n * default, a view that turns out to have no `id` column is read as before\n * (without the key order) and a development warning suggests setting this.\n */\n orderKey?: string | false;\n /**\n * `\"bin\"` for a table whose delete trigger moves the row to a recycle bin\n * instead of removing it (see `SupabaseProviderOptions.binTables`).\n * `\"hard\"` forces a plain delete even when `binTables` lists the table.\n */\n deleteMode?: \"hard\" | \"bin\";\n /**\n * Turns submitted values into the row to write: trim, drop read-only keys,\n * validate. Runs before every create and update, including the `create`\n * and `update` overrides. Throw (ideally `DataWriteError(\"invalid\", ...)`)\n * to refuse the write; nothing is sent.\n */\n prepare?: (\n values: Record<string, unknown>,\n context: SupabaseWriteContext,\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n /**\n * Creates the row some other way than an insert, e.g. a security-definer\n * RPC. Return the new row, or its id and the provider reads the row back\n * (if the read-back fails, the create is still reported as saved, with\n * just the id, so the user does not retry and make a second one). Throw to\n * fail; a Supabase `{ message, code }` error is mapped like any other.\n */\n create?: (row: Record<string, unknown>) => Promise<BaseRecord | Identifier>;\n /**\n * Updates the row some other way than an update, e.g. an RPC. Return the\n * updated row, or its id (or `true`) and the provider reads it back.\n * Returning nothing (`undefined`/`null`/`false`) means no row changed: the provider then reads the\n * row to say why (`forbidden` or `gone`), exactly as for a plain update,\n * so a function that silently skips a row never reports a save.\n */\n update?: (\n id: Identifier,\n row: Record<string, unknown>,\n ) => Promise<BaseRecord | Identifier | boolean | null | undefined | void>;\n /** Maps a stored row to edit-form values; see `DataProvider.toFormValues`. */\n toFormValues?: (record: Record<string, unknown>) => Record<string, unknown>;\n /**\n * Other cache keys a committed write to this resource makes stale, e.g.\n * `[[\"staff\"], [\"me\"]]`. Served through `DataProvider.invalidates`, which\n * `useResource` and `useResourceForm` invalidate after their writes.\n */\n invalidates?: InvalidationKey[] | ((event: WriteEvent) => InvalidationKey[]);\n /**\n * Serve `subscribe` for this resource through Supabase Realtime\n * (`postgres_changes`), so `live` lists and records refresh when the table\n * changes. The table must be in the `supabase_realtime` publication, with\n * RLS on. `false` turns it off even when `SupabaseProviderOptions.realtime`\n * covers the resource.\n */\n realtime?: boolean;\n}\n\n/** Options for `createSupabaseProvider`. All optional; none changes reads. */\nexport interface SupabaseProviderOptions {\n /**\n * Recycle-bin tables: their delete trigger turns a delete into a \"binned\"\n * mark and the binned row drops out of the caller's view (RLS or a view\n * filter). The database reports such a delete as zero rows, so for these\n * the provider checks the row is visible, deletes it, and reads it back:\n * gone from view is success, still visible is `forbidden`. A row that was\n * not visible beforehand is `gone`.\n */\n binTables?: readonly string[] | ((resource: string) => boolean);\n /** Per-resource rules, keyed by resource (table) name. */\n resources?: Record<string, SupabaseResourceConfig>;\n /**\n * Called after every committed create, update and delete, e.g. to\n * invalidate caches the Genesis hooks don't know about. Awaited, but a\n * failure is logged and never turns a committed write into a failed one.\n */\n onWrite?: (event: WriteEvent) => void | Promise<void>;\n /**\n * The most rows one list page may ask for (PostgREST's `max-rows` caps\n * reads anyway; default 1000). A larger request is refused with an\n * `invalid` `DataReadError` (its `cause` says why) rather than cut short,\n * so page boundaries never disagree with the caller's `perPage`.\n * `capabilities().maxPerPage` reports it.\n */\n maxPerPage?: number;\n /**\n * Called with every failed read, before it is thrown. The thrown\n * `DataReadError` carries a plain message for users; the store's own\n * error (its raw text and code) is its `cause`, for logging here.\n */\n onReadError?: (\n error: DataReadError,\n context: { resource: string; operation: \"getList\" | \"getOne\" | \"getMany\" },\n ) => void | Promise<void>;\n /**\n * Which resources `subscribe` serves through Supabase Realtime: `true` for\n * all, a list of names, or a test. Off by default; a resource's own\n * `resources[name].realtime` wins. Needs a client with `channel()` (any\n * `@supabase/supabase-js` client).\n */\n realtime?: boolean | readonly string[] | ((resource: string) => boolean);\n}\n\n/** A PostgREST \"undefined column\" error (42703) naming `column`. */\n/**\n * A PostgreSQL \"undefined column\" error (42703) for `table`'s own `column`:\n * `column \"id\" does not exist` or `column <table>.id does not exist`. Not a\n * related table's column (`author.id`) or any other message mentioning it.\n */\nfunction isMissingColumn(error: unknown, table: string, column: string): boolean {\n if (!error || typeof error !== \"object\") return false;\n const { code, message } = error as { code?: unknown; message?: unknown };\n if (code !== \"42703\" || typeof message !== \"string\") return false;\n const match = /^column (?:\"?([^.\"\\s]+)\"?\\.)?\"?([^.\"\\s]+)\"? does not exist$/.exec(message.trim());\n if (!match || match[2] !== column) return false;\n const ownTable = table.split(\".\").pop()?.replace(/\"/g, \"\");\n return match[1] === undefined || match[1] === ownTable;\n}\n\nconst SERVED_OPERATORS: readonly FilterOperator[] = [\n \"eq\", \"neq\", \"gt\", \"lt\", \"gte\", \"lte\", \"contains\", \"in\", \"between\", \"is_null\", \"is_not_null\",\n];\n\nfunction escapeIlike(value: string): string {\n return value.replace(/[%_\\\\]/g, (char) => `\\\\${char}`);\n}\n\nfunction isIdentifier(value: unknown): value is Identifier {\n return typeof value === \"string\" || typeof value === \"number\";\n}\n\n// ---------------------------------------------------------------------------\n// Cursor (keyset) paging\n// ---------------------------------------------------------------------------\n\n/** What a cursor holds: the sort it was made for, and the last row's values. */\ninterface CursorState {\n /** Sort field, or null when ordered by the key alone. */\n s: string | null;\n o: \"asc\" | \"desc\";\n /** The key column. */\n k: string;\n /** The last row's sort value (absent when `s` is null). */\n v?: string | number | boolean | null;\n /** The last row's key value. */\n id: string | number;\n}\n\nconst PLAIN_COLUMN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nfunction encodeCursor(state: CursorState): string {\n const bytes = new TextEncoder().encode(JSON.stringify(state));\n let binary = \"\";\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction decodeCursor(cursor: string): CursorState | undefined {\n try {\n const binary = atob(cursor.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));\n const state = JSON.parse(new TextDecoder().decode(bytes)) as CursorState;\n if (!state || typeof state !== \"object\" || typeof state.k !== \"string\" || !isIdentifier(state.id)) return undefined;\n if (state.o !== \"asc\" && state.o !== \"desc\") return undefined;\n return state;\n } catch {\n return undefined;\n }\n}\n\n/** A value quoted for a PostgREST filter, so commas, dots and parens are literal. */\nfunction quoteFilterValue(value: string | number | boolean): string {\n return `\"${String(value).replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * The PostgREST `or` clauses selecting the rows after `state`, for a list\n * ordered by `s` (`o`, nulls last when ascending and first when descending,\n * as Postgres orders them by default) and then by the key ascending.\n * @internal Exported for tests.\n */\nexport function keysetClauses(state: CursorState): string {\n const k = state.k;\n const K = quoteFilterValue(state.id);\n if (state.s === null) return `${k}.${state.o === \"asc\" ? \"gt\" : \"lt\"}.${K}`;\n const s = state.s;\n const v = state.v;\n const afterInTies = (eq: string) => `and(${eq},${k}.gt.${K})`;\n if (v === null || v === undefined) {\n // Asc: nulls are last, so only later nulls remain. Desc: nulls are\n // first, so later nulls and then every non-null row remain.\n const ties = afterInTies(`${s}.is.null`);\n return state.o === \"asc\" ? ties : `${s}.not.is.null,${ties}`;\n }\n const V = quoteFilterValue(v);\n const ties = afterInTies(`${s}.eq.${V}`);\n return state.o === \"asc\" ? `${s}.gt.${V},${ties},${s}.is.null` : `${s}.lt.${V},${ties}`;\n}\n/** `\"schema.table\"` or `\"table\"` (schema `public`), as Realtime names them. */\nfunction realtimeTable(resource: string): { schema: string; table: string } {\n const dot = resource.indexOf(\".\");\n const strip = (name: string) => name.replace(/\"/g, \"\");\n return dot < 0\n ? { schema: \"public\", table: strip(resource) }\n : { schema: strip(resource.slice(0, dot)), table: strip(resource.slice(dot + 1)) };\n}\n\nlet realtimeChannelSeq = 0;\nconst warnedRealtime = new Set<string>();\n\n/**\n * The Supabase data provider. Reads and writes go through the client you\n * pass, under that client's session and RLS.\n *\n * Writes never report a save that did not happen:\n * - `update` and `deleteOne` ask for the affected rows. Zero rows is a\n * `DataWriteError`: the row is read back, and still visible means\n * `forbidden` (RLS or a trigger refused the change), no longer visible\n * means `gone`.\n * - Database errors on writes are thrown as `DataWriteError` with the\n * outcome their code means (`writeOutcomeFromCode`) and the code kept on\n * `error.code`.\n * - Recycle-bin tables (`binTables`) succeed when the row leaves the\n * caller's view.\n *\n * Reads are unchanged: errors are thrown as an `Error` carrying `code`.\n */\nexport function createSupabaseProvider(\n client: SupabaseClientInput,\n options: SupabaseProviderOptions = {},\n): DataProvider {\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function applyFilters(\n query: SupabaseQueryBuilder,\n filters: FilterParam[] | undefined,\n ): SupabaseQueryBuilder {\n if (!filters) return query;\n for (const f of filters) {\n switch (f.operator) {\n case \"eq\":\n query = query.eq(f.field, f.value);\n break;\n case \"neq\":\n query = query.neq(f.field, f.value);\n break;\n case \"gt\":\n query = query.gt(f.field, f.value);\n break;\n case \"lt\":\n query = query.lt(f.field, f.value);\n break;\n case \"gte\":\n query = query.gte(f.field, f.value);\n break;\n case \"lte\":\n query = query.lte(f.field, f.value);\n break;\n case \"contains\":\n query = query.ilike(f.field, `%${escapeIlike(String(f.value))}%`);\n break;\n case \"in\":\n query = query.in(f.field, f.value);\n break;\n case \"is_null\":\n query = query.is(f.field, null);\n break;\n case \"is_not_null\":\n query = query.not(f.field, \"is\", null);\n break;\n case \"between\": {\n const [lo, hi] = f.value;\n query = query.gte(f.field, lo).lte(f.field, hi);\n break;\n }\n default:\n throw new Error(`[SupabaseProvider] Unknown filter operator \"${(f as FilterParam).operator}\"`);\n break;\n }\n }\n return query;\n }\n\n const maxPerPage = options.maxPerPage ?? 1000;\n // Resources found to have no \"id\" column for the default orderKey.\n const keylessResources = new Set<string>();\n\n /** Tell `onReadError` (sync or async; its failure is swallowed), then throw. */\n async function reportReadError(\n error: DataReadError,\n resource: string,\n operation: \"getList\" | \"getOne\" | \"getMany\",\n ): Promise<never> {\n try {\n await Promise.resolve(options.onReadError?.(error, { resource, operation }));\n } catch {\n // A logging hook never changes what the caller is told.\n }\n throw error;\n }\n\n /** A failed read, as a `DataReadError` with a message users can be shown. */\n async function throwIfReadError(\n result: { error: unknown },\n resource: string,\n operation: \"getList\" | \"getOne\" | \"getMany\",\n ): Promise<void> {\n if (!result.error) return;\n const raw = result.error as { message?: string; code?: string };\n const code = typeof raw.code === \"string\" ? raw.code : undefined;\n const outcome = readOutcomeFromCode(code);\n const error = new DataReadError(\n outcome,\n readFailureMessage(outcome, nounFor(resource), operation === \"getOne\", configFor(resource).nounPlural),\n { code, cause: result.error },\n );\n await reportReadError(error, resource, operation);\n }\n\n // ---------------------------------------------------------------------------\n // Write helpers\n // ---------------------------------------------------------------------------\n\n const from = (resource: string) => client.from(resource) as SupabaseQueryBuilder;\n const configFor = (resource: string): SupabaseResourceConfig =>\n options.resources?.[resource] ?? {};\n const nounFor = (resource: string) => configFor(resource).noun ?? \"record\";\n\n function realtimeEnabled(resource: string): boolean {\n if (typeof client.channel !== \"function\") return false;\n const own = configFor(resource).realtime;\n if (own !== undefined) return own;\n const all = options.realtime;\n if (!all) return false;\n if (all === true) return true;\n return typeof all === \"function\" ? all(resource) : all.includes(resource);\n }\n\n function isBinTable(resource: string): boolean {\n const mode = configFor(resource).deleteMode;\n if (mode) return mode === \"bin\";\n const bin = options.binTables;\n if (!bin) return false;\n return typeof bin === \"function\" ? bin(resource) : bin.includes(resource);\n }\n\n /** Awaits a write-path query: its rows, or a `DataWriteError`. */\n async function run(query: SupabaseQueryBuilder): Promise<unknown[]> {\n let result: { data: unknown; error: unknown };\n try {\n result = (await query) as { data: unknown; error: unknown };\n } catch (error) {\n throw toDataWriteError(error);\n }\n if (result.error) throw toDataWriteError(result.error);\n if (Array.isArray(result.data)) return result.data;\n return result.data == null ? [] : [result.data];\n }\n\n async function isVisible(resource: string, id: Identifier): Promise<boolean> {\n return (await run(from(resource).select(\"id\").eq(\"id\", id))).length > 0;\n }\n\n async function readBack(resource: string, id: Identifier): Promise<BaseRecord | undefined> {\n return (await run(from(resource).select(\"*\").eq(\"id\", id)))[0] as BaseRecord | undefined;\n }\n\n function goneError(resource: string): DataWriteError {\n return new DataWriteError(\n \"gone\",\n `This ${nounFor(resource)} no longer exists, or you can no longer see it.`,\n );\n }\n\n /**\n * A write matched no rows: read the row back to say why. Still visible\n * means the change was refused; not visible means it is gone (deleted, or\n * hidden from this user — the two can't be told apart under RLS).\n */\n async function noRowsError(\n resource: string,\n id: Identifier,\n verb: \"change\" | \"delete\",\n ): Promise<DataWriteError> {\n let visible: boolean;\n try {\n visible = await isVisible(resource, id);\n } catch (error) {\n const cause = toDataWriteError(error);\n return new DataWriteError(\n cause.outcome === \"unauthenticated\" ? \"unauthenticated\" : \"error\",\n `This ${nounFor(resource)} was not ${verb === \"change\" ? \"changed\" : \"deleted\"}, and reading it back failed (${cause.message}).`,\n { code: cause.code, cause: error },\n );\n }\n if (visible) {\n return new DataWriteError(\"forbidden\", `You can't ${verb} this ${nounFor(resource)}.`);\n }\n return goneError(resource);\n }\n\n async function prepare(\n resource: string,\n values: Record<string, unknown>,\n context: SupabaseWriteContext,\n ): Promise<Record<string, unknown>> {\n const rule = configFor(resource).prepare;\n if (!rule) return values;\n try {\n return await rule({ ...values }, context);\n } catch (error) {\n throw toDataWriteError(error);\n }\n }\n\n /** After a committed write. Never turns it into a failure. */\n async function committed(event: WriteEvent): Promise<void> {\n if (!options.onWrite) return;\n try {\n await options.onWrite(event);\n } catch (error) {\n console.error(`[SupabaseProvider] onWrite failed for \"${event.resource}\":`, error);\n }\n }\n\n // ---------------------------------------------------------------------------\n // DataProvider implementation\n // ---------------------------------------------------------------------------\n\n /** The search as PostgREST `or` clauses, or \"\" for none. */\n function searchClauses(resource: string, params: ListParams): string {\n const searchFields = configFor(resource).searchFields ?? params.search?.fields ?? [];\n if (!params.search || !params.search.query || searchFields.length === 0) return \"\";\n const escaped = escapeIlike(params.search.query);\n const safeFieldPattern = /^[a-zA-Z_][a-zA-Z0-9_.]*$/;\n return searchFields\n .filter((f) => safeFieldPattern.test(f))\n // Quoted, so commas, dots and parens in the query stay literal (also\n // when nested inside the keyset's `and(or(…))`).\n .map((f) => `${f}.ilike.${quoteFilterValue(`%${escaped}%`)}`)\n .join(\",\");\n }\n\n /** A cursor request this provider can't serve: `invalid`, with why as the cause. */\n function refuseCursor(resource: string, why: string): Promise<never> {\n return reportReadError(\n new DataReadError(\n \"invalid\",\n readFailureMessage(\"invalid\", nounFor(resource), false, configFor(resource).nounPlural),\n { cause: new Error(`[SupabaseProvider] \"${resource}\": ${why}`) },\n ),\n resource,\n \"getList\",\n );\n }\n\n /**\n * One page by keyset: ordered by the sort column and then the key, the\n * rows after the cursor's row, plus one more to tell whether a next page\n * exists. Counted only on the first page.\n */\n async function getCursorPage(\n resource: string,\n params: ListParams,\n key: string | false,\n ): Promise<{ data: unknown[]; total: number; nextCursor: string | null }> {\n const { cursor } = params.pagination!;\n // The look-ahead row must fit under PostgREST's max-rows (maxPerPage), or\n // it is dropped and the list would end after one page. A keyset page can\n // be shorter than asked without skipping or repeating rows.\n const perPage = Math.max(1, Math.min(params.pagination!.perPage, maxPerPage - 1));\n if (!key) {\n return refuseCursor(resource, \"cursor paging needs a unique key column to order by; its orderKey is false. Set orderKey to a unique, non-null column, or page by offset.\");\n }\n if (!PLAIN_COLUMN.test(key)) return refuseCursor(resource, `the key column \"${key}\" can't be used in a cursor.`);\n const sort = params.sort && params.sort.field !== key ? params.sort : undefined;\n if (sort && !PLAIN_COLUMN.test(sort.field)) {\n return refuseCursor(resource, `cursor paging can sort only by a plain column, not \"${sort.field}\".`);\n }\n const order: \"asc\" | \"desc\" = params.sort?.order ?? \"asc\";\n const sortField = sort ? sort.field : null;\n\n let after: CursorState | undefined;\n if (cursor) {\n after = decodeCursor(cursor);\n if (!after) return refuseCursor(resource, \"the cursor is not one this provider made.\");\n if (after.s !== sortField || after.o !== order || after.k !== key) {\n return refuseCursor(resource, \"the cursor was made for a different sort; start again from the first page (cursor: null).\");\n }\n }\n\n let query = from(resource).select(\n params.select ?? \"*\",\n ...(cursor ? [] : [{ count: \"exact\" as const }]),\n );\n query = applyFilters(query, params.filters);\n const search = searchClauses(resource, params);\n const keyset = after ? keysetClauses(after) : \"\";\n // Both are OR groups that must hold together: nest them in one `or`.\n if (search && keyset) query = query.or(`and(or(${search}),or(${keyset}))`);\n else if (search || keyset) query = query.or(search || keyset);\n\n if (sortField) {\n // Pinned to Postgres's default null placement, which the keyset assumes.\n query = query.order(sortField, { ascending: order === \"asc\", nullsFirst: order === \"desc\" });\n query = query.order(key, { ascending: true });\n } else {\n query = query.order(key, { ascending: order === \"asc\" });\n }\n query = query.range(0, perPage);\n\n const result = (await query) as unknown as { data: unknown[] | null; error: unknown; count?: number | null };\n await throwIfReadError(result, resource, \"getList\");\n const rows = (result.data ?? []) as Record<string, unknown>[];\n const page = rows.slice(0, perPage);\n let nextCursor: string | null = null;\n if (rows.length > perPage) {\n const last = page[page.length - 1]!;\n const id = last[key];\n const v = sortField ? last[sortField] : undefined;\n if (!isIdentifier(id) || (sortField && !(sortField in last))) {\n return refuseCursor(resource, `the selected columns must include \"${key}\"${sortField ? ` and \"${sortField}\"` : \"\"} to page by cursor.`);\n }\n if (v !== undefined && v !== null && typeof v === \"object\") {\n return refuseCursor(resource, `cursor paging can't sort by \"${sortField}\": its values aren't plain (text, number, date, boolean).`);\n }\n nextCursor = encodeCursor({\n s: sortField,\n o: order,\n k: key,\n ...(sortField ? { v: (v ?? null) as CursorState[\"v\"] } : {}),\n id,\n });\n }\n return { data: page, total: cursor ? -1 : (result.count ?? 0), nextCursor };\n }\n\n const provider: DataProvider = {\n async getList(resource, params) {\n // Refused, not cut short: a shorter page than the caller asked for\n // would shift every later page's boundary and skip or repeat rows.\n if (params.pagination && params.pagination.perPage > maxPerPage) {\n const { perPage } = params.pagination;\n await reportReadError(\n new DataReadError(\n \"invalid\",\n readFailureMessage(\"invalid\", nounFor(resource), false, configFor(resource).nounPlural),\n {\n cause: new Error(\n `[SupabaseProvider] \"${resource}\" asked for ${perPage} rows per page; the most is ${maxPerPage} (maxPerPage). Ask for at most ${maxPerPage} and page through the rest.`,\n ),\n },\n ),\n resource,\n \"getList\",\n );\n }\n\n const configuredKey = configFor(resource).orderKey;\n if (params.pagination && params.pagination.cursor !== undefined) {\n return getCursorPage(resource, params, configuredKey === undefined ? \"id\" : configuredKey) as never;\n }\n const run = (key: string | false) => {\n let query = (client.from(resource) as SupabaseQueryBuilder).select(\n params.select ?? \"*\",\n { count: \"exact\" },\n );\n\n query = applyFilters(query, params.filters);\n\n // Search — convert to OR of ilike. A resource's configured\n // `searchFields` win over the caller's.\n const clauses = searchClauses(resource, params);\n if (clauses) {\n query = query.or(clauses);\n }\n\n // Sort, then the key column, so equal sort values keep one order\n // across pages (otherwise a row can repeat on page 2 or be skipped).\n // An unsorted page is ordered by the key alone: without an ORDER BY\n // the database may return pages in any order.\n if (params.sort) {\n query = query.order(params.sort.field, {\n ascending: params.sort.order === \"asc\",\n });\n if (key && key !== params.sort.field) query = query.order(key, { ascending: true });\n } else if (params.pagination && key) {\n query = query.order(key, { ascending: true });\n }\n\n if (params.pagination) {\n const { page, perPage } = params.pagination;\n const from = (page - 1) * perPage;\n const to = from + perPage - 1;\n query = query.range(from, to);\n }\n\n return query as unknown as Promise<{\n data: unknown[];\n error: unknown;\n count?: number | null;\n }>;\n };\n\n // The default key (\"id\") is a guess: a view without that column reads\n // as before, without the key order, and is not ordered by it again.\n const guessKey = configuredKey === undefined && !keylessResources.has(resource);\n let result = await run(configuredKey ?? (keylessResources.has(resource) ? false : \"id\"));\n if (guessKey && isMissingColumn(result.error, resource, \"id\")) {\n keylessResources.add(resource);\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[SupabaseProvider] \"${resource}\" has no \"id\" column, so its pages have no stable order. Set resources.${resource}.orderKey to a unique column (or false to silence this).`,\n );\n }\n result = await run(false);\n }\n await throwIfReadError(result, resource, \"getList\");\n\n return { data: result.data ?? [], total: result.count ?? 0 } as never;\n },\n\n async getOne(resource, params) {\n const result = (await (client.from(resource) as SupabaseQueryBuilder)\n .select(params.select ?? \"*\")\n .eq(\"id\", params.id)\n .single()) as { data: unknown; error: unknown };\n await throwIfReadError(result, resource, \"getOne\");\n return { data: result.data } as never;\n },\n\n async getMany(resource, params) {\n if (params.ids.length === 0) return { data: [] } as never;\n const result = (await (client.from(resource) as SupabaseQueryBuilder)\n .select(\"*\")\n .in(\"id\", params.ids)) as { data: unknown[]; error: unknown };\n await throwIfReadError(result, resource, \"getMany\");\n return { data: result.data ?? [] } as never;\n },\n\n async capabilities(resource?: string): Promise<ProviderCapabilities> {\n return {\n search: resource ? configFor(resource).searchFields?.length !== 0 : true,\n sort: true,\n filterOperators: SERVED_OPERATORS,\n bulkWrites: false,\n versionedWrites: false,\n compositeKeys: false,\n multiSort: false,\n create: true,\n delete: true,\n maxPerPage,\n softDelete: resource ? isBinTable(resource) : false,\n cursorPagination: resource ? configFor(resource).orderKey !== false : true,\n realtime: resource\n ? realtimeEnabled(resource)\n : typeof client.channel === \"function\" &&\n (!!options.realtime ||\n Object.values(options.resources ?? {}).some((r) => r.realtime === true)),\n };\n },\n\n subscribe(resource, params, callback) {\n if (!realtimeEnabled(resource)) {\n if (process.env.NODE_ENV !== \"production\" && !warnedRealtime.has(resource)) {\n warnedRealtime.add(resource);\n console.warn(\n typeof client.channel !== \"function\"\n ? `[SupabaseProvider] \"${resource}\" was subscribed to, but the client has no channel() (Supabase Realtime), so nothing will be reported.`\n : `[SupabaseProvider] \"${resource}\" was subscribed to, but realtime is off for it. Set resources.${resource}.realtime (or the realtime option) to true.`,\n );\n }\n return () => {};\n }\n const { schema, table } = realtimeTable(resource);\n // No server-side `id=eq.` filter for one record: Realtime never\n // delivers DELETE events through a filter, so the id is matched below.\n // A unique topic: supabase-js hands back an existing channel for a\n // topic already open, and removing it would end the other subscriber.\n const channel = client.channel!(\n `genesis:${resource}:${++realtimeChannelSeq}`,\n ) as SupabaseRealtimeChannel;\n let closed = false;\n let subscribedOnce = false;\n let interrupted = false;\n const emit = (event: ResourceChangeEvent) => {\n if (closed) return;\n try {\n callback(event);\n } catch (error) {\n console.error(`[SupabaseProvider] a realtime callback for \"${resource}\" threw:`, error);\n }\n };\n channel\n .on(\n \"postgres_changes\",\n { event: \"*\", schema, table },\n (payload) => {\n // Only the id: the payload is a hint, never data to show. Realtime\n // applies RLS to inserts and updates, but a delete's old key is\n // sent to every subscriber, so nothing else is passed on.\n const row = payload.eventType === \"DELETE\" ? payload.old : payload.new;\n const id = row?.[\"id\"];\n if (params.id != null && isIdentifier(id) && String(id) !== String(params.id)) return;\n const type =\n payload.eventType === \"INSERT\" ? \"created\" : payload.eventType === \"UPDATE\" ? \"updated\" : \"deleted\";\n emit(isIdentifier(id) ? { type, id } : { type });\n },\n )\n .subscribe((status) => {\n if (status === \"SUBSCRIBED\") {\n // Back after a drop: changes made meanwhile were not sent.\n if (subscribedOnce && interrupted) emit({ type: \"changed\" });\n subscribedOnce = true;\n interrupted = false;\n } else if (status === \"CHANNEL_ERROR\" || status === \"TIMED_OUT\" || status === \"CLOSED\") {\n interrupted = true;\n }\n });\n return () => {\n if (closed) return;\n closed = true;\n try {\n const done =\n typeof client.removeChannel === \"function\"\n ? client.removeChannel(channel)\n : channel.unsubscribe?.();\n // A failed removal (socket already gone) is nothing to report.\n if (done && typeof (done as Promise<unknown>).catch === \"function\") {\n (done as Promise<unknown>).catch(() => {});\n }\n } catch {\n // As above.\n }\n };\n },\n\n async create(resource, params) {\n const row = await prepare(resource, params.data as Record<string, unknown>, {\n resource,\n action: \"create\",\n });\n const override = configFor(resource).create;\n let record: BaseRecord;\n if (override) {\n let returned: BaseRecord | Identifier;\n try {\n returned = await override(row);\n } catch (error) {\n throw toDataWriteError(error);\n }\n if (isIdentifier(returned)) {\n // The row exists from here on. A failed read-back must not report\n // the create as failed: the user would retry and make a second one.\n record = (await readBack(resource, returned).catch(() => undefined)) ?? { id: returned };\n } else if (returned && typeof returned === \"object\" && isIdentifier(returned.id)) {\n record = returned;\n } else {\n throw new DataWriteError(\n \"error\",\n `[SupabaseProvider] The create rule for \"${resource}\" returned neither the new row nor its id.`,\n );\n }\n } else {\n const rows = await run(from(resource).insert(row).select(\"*\").single());\n record = rows[0] as BaseRecord;\n }\n await committed({ resource, kind: \"create\", id: record.id, record });\n return { data: record } as never;\n },\n\n async update(resource, params) {\n const { id } = params;\n const row = await prepare(resource, params.data as Record<string, unknown>, {\n resource,\n action: \"update\",\n id,\n });\n const override = configFor(resource).update;\n let record: BaseRecord;\n if (override) {\n let returned: BaseRecord | Identifier | boolean | null | undefined | void;\n try {\n returned = await override(id, row);\n } catch (error) {\n throw toDataWriteError(error);\n }\n const result: unknown = returned;\n if (result == null || result === false) throw await noRowsError(resource, id, \"change\");\n if (isIdentifier(result) || result === true) {\n // The change committed; a failed read-back still reports it saved.\n const readId = result === true ? id : result;\n record = (await readBack(resource, readId).catch(() => undefined)) ?? { ...row, id: readId };\n } else if (typeof result === \"object\") {\n record = { id, ...(result as Record<string, unknown>) } as BaseRecord;\n } else {\n throw new DataWriteError(\n \"error\",\n `[SupabaseProvider] The update rule for \"${resource}\" returned neither the row, its id, nor nothing.`,\n );\n }\n } else {\n const rows = await run(from(resource).update(row).eq(\"id\", id).select(\"*\"));\n if (rows.length === 0) throw await noRowsError(resource, id, \"change\");\n record = rows[0] as BaseRecord;\n }\n await committed({ resource, kind: \"update\", id, record });\n return { data: record } as never;\n },\n\n async deleteOne(resource, params) {\n const { id } = params;\n let deletedId: Identifier = id;\n if (isBinTable(resource)) {\n // A binned delete reports zero rows whether or not it worked, so the\n // answer comes from visibility before and after.\n if (!(await isVisible(resource, id))) throw goneError(resource);\n await run(from(resource).delete().eq(\"id\", id));\n let stillVisible: boolean;\n try {\n stillVisible = await isVisible(resource, id);\n } catch (error) {\n const cause = toDataWriteError(error);\n throw new DataWriteError(\n \"error\",\n `The ${nounFor(resource)} may not have been deleted: checking it failed (${cause.message}).`,\n { code: cause.code, cause: error },\n );\n }\n if (stillVisible) {\n throw new DataWriteError(\"forbidden\", `You can't delete this ${nounFor(resource)}.`);\n }\n } else {\n const rows = await run(from(resource).delete().eq(\"id\", id).select(\"id\"));\n if (rows.length === 0) throw await noRowsError(resource, id, \"delete\");\n const returnedId = (rows[0] as { id?: unknown }).id;\n if (isIdentifier(returnedId)) deletedId = returnedId;\n }\n await committed({ resource, kind: \"delete\", id: deletedId });\n return { data: { id: deletedId } };\n },\n\n toFormValues(resource, record) {\n const map = configFor(resource).toFormValues;\n return map ? map(record) : record;\n },\n\n invalidates(event) {\n const keys = configFor(event.resource).invalidates;\n if (!keys) return [];\n return typeof keys === \"function\" ? keys(event) : keys;\n },\n };\n\n return provider;\n}\n"]}
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '../chunk-V3GDAELU.js';
|
|
2
2
|
export { useInfiniteResource } from '../chunk-ADD2RIGA.js';
|
|
3
|
-
export { buildArrayItemDefaults, useResourceForm } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
3
|
+
export { buildArrayItemDefaults, useResourceForm } from '../chunk-SQR4GFRM.js';
|
|
4
|
+
import '../chunk-LG6TUBVM.js';
|
|
5
5
|
export { useOne } from '../chunk-ZKMAU6NN.js';
|
|
6
6
|
export { useResource } from '../chunk-QFR6YJ3R.js';
|
|
7
7
|
export { DEFAULT_LIVE_DEBOUNCE_MS } from '../chunk-KXVHDK3Q.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { buildArrayItemDefaults, useResourceForm } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { buildArrayItemDefaults, useResourceForm } from '../chunk-SQR4GFRM.js';
|
|
2
|
+
import '../chunk-LG6TUBVM.js';
|
|
3
3
|
import '../chunk-ZKMAU6NN.js';
|
|
4
4
|
import '../chunk-KXVHDK3Q.js';
|
|
5
5
|
import '../chunk-XQO4OH2N.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { A as ArrayFilter, B as BaseRecord, a as BulkChange, b as BulkResult, C as CreateParams, c as CreateResult, D as DataProvider, d as DeleteParams, e as DeleteResult, F as FilterParam, G as GetManyParams, f as GetManyResult, g as GetOneParams, h as GetOneResult, H as HistoryParams, I as Identifier, i as ImportParams, j as InvalidationKey, L as ListParams, k as ListResult, N as NullFilter, P as PaginationParam, R as RangeFilter, l as ResourceChangeEvent, m as RowFailure, S as ScalarFilter, n as SortParam, o as SubscribeParams, U as UpdateParams, p as UpdateResult, W as WriteEvent } from './types-CS9UpxQS.js';
|
|
2
|
-
export { D as DataReadError, a as DataReadErrorOptions, b as DataWriteError, c as DataWriteErrorOptions, R as ReadOutcome, W as WriteOutcome, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from './read-outcome-
|
|
2
|
+
export { D as DataReadError, a as DataReadErrorOptions, b as DataWriteError, c as DataWriteErrorOptions, R as ReadOutcome, W as WriteOutcome, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from './read-outcome-B6nACXZ7.js';
|
|
3
3
|
export { DataProviderRoot, DataProviderRootProps, GenesisProvider, GenesisProviderProps, MockProviderOptions, PostgrestFieldErrors, SupabaseClient, SupabaseClientInput, SupabaseProviderOptions, SupabaseRealtimeChannel, SupabaseRealtimePayload, SupabaseResourceConfig, SupabaseWriteContext, createMockProvider, createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, useDataProvider, useStorage, writeOutcomeFromCode } from './provider/index.js';
|
|
4
4
|
export { S as StorageAdapter } from './types-DKcxHXxq.js';
|
|
5
5
|
export { createLocalStorageAdapter, createMemoryStorageAdapter, createNoopStorageAdapter } from './storage/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, writeOutcomeFromCode } from './chunk-
|
|
1
|
+
export { createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, writeOutcomeFromCode } from './chunk-XKLYDAT5.js';
|
|
2
2
|
export { decodeRecordKey, encodeRecordKey, keyFields } from './chunk-KV2HW4G4.js';
|
|
3
3
|
export { DataReadError, isDataReadError, readFailureMessage } from './chunk-HUNGCTRA.js';
|
|
4
4
|
import './chunk-XCX2TRBL.js';
|
|
5
5
|
import './chunk-65SXNHWE.js';
|
|
6
6
|
import './chunk-V3GDAELU.js';
|
|
7
7
|
export { useInfiniteResource } from './chunk-ADD2RIGA.js';
|
|
8
|
-
export { buildArrayItemDefaults, useResourceForm } from './chunk-
|
|
9
|
-
export { DataWriteError, isDataWriteError } from './chunk-
|
|
8
|
+
export { buildArrayItemDefaults, useResourceForm } from './chunk-SQR4GFRM.js';
|
|
9
|
+
export { DataWriteError, isDataWriteError } from './chunk-LG6TUBVM.js';
|
|
10
10
|
export { useOne } from './chunk-ZKMAU6NN.js';
|
|
11
11
|
export { useResource } from './chunk-QFR6YJ3R.js';
|
|
12
12
|
export { DEFAULT_LIVE_DEBOUNCE_MS } from './chunk-KXVHDK3Q.js';
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { D as DataProvider, I as Identifier, B as BaseRecord, j as InvalidationKey, W as WriteEvent } from '../types-CS9UpxQS.js';
|
|
2
2
|
export { A as ArrayFilter, a as BulkChange, b as BulkResult, C as CreateParams, c as CreateResult, d as DeleteParams, e as DeleteResult, F as FilterParam, G as GetManyParams, f as GetManyResult, g as GetOneParams, h as GetOneResult, H as HistoryParams, i as ImportParams, L as ListParams, k as ListResult, N as NullFilter, P as PaginationParam, R as RangeFilter, l as ResourceChangeEvent, m as RowFailure, S as ScalarFilter, n as SortParam, o as SubscribeParams, U as UpdateParams, p as UpdateResult } from '../types-CS9UpxQS.js';
|
|
3
|
-
import { D as DataReadError, R as ReadOutcome, b as DataWriteError, W as WriteOutcome } from '../read-outcome-
|
|
4
|
-
export { a as DataReadErrorOptions, c as DataWriteErrorOptions, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from '../read-outcome-
|
|
3
|
+
import { D as DataReadError, R as ReadOutcome, b as DataWriteError, W as WriteOutcome } from '../read-outcome-B6nACXZ7.js';
|
|
4
|
+
export { a as DataReadErrorOptions, c as DataWriteErrorOptions, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from '../read-outcome-B6nACXZ7.js';
|
|
5
5
|
import * as react from 'react';
|
|
6
6
|
import { ReactNode } from 'react';
|
|
7
7
|
import { QueryClient } from '@tanstack/react-query';
|
|
@@ -256,9 +256,10 @@ declare function readOutcomeFromCode(code: string | null | undefined): ReadOutco
|
|
|
256
256
|
*
|
|
257
257
|
* - `42501` (insufficient privilege, including "new row violates row-level
|
|
258
258
|
* security policy") → `forbidden`
|
|
259
|
-
* - `
|
|
260
|
-
*
|
|
261
|
-
* `
|
|
259
|
+
* - `23505` (unique violation) → `duplicate`
|
|
260
|
+
* - `22***` (data exception: bad type, out of range) and the other `23***`
|
|
261
|
+
* (integrity constraint: `23503` foreign key, `23502` not null, `23514`
|
|
262
|
+
* check) → `invalid`
|
|
262
263
|
* - `PGRST301`–`PGRST303` (JWT missing, expired or rejected), `28000`,
|
|
263
264
|
* `28P01` → `unauthenticated`
|
|
264
265
|
* - `PGRST116` (one row was asked for and none came back) → `gone`
|
package/dist/provider/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, writeOutcomeFromCode } from '../chunk-
|
|
1
|
+
export { createSupabaseProvider, fieldErrorsFromPostgrest, readOutcomeFromCode, toDataWriteError, writeOutcomeFromCode } from '../chunk-XKLYDAT5.js';
|
|
2
2
|
export { DataReadError, isDataReadError, readFailureMessage } from '../chunk-HUNGCTRA.js';
|
|
3
|
-
export { DataWriteError, isDataWriteError } from '../chunk-
|
|
3
|
+
export { DataWriteError, isDataWriteError } from '../chunk-LG6TUBVM.js';
|
|
4
4
|
import '../chunk-RYEXWQFD.js';
|
|
5
5
|
export { DataProviderRoot, GenesisProvider, createMockProvider, useDataProvider, useStorage } from '../chunk-GGSXSI6Z.js';
|
|
6
6
|
import '../chunk-ZYJUEJ4Z.js';
|
|
@@ -9,13 +9,16 @@ import { D as DataRow } from './types-C7FJtFXV.js';
|
|
|
9
9
|
* - `forbidden`: the row is visible and unchanged, but the app or the
|
|
10
10
|
* database does not let this user make this change. Only reported when
|
|
11
11
|
* that is proven, never assumed from "zero rows changed".
|
|
12
|
+
* - `duplicate`: a row with the same unique key already exists (`23505`).
|
|
13
|
+
* A caller keeping "one live row per key" (a draft, a natural-key upsert)
|
|
14
|
+
* adopts the existing row instead; `fields` still names the clashing field.
|
|
12
15
|
* - `invalid`: the store rejected the value (type, constraint, not-null).
|
|
13
16
|
* - `audit_failed`: the audit entry could not be written, so the edit was
|
|
14
17
|
* rolled back with it.
|
|
15
18
|
* - `unauthenticated`: no signed-in user, or the session expired.
|
|
16
19
|
* - `error`: anything else. The edit did not commit.
|
|
17
20
|
*/
|
|
18
|
-
type WriteOutcome = "conflict" | "gone" | "forbidden" | "invalid" | "audit_failed" | "unauthenticated" | "error";
|
|
21
|
+
type WriteOutcome = "conflict" | "gone" | "forbidden" | "duplicate" | "invalid" | "audit_failed" | "unauthenticated" | "error";
|
|
19
22
|
interface DataWriteErrorOptions {
|
|
20
23
|
/** The row as it is now, for a `conflict`. Only fields the user may read. */
|
|
21
24
|
current?: DataRow;
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { e as ResourceContract, D as DataRow } from '../types-C7FJtFXV.js';
|
|
2
2
|
export { A as AuditEntry, F as FieldPermissions, a as FieldReference, b as FieldSchema, c as FilterOperator, P as ProviderCapabilities, R as RecordComment, d as ResourceAccess, f as ResourceRelation, g as ResourceSchema, h as ResourceSummary, i as RowAction, S as StorageType, V as VersionField } from '../types-C7FJtFXV.js';
|
|
3
3
|
import { I as Identifier } from '../types-CS9UpxQS.js';
|
|
4
|
-
export { D as DataReadError, a as DataReadErrorOptions, b as DataWriteError, c as DataWriteErrorOptions, R as ReadOutcome, W as WriteOutcome, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from '../read-outcome-
|
|
4
|
+
export { D as DataReadError, a as DataReadErrorOptions, b as DataWriteError, c as DataWriteErrorOptions, R as ReadOutcome, W as WriteOutcome, i as isDataReadError, d as isDataWriteError, r as readFailureMessage } from '../read-outcome-B6nACXZ7.js';
|
|
5
5
|
export { FieldType as WidgetHint } from '../form-types.js';
|
|
6
6
|
|
|
7
7
|
/** The key of a contract as a list, whichever form `key` was declared in. */
|
package/dist/schema/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { decodeRecordKey, encodeRecordKey, keyFields } from '../chunk-KV2HW4G4.js';
|
|
2
2
|
export { DataReadError, isDataReadError, readFailureMessage } from '../chunk-HUNGCTRA.js';
|
|
3
|
-
export { DataWriteError, isDataWriteError } from '../chunk-
|
|
3
|
+
export { DataWriteError, isDataWriteError } from '../chunk-LG6TUBVM.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marktiderman/genesis-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"@types/react": "^19.2.14",
|
|
70
70
|
"react-hook-form": "^7.56.4",
|
|
71
71
|
"tsup": "^8.3.0",
|
|
72
|
-
"typescript": "
|
|
72
|
+
"typescript": "~6.0.3",
|
|
73
73
|
"vitest": "^4.1.12",
|
|
74
74
|
"zod": "^3.25.67"
|
|
75
75
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema/write-outcome.ts"],"names":[],"mappings":";AAuDO,IAAM,cAAA,GAAN,cAA6B,KAAA,CAAM;AAAA,EAC/B,OAAA;AAAA,EACA,OAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAEA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA;AAAA,EAET,WAAA,CAAY,OAAA,EAAuB,OAAA,EAAiB,OAAA,GAAiC,EAAC,EAAG;AACvF,IAAA,KAAA,CAAM,OAAA,EAAS,QAAQ,KAAA,KAAU,MAAA,GAAY,SAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,CAAA;AACjF,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,OAAA,CAAQ,cAAA;AAC9B,IAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,IAAA,CAAK,OAAO,OAAA,CAAQ,IAAA;AACpD,IAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,CAAO,IAAA,CAAK,QAAQ,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5D,MAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA,CAAO,EAAE,GAAG,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACnD;AAAA,EACF;AACF;AAMO,SAAS,iBAAiB,KAAA,EAAyC;AACxE,EAAA,OACE,iBAAiB,KAAA,IACjB,KAAA,CAAM,SAAS,gBAAA,IACf,OAAQ,MAAgC,OAAA,KAAY,QAAA;AAExD","file":"chunk-5NHR6ZXS.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Why a write did not save (DATA-STUDIO.md \"Write safety\")\n//\n// A write that changes nothing is never reported as \"permission denied\" by\n// assumption. The provider re-reads the row and says what actually happened.\n// ---------------------------------------------------------------------------\n\nimport type { DataRow } from \"./types\";\n\n/**\n * - `conflict`: someone else changed the row since it was read. `current`\n * carries the row as it is now.\n * - `gone`: the row was deleted, or is no longer visible to this user. The\n * two cannot be told apart without a privileged look at the table, which\n * would show this user a fact about a row they cannot see.\n * - `forbidden`: the row is visible and unchanged, but the app or the\n * database does not let this user make this change. Only reported when\n * that is proven, never assumed from \"zero rows changed\".\n * - `invalid`: the store rejected the value (type, constraint, not-null).\n * - `audit_failed`: the audit entry could not be written, so the edit was\n * rolled back with it.\n * - `unauthenticated`: no signed-in user, or the session expired.\n * - `error`: anything else. The edit did not commit.\n */\nexport type WriteOutcome =\n | \"conflict\"\n | \"gone\"\n | \"forbidden\"\n | \"invalid\"\n | \"audit_failed\"\n | \"unauthenticated\"\n | \"error\";\n\nexport interface DataWriteErrorOptions {\n /** The row as it is now, for a `conflict`. Only fields the user may read. */\n current?: DataRow;\n /** The row's current version token, for a `conflict`. */\n currentVersion?: string | null;\n /**\n * The store's own error code, when it gave one (a Postgres SQLSTATE such as\n * `23505`, or a PostgREST code such as `PGRST301`).\n */\n code?: string;\n /**\n * Per-field messages, keyed by field (column) name, for a write the store\n * rejected because of particular values. Each message is safe to show next\n * to its input: plain words, never the store's raw text or the value.\n * `useResourceForm` puts each one on its field.\n */\n fields?: Record<string, string>;\n /** The underlying error, kept for logging. */\n cause?: unknown;\n}\n\n/** Thrown by a provider when a write did not commit. */\nexport class DataWriteError extends Error {\n readonly outcome: WriteOutcome;\n readonly current?: DataRow;\n readonly currentVersion?: string | null;\n /** The store's own error code, when it gave one. */\n readonly code?: string;\n /**\n * Per-field messages (field name → safe message), when the store said which\n * values it rejected. See `DataWriteErrorOptions.fields`.\n */\n readonly fields?: Readonly<Record<string, string>>;\n\n constructor(outcome: WriteOutcome, message: string, options: DataWriteErrorOptions = {}) {\n super(message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = \"DataWriteError\";\n this.outcome = outcome;\n this.current = options.current;\n this.currentVersion = options.currentVersion;\n if (options.code !== undefined) this.code = options.code;\n if (options.fields && Object.keys(options.fields).length > 0) {\n this.fields = Object.freeze({ ...options.fields });\n }\n }\n}\n\n/**\n * `instanceof` fails when two copies of this package are installed, so check\n * the shape instead.\n */\nexport function isDataWriteError(error: unknown): error is DataWriteError {\n return (\n error instanceof Error &&\n error.name === \"DataWriteError\" &&\n typeof (error as { outcome?: unknown }).outcome === \"string\"\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider/postgrest-errors.ts","../src/provider/supabase-provider.ts"],"names":["ties","run","from"],"mappings":"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","file":"chunk-Y475Z7BM.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Postgres / PostgREST error codes → Genesis write outcomes\n// ---------------------------------------------------------------------------\n\nimport {\n DataWriteError,\n isDataWriteError,\n type WriteOutcome,\n} from \"../schema/write-outcome\";\nimport type { ReadOutcome } from \"../schema/read-outcome\";\nimport { titleCase } from \"../utils\";\n\n/**\n * Maps a store error code to the read outcome it means: the write mapping,\n * with `22***` and PostgREST request errors (`PGRST1**` other than PGRST116,\n * `42703` unknown column, `42P01` unknown table) read as `invalid`.\n */\nexport function readOutcomeFromCode(code: string | null | undefined): ReadOutcome {\n if (!code) return \"error\";\n if (code === \"42703\" || code === \"42P01\" || (/^PGRST1\\d\\d$/.test(code) && code !== \"PGRST116\")) {\n return \"invalid\";\n }\n const write = writeOutcomeFromCode(code);\n return write === \"forbidden\" || write === \"gone\" || write === \"unauthenticated\" || write === \"invalid\"\n ? write\n : \"error\";\n}\n\n/**\n * Maps a Postgres SQLSTATE or PostgREST error code to the write outcome it\n * means. Anything not listed is `error`: a code is only read as a refusal or\n * a bad value when it says so.\n *\n * - `42501` (insufficient privilege, including \"new row violates row-level\n * security policy\") → `forbidden`\n * - `22***` (data exception: bad type, out of range) and `23***` (integrity\n * constraint: `23505` unique, `23503` foreign key, `23502` not null,\n * `23514` check) → `invalid`\n * - `PGRST301`–`PGRST303` (JWT missing, expired or rejected), `28000`,\n * `28P01` → `unauthenticated`\n * - `PGRST116` (one row was asked for and none came back) → `gone`\n */\nexport function writeOutcomeFromCode(code: string | null | undefined): WriteOutcome {\n if (!code) return \"error\";\n if (code === \"42501\") return \"forbidden\";\n if (code === \"PGRST116\") return \"gone\";\n if (code === \"PGRST301\" || code === \"PGRST302\" || code === \"PGRST303\") return \"unauthenticated\";\n if (code === \"28000\" || code === \"28P01\") return \"unauthenticated\";\n if (/^2[23][0-9A-Z]{3}$/.test(code)) return \"invalid\";\n return \"error\";\n}\n\n/** A column name as Postgres reports it unquoted; anything else is not mapped. */\nconst COLUMN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/**\n * One index expression as Postgres prints it: a plain column, or one column\n * wrapped in a function, optionally cast (`lower(email::text)`,\n * `lower((email)::text)`). Anything else is not mapped.\n */\nconst WRAPPED_COLUMN = /^[A-Za-z_][A-Za-z0-9_]*\\(\\(?([A-Za-z_][A-Za-z0-9_]*)\\)?(?:::[A-Za-z_][A-Za-z0-9_ ]*)?\\)$/;\n\nfunction columnOf(expression: string): string | undefined {\n if (COLUMN.test(expression)) return expression;\n return WRAPPED_COLUMN.exec(expression)?.[1];\n}\n\n/**\n * The columns of a `Key (a, b)=(...)` detail line, or none when any is not a\n * plain column (or one column in a simple expression index). The key list is\n * read with its parentheses balanced, so an expression index such as\n * `Key (lower(email::text))=(…)` is recognised.\n */\nfunction keyColumns(details: string, tail: RegExp): string[] {\n if (!details.startsWith(\"Key (\") || !tail.test(details)) return [];\n let depth = 1;\n let end = -1;\n for (let i = \"Key (\".length; i < details.length; i++) {\n const ch = details[i];\n if (ch === \"(\") depth++;\n else if (ch === \")\" && --depth === 0) {\n end = i;\n break;\n }\n }\n if (end < 0 || details.slice(end + 1, end + 3) !== \"=(\") return [];\n const parts: string[] = [];\n let level = 0;\n let current = \"\";\n for (const ch of details.slice(\"Key (\".length, end)) {\n if (ch === \"(\") level++;\n else if (ch === \")\") level--;\n if (ch === \",\" && level === 0) {\n parts.push(current.trim());\n current = \"\";\n } else {\n current += ch;\n }\n }\n parts.push(current.trim());\n const columns = parts.map(columnOf);\n return columns.length > 0 && columns.every((c): c is string => !!c) ? columns : [];\n}\n\nfunction listLabels(columns: string[]): string {\n const labels = columns.map((c) => titleCase(c));\n if (labels.length === 1) return labels[0]!;\n return `${labels.slice(0, -1).join(\", \")} and ${labels[labels.length - 1]}`;\n}\n\n/** Field errors read from a store error, with the safe sentence that sums them up. */\nexport interface PostgrestFieldErrors {\n /** Column name → safe message for that input. */\n fields: Record<string, string>;\n /** One safe sentence for the whole error, to replace the store's raw text. */\n message: string;\n}\n\n/**\n * Reads which columns a Postgres constraint error is about, from PostgREST's\n * `message` / `details`, and gives safe messages for them. Only plain column\n * names are taken from the store's text; the values it echoes are never\n * used. A unique violation whose columns cannot be read (a complex\n * expression index, no details), or an insert/update foreign-key violation\n * whose key is an expression, gets the safe sentence with no `fields`, so the\n * store's raw text (constraint name, echoed value) never reaches the user.\n * Returns `undefined` for anything else.\n *\n * - `23505` unique violation, `Key (email)=(…) already exists.` → each\n * column: \"This value is already in use.\" (several columns: \"This\n * combination is already in use.\")\n * - `23502` not-null, `null value in column \"title\" …` → \"This field is\n * required.\"\n * - `23503` foreign key on insert/update, `Key (owner_id)=(…) is not present\n * in table …` → \"The selected item doesn't exist.\"\n */\nexport function fieldErrorsFromPostgrest(error: {\n code?: unknown;\n message?: unknown;\n details?: unknown;\n}): PostgrestFieldErrors | undefined {\n const code = typeof error.code === \"string\" ? error.code : undefined;\n const details = typeof error.details === \"string\" ? error.details.trim() : \"\";\n const message = typeof error.message === \"string\" ? error.message : \"\";\n if (code === \"23505\") {\n const columns = keyColumns(details, /\\) already exists\\.?$/);\n // Not mappable to a column: still never show the store's raw text (it\n // names the constraint and echoes the value).\n if (columns.length === 0) return { fields: {}, message: \"This value is already in use.\" };\n const each = columns.length === 1 ? \"This value is already in use.\" : \"This combination is already in use.\";\n return {\n fields: Object.fromEntries(columns.map((c) => [c, each])),\n message:\n columns.length === 1\n ? `${listLabels(columns)} is already in use.`\n : `This combination of ${listLabels(columns)} is already in use.`,\n };\n }\n if (code === \"23502\") {\n const column = /^null value in column \"([A-Za-z_][A-Za-z0-9_]*)\"(?: |$)/.exec(message)?.[1];\n if (!column || !COLUMN.test(column)) return undefined;\n return {\n fields: { [column]: \"This field is required.\" },\n message: `${titleCase(column)} is required.`,\n };\n }\n if (code === \"23503\") {\n const tail = /\\) is not present in table \"[^\"]*\"\\.?$/;\n if (!tail.test(details)) return undefined;\n const columns = keyColumns(details, tail);\n if (columns.length === 0) return { fields: {}, message: \"The selected item doesn't exist.\" };\n return {\n fields: Object.fromEntries(columns.map((c) => [c, \"The selected item doesn't exist.\"])),\n message: `${listLabels(columns)}: the selected item doesn't exist.`,\n };\n }\n return undefined;\n}\n\n/**\n * Turns anything a write threw, or the `{ message, code }` error a Supabase\n * client returned, into a `DataWriteError`. A `DataWriteError` passes through\n * unchanged; anything else keeps its message and `code`, and is kept as the\n * `cause`.\n *\n * When the error names the columns it is about (`fieldErrorsFromPostgrest`:\n * unique, not-null and foreign-key violations), the result carries `fields`\n * and its message is replaced with a safe sentence; the raw text stays on\n * the `cause`.\n */\nexport function toDataWriteError(error: unknown): DataWriteError {\n if (isDataWriteError(error)) return error;\n const shape = (typeof error === \"object\" && error !== null ? error : {}) as {\n message?: unknown;\n code?: unknown;\n details?: unknown;\n };\n const code = typeof shape.code === \"string\" ? shape.code : undefined;\n const mapped = fieldErrorsFromPostgrest(shape);\n if (mapped) {\n return new DataWriteError(writeOutcomeFromCode(code), mapped.message, {\n code,\n fields: Object.keys(mapped.fields).length > 0 ? mapped.fields : undefined,\n cause: error,\n });\n }\n const message =\n typeof shape.message === \"string\" && shape.message\n ? shape.message\n : error instanceof Error\n ? error.message\n : String(error);\n return new DataWriteError(writeOutcomeFromCode(code), message, { code, cause: error });\n}\n","import type {\n BaseRecord,\n DataProvider,\n FilterParam,\n Identifier,\n InvalidationKey,\n ListParams,\n ResourceChangeEvent,\n WriteEvent,\n} from \"./types\";\nimport { DataWriteError } from \"../schema/write-outcome\";\nimport { DataReadError, readFailureMessage } from \"../schema/read-outcome\";\nimport type { FilterOperator, ProviderCapabilities } from \"../schema/types\";\nimport { readOutcomeFromCode, toDataWriteError } from \"./postgrest-errors\";\n\n// ---------------------------------------------------------------------------\n// Minimal Supabase client shape — no hard dependency on @supabase/supabase-js\n// ---------------------------------------------------------------------------\n\n/** A chainable query builder returned by `client.from(table)`. */\ninterface SupabaseQueryBuilder {\n select(\n columns?: string,\n options?: { count?: \"exact\" | \"planned\" | \"estimated\" },\n ): SupabaseQueryBuilder;\n insert(data: Record<string, unknown> | Record<string, unknown>[]): SupabaseQueryBuilder;\n update(data: Record<string, unknown>): SupabaseQueryBuilder;\n delete(): SupabaseQueryBuilder;\n eq(column: string, value: unknown): SupabaseQueryBuilder;\n neq(column: string, value: unknown): SupabaseQueryBuilder;\n gt(column: string, value: unknown): SupabaseQueryBuilder;\n lt(column: string, value: unknown): SupabaseQueryBuilder;\n gte(column: string, value: unknown): SupabaseQueryBuilder;\n lte(column: string, value: unknown): SupabaseQueryBuilder;\n ilike(column: string, value: string): SupabaseQueryBuilder;\n in(column: string, values: unknown[]): SupabaseQueryBuilder;\n is(column: string, value: null): SupabaseQueryBuilder;\n not(column: string, operator: string, value: unknown): SupabaseQueryBuilder;\n or(filters: string): SupabaseQueryBuilder;\n order(column: string, options?: { ascending?: boolean; nullsFirst?: boolean }): SupabaseQueryBuilder;\n range(from: number, to: number): SupabaseQueryBuilder;\n single(): SupabaseQueryBuilder;\n then: Promise<{ data: unknown; error: unknown; count?: number | null }>[\"then\"];\n}\n\n/**\n * Minimal Supabase client interface — the public shape this package has\n * always exposed for a caller that wants to type its own client or a\n * wrapper around one. Unchanged: `from()` still returns `SupabaseQueryBuilder`\n * so existing consumers that annotate a variable with this type and chain\n * off it keep type-checking exactly as before.\n */\nexport interface SupabaseClient {\n from(table: string): SupabaseQueryBuilder;\n /** Supabase Realtime; needed only for `subscribe` (see `SupabaseProviderOptions.realtime`). */\n channel?(name: string): SupabaseRealtimeChannel;\n /** Releases a channel made by `channel()`. */\n removeChannel?(channel: SupabaseRealtimeChannel): unknown;\n}\n\n/**\n * One `postgres_changes` message, as Supabase Realtime sends it. Only the\n * fields the provider reads; a real payload has more.\n */\nexport interface SupabaseRealtimePayload {\n eventType: \"INSERT\" | \"UPDATE\" | \"DELETE\";\n /** The row after an insert or update (empty for a delete). */\n new?: Record<string, unknown>;\n /** For a delete or update: the old row's key (all of it with `REPLICA IDENTITY FULL`). */\n old?: Record<string, unknown>;\n}\n\n/**\n * The part of a Supabase `RealtimeChannel` the provider uses. A real\n * `@supabase/supabase-js` channel satisfies it.\n */\nexport interface SupabaseRealtimeChannel {\n on(\n type: \"postgres_changes\",\n filter: {\n event: \"*\" | \"INSERT\" | \"UPDATE\" | \"DELETE\";\n schema: string;\n table: string;\n filter?: string;\n },\n callback: (payload: SupabaseRealtimePayload) => void,\n ): SupabaseRealtimeChannel;\n subscribe(callback?: (status: string, error?: unknown) => void): SupabaseRealtimeChannel;\n unsubscribe?(): unknown;\n}\n\n/**\n * What `createSupabaseProvider` actually requires from its `client` argument\n * — deliberately looser than the public `SupabaseClient` above, and used\n * ONLY for that one parameter. A real `@supabase/supabase-js` client's\n * `from()` returns a generic, table-typed `PostgrestQueryBuilder` whose chain\n * methods don't structurally match `SupabaseQueryBuilder`, which used to\n * force callers to pass their client through `as never`. Since `unknown` is\n * a supertype of everything, any real client's `from(table: string)`\n * satisfies THIS shape without a cast; `createSupabaseProvider` narrows to\n * `SupabaseQueryBuilder` internally, once, right after each `from()` call.\n * Loosening only the input here — rather than `SupabaseClient` itself —\n * means a caller relying on `SupabaseClient`'s stricter return type for\n * their own chaining is unaffected.\n */\nexport interface SupabaseClientInput {\n from(table: string): unknown;\n /** Supabase Realtime, for `subscribe`. Any real client's `channel` fits. */\n channel?(name: string): unknown;\n removeChannel?(channel: unknown): unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Provider factory\n// ---------------------------------------------------------------------------\n\n/** What a write hook is told about the write it is part of. */\nexport interface SupabaseWriteContext {\n resource: string;\n action: \"create\" | \"update\";\n /** The row's id, for an update. */\n id?: Identifier;\n}\n\n/** Per-resource rules for `createSupabaseProvider`. Every field is optional. */\nexport interface SupabaseResourceConfig {\n /** Singular noun for failure messages, e.g. \"project\". Defaults to \"record\". */\n noun?: string;\n /** Plural for list messages, when it isn't `noun` + \"s\" (\"categories\"). */\n nounPlural?: string;\n /**\n * The columns a search covers. `[]` means the resource can't be searched,\n * and `capabilities(resource).search` reports false so a UI hides the box.\n * Set, they replace the caller's `search.fields`; omitted, those are used\n * as given.\n */\n searchFields?: readonly string[];\n /**\n * The column a sorted list orders by last, so rows with equal sort values\n * keep one order from page to page (none repeats, none is skipped).\n * Default `\"id\"`; `false` for a table or view without one. With the\n * default, a view that turns out to have no `id` column is read as before\n * (without the key order) and a development warning suggests setting this.\n */\n orderKey?: string | false;\n /**\n * `\"bin\"` for a table whose delete trigger moves the row to a recycle bin\n * instead of removing it (see `SupabaseProviderOptions.binTables`).\n * `\"hard\"` forces a plain delete even when `binTables` lists the table.\n */\n deleteMode?: \"hard\" | \"bin\";\n /**\n * Turns submitted values into the row to write: trim, drop read-only keys,\n * validate. Runs before every create and update, including the `create`\n * and `update` overrides. Throw (ideally `DataWriteError(\"invalid\", ...)`)\n * to refuse the write; nothing is sent.\n */\n prepare?: (\n values: Record<string, unknown>,\n context: SupabaseWriteContext,\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n /**\n * Creates the row some other way than an insert, e.g. a security-definer\n * RPC. Return the new row, or its id and the provider reads the row back\n * (if the read-back fails, the create is still reported as saved, with\n * just the id, so the user does not retry and make a second one). Throw to\n * fail; a Supabase `{ message, code }` error is mapped like any other.\n */\n create?: (row: Record<string, unknown>) => Promise<BaseRecord | Identifier>;\n /**\n * Updates the row some other way than an update, e.g. an RPC. Return the\n * updated row, or its id (or `true`) and the provider reads it back.\n * Returning nothing (`undefined`/`null`/`false`) means no row changed: the provider then reads the\n * row to say why (`forbidden` or `gone`), exactly as for a plain update,\n * so a function that silently skips a row never reports a save.\n */\n update?: (\n id: Identifier,\n row: Record<string, unknown>,\n ) => Promise<BaseRecord | Identifier | boolean | null | undefined | void>;\n /** Maps a stored row to edit-form values; see `DataProvider.toFormValues`. */\n toFormValues?: (record: Record<string, unknown>) => Record<string, unknown>;\n /**\n * Other cache keys a committed write to this resource makes stale, e.g.\n * `[[\"staff\"], [\"me\"]]`. Served through `DataProvider.invalidates`, which\n * `useResource` and `useResourceForm` invalidate after their writes.\n */\n invalidates?: InvalidationKey[] | ((event: WriteEvent) => InvalidationKey[]);\n /**\n * Serve `subscribe` for this resource through Supabase Realtime\n * (`postgres_changes`), so `live` lists and records refresh when the table\n * changes. The table must be in the `supabase_realtime` publication, with\n * RLS on. `false` turns it off even when `SupabaseProviderOptions.realtime`\n * covers the resource.\n */\n realtime?: boolean;\n}\n\n/** Options for `createSupabaseProvider`. All optional; none changes reads. */\nexport interface SupabaseProviderOptions {\n /**\n * Recycle-bin tables: their delete trigger turns a delete into a \"binned\"\n * mark and the binned row drops out of the caller's view (RLS or a view\n * filter). The database reports such a delete as zero rows, so for these\n * the provider checks the row is visible, deletes it, and reads it back:\n * gone from view is success, still visible is `forbidden`. A row that was\n * not visible beforehand is `gone`.\n */\n binTables?: readonly string[] | ((resource: string) => boolean);\n /** Per-resource rules, keyed by resource (table) name. */\n resources?: Record<string, SupabaseResourceConfig>;\n /**\n * Called after every committed create, update and delete, e.g. to\n * invalidate caches the Genesis hooks don't know about. Awaited, but a\n * failure is logged and never turns a committed write into a failed one.\n */\n onWrite?: (event: WriteEvent) => void | Promise<void>;\n /**\n * The most rows one list page may ask for (PostgREST's `max-rows` caps\n * reads anyway; default 1000). A larger request is refused with an\n * `invalid` `DataReadError` (its `cause` says why) rather than cut short,\n * so page boundaries never disagree with the caller's `perPage`.\n * `capabilities().maxPerPage` reports it.\n */\n maxPerPage?: number;\n /**\n * Called with every failed read, before it is thrown. The thrown\n * `DataReadError` carries a plain message for users; the store's own\n * error (its raw text and code) is its `cause`, for logging here.\n */\n onReadError?: (\n error: DataReadError,\n context: { resource: string; operation: \"getList\" | \"getOne\" | \"getMany\" },\n ) => void | Promise<void>;\n /**\n * Which resources `subscribe` serves through Supabase Realtime: `true` for\n * all, a list of names, or a test. Off by default; a resource's own\n * `resources[name].realtime` wins. Needs a client with `channel()` (any\n * `@supabase/supabase-js` client).\n */\n realtime?: boolean | readonly string[] | ((resource: string) => boolean);\n}\n\n/** A PostgREST \"undefined column\" error (42703) naming `column`. */\n/**\n * A PostgreSQL \"undefined column\" error (42703) for `table`'s own `column`:\n * `column \"id\" does not exist` or `column <table>.id does not exist`. Not a\n * related table's column (`author.id`) or any other message mentioning it.\n */\nfunction isMissingColumn(error: unknown, table: string, column: string): boolean {\n if (!error || typeof error !== \"object\") return false;\n const { code, message } = error as { code?: unknown; message?: unknown };\n if (code !== \"42703\" || typeof message !== \"string\") return false;\n const match = /^column (?:\"?([^.\"\\s]+)\"?\\.)?\"?([^.\"\\s]+)\"? does not exist$/.exec(message.trim());\n if (!match || match[2] !== column) return false;\n const ownTable = table.split(\".\").pop()?.replace(/\"/g, \"\");\n return match[1] === undefined || match[1] === ownTable;\n}\n\nconst SERVED_OPERATORS: readonly FilterOperator[] = [\n \"eq\", \"neq\", \"gt\", \"lt\", \"gte\", \"lte\", \"contains\", \"in\", \"between\", \"is_null\", \"is_not_null\",\n];\n\nfunction escapeIlike(value: string): string {\n return value.replace(/[%_\\\\]/g, (char) => `\\\\${char}`);\n}\n\nfunction isIdentifier(value: unknown): value is Identifier {\n return typeof value === \"string\" || typeof value === \"number\";\n}\n\n// ---------------------------------------------------------------------------\n// Cursor (keyset) paging\n// ---------------------------------------------------------------------------\n\n/** What a cursor holds: the sort it was made for, and the last row's values. */\ninterface CursorState {\n /** Sort field, or null when ordered by the key alone. */\n s: string | null;\n o: \"asc\" | \"desc\";\n /** The key column. */\n k: string;\n /** The last row's sort value (absent when `s` is null). */\n v?: string | number | boolean | null;\n /** The last row's key value. */\n id: string | number;\n}\n\nconst PLAIN_COLUMN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nfunction encodeCursor(state: CursorState): string {\n const bytes = new TextEncoder().encode(JSON.stringify(state));\n let binary = \"\";\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction decodeCursor(cursor: string): CursorState | undefined {\n try {\n const binary = atob(cursor.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));\n const state = JSON.parse(new TextDecoder().decode(bytes)) as CursorState;\n if (!state || typeof state !== \"object\" || typeof state.k !== \"string\" || !isIdentifier(state.id)) return undefined;\n if (state.o !== \"asc\" && state.o !== \"desc\") return undefined;\n return state;\n } catch {\n return undefined;\n }\n}\n\n/** A value quoted for a PostgREST filter, so commas, dots and parens are literal. */\nfunction quoteFilterValue(value: string | number | boolean): string {\n return `\"${String(value).replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * The PostgREST `or` clauses selecting the rows after `state`, for a list\n * ordered by `s` (`o`, nulls last when ascending and first when descending,\n * as Postgres orders them by default) and then by the key ascending.\n * @internal Exported for tests.\n */\nexport function keysetClauses(state: CursorState): string {\n const k = state.k;\n const K = quoteFilterValue(state.id);\n if (state.s === null) return `${k}.${state.o === \"asc\" ? \"gt\" : \"lt\"}.${K}`;\n const s = state.s;\n const v = state.v;\n const afterInTies = (eq: string) => `and(${eq},${k}.gt.${K})`;\n if (v === null || v === undefined) {\n // Asc: nulls are last, so only later nulls remain. Desc: nulls are\n // first, so later nulls and then every non-null row remain.\n const ties = afterInTies(`${s}.is.null`);\n return state.o === \"asc\" ? ties : `${s}.not.is.null,${ties}`;\n }\n const V = quoteFilterValue(v);\n const ties = afterInTies(`${s}.eq.${V}`);\n return state.o === \"asc\" ? `${s}.gt.${V},${ties},${s}.is.null` : `${s}.lt.${V},${ties}`;\n}\n/** `\"schema.table\"` or `\"table\"` (schema `public`), as Realtime names them. */\nfunction realtimeTable(resource: string): { schema: string; table: string } {\n const dot = resource.indexOf(\".\");\n const strip = (name: string) => name.replace(/\"/g, \"\");\n return dot < 0\n ? { schema: \"public\", table: strip(resource) }\n : { schema: strip(resource.slice(0, dot)), table: strip(resource.slice(dot + 1)) };\n}\n\nlet realtimeChannelSeq = 0;\nconst warnedRealtime = new Set<string>();\n\n/**\n * The Supabase data provider. Reads and writes go through the client you\n * pass, under that client's session and RLS.\n *\n * Writes never report a save that did not happen:\n * - `update` and `deleteOne` ask for the affected rows. Zero rows is a\n * `DataWriteError`: the row is read back, and still visible means\n * `forbidden` (RLS or a trigger refused the change), no longer visible\n * means `gone`.\n * - Database errors on writes are thrown as `DataWriteError` with the\n * outcome their code means (`writeOutcomeFromCode`) and the code kept on\n * `error.code`.\n * - Recycle-bin tables (`binTables`) succeed when the row leaves the\n * caller's view.\n *\n * Reads are unchanged: errors are thrown as an `Error` carrying `code`.\n */\nexport function createSupabaseProvider(\n client: SupabaseClientInput,\n options: SupabaseProviderOptions = {},\n): DataProvider {\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function applyFilters(\n query: SupabaseQueryBuilder,\n filters: FilterParam[] | undefined,\n ): SupabaseQueryBuilder {\n if (!filters) return query;\n for (const f of filters) {\n switch (f.operator) {\n case \"eq\":\n query = query.eq(f.field, f.value);\n break;\n case \"neq\":\n query = query.neq(f.field, f.value);\n break;\n case \"gt\":\n query = query.gt(f.field, f.value);\n break;\n case \"lt\":\n query = query.lt(f.field, f.value);\n break;\n case \"gte\":\n query = query.gte(f.field, f.value);\n break;\n case \"lte\":\n query = query.lte(f.field, f.value);\n break;\n case \"contains\":\n query = query.ilike(f.field, `%${escapeIlike(String(f.value))}%`);\n break;\n case \"in\":\n query = query.in(f.field, f.value);\n break;\n case \"is_null\":\n query = query.is(f.field, null);\n break;\n case \"is_not_null\":\n query = query.not(f.field, \"is\", null);\n break;\n case \"between\": {\n const [lo, hi] = f.value;\n query = query.gte(f.field, lo).lte(f.field, hi);\n break;\n }\n default:\n throw new Error(`[SupabaseProvider] Unknown filter operator \"${(f as FilterParam).operator}\"`);\n break;\n }\n }\n return query;\n }\n\n const maxPerPage = options.maxPerPage ?? 1000;\n // Resources found to have no \"id\" column for the default orderKey.\n const keylessResources = new Set<string>();\n\n /** Tell `onReadError` (sync or async; its failure is swallowed), then throw. */\n async function reportReadError(\n error: DataReadError,\n resource: string,\n operation: \"getList\" | \"getOne\" | \"getMany\",\n ): Promise<never> {\n try {\n await Promise.resolve(options.onReadError?.(error, { resource, operation }));\n } catch {\n // A logging hook never changes what the caller is told.\n }\n throw error;\n }\n\n /** A failed read, as a `DataReadError` with a message users can be shown. */\n async function throwIfReadError(\n result: { error: unknown },\n resource: string,\n operation: \"getList\" | \"getOne\" | \"getMany\",\n ): Promise<void> {\n if (!result.error) return;\n const raw = result.error as { message?: string; code?: string };\n const code = typeof raw.code === \"string\" ? raw.code : undefined;\n const outcome = readOutcomeFromCode(code);\n const error = new DataReadError(\n outcome,\n readFailureMessage(outcome, nounFor(resource), operation === \"getOne\", configFor(resource).nounPlural),\n { code, cause: result.error },\n );\n await reportReadError(error, resource, operation);\n }\n\n // ---------------------------------------------------------------------------\n // Write helpers\n // ---------------------------------------------------------------------------\n\n const from = (resource: string) => client.from(resource) as SupabaseQueryBuilder;\n const configFor = (resource: string): SupabaseResourceConfig =>\n options.resources?.[resource] ?? {};\n const nounFor = (resource: string) => configFor(resource).noun ?? \"record\";\n\n function realtimeEnabled(resource: string): boolean {\n if (typeof client.channel !== \"function\") return false;\n const own = configFor(resource).realtime;\n if (own !== undefined) return own;\n const all = options.realtime;\n if (!all) return false;\n if (all === true) return true;\n return typeof all === \"function\" ? all(resource) : all.includes(resource);\n }\n\n function isBinTable(resource: string): boolean {\n const mode = configFor(resource).deleteMode;\n if (mode) return mode === \"bin\";\n const bin = options.binTables;\n if (!bin) return false;\n return typeof bin === \"function\" ? bin(resource) : bin.includes(resource);\n }\n\n /** Awaits a write-path query: its rows, or a `DataWriteError`. */\n async function run(query: SupabaseQueryBuilder): Promise<unknown[]> {\n let result: { data: unknown; error: unknown };\n try {\n result = (await query) as { data: unknown; error: unknown };\n } catch (error) {\n throw toDataWriteError(error);\n }\n if (result.error) throw toDataWriteError(result.error);\n if (Array.isArray(result.data)) return result.data;\n return result.data == null ? [] : [result.data];\n }\n\n async function isVisible(resource: string, id: Identifier): Promise<boolean> {\n return (await run(from(resource).select(\"id\").eq(\"id\", id))).length > 0;\n }\n\n async function readBack(resource: string, id: Identifier): Promise<BaseRecord | undefined> {\n return (await run(from(resource).select(\"*\").eq(\"id\", id)))[0] as BaseRecord | undefined;\n }\n\n function goneError(resource: string): DataWriteError {\n return new DataWriteError(\n \"gone\",\n `This ${nounFor(resource)} no longer exists, or you can no longer see it.`,\n );\n }\n\n /**\n * A write matched no rows: read the row back to say why. Still visible\n * means the change was refused; not visible means it is gone (deleted, or\n * hidden from this user — the two can't be told apart under RLS).\n */\n async function noRowsError(\n resource: string,\n id: Identifier,\n verb: \"change\" | \"delete\",\n ): Promise<DataWriteError> {\n let visible: boolean;\n try {\n visible = await isVisible(resource, id);\n } catch (error) {\n const cause = toDataWriteError(error);\n return new DataWriteError(\n cause.outcome === \"unauthenticated\" ? \"unauthenticated\" : \"error\",\n `This ${nounFor(resource)} was not ${verb === \"change\" ? \"changed\" : \"deleted\"}, and reading it back failed (${cause.message}).`,\n { code: cause.code, cause: error },\n );\n }\n if (visible) {\n return new DataWriteError(\"forbidden\", `You can't ${verb} this ${nounFor(resource)}.`);\n }\n return goneError(resource);\n }\n\n async function prepare(\n resource: string,\n values: Record<string, unknown>,\n context: SupabaseWriteContext,\n ): Promise<Record<string, unknown>> {\n const rule = configFor(resource).prepare;\n if (!rule) return values;\n try {\n return await rule({ ...values }, context);\n } catch (error) {\n throw toDataWriteError(error);\n }\n }\n\n /** After a committed write. Never turns it into a failure. */\n async function committed(event: WriteEvent): Promise<void> {\n if (!options.onWrite) return;\n try {\n await options.onWrite(event);\n } catch (error) {\n console.error(`[SupabaseProvider] onWrite failed for \"${event.resource}\":`, error);\n }\n }\n\n // ---------------------------------------------------------------------------\n // DataProvider implementation\n // ---------------------------------------------------------------------------\n\n /** The search as PostgREST `or` clauses, or \"\" for none. */\n function searchClauses(resource: string, params: ListParams): string {\n const searchFields = configFor(resource).searchFields ?? params.search?.fields ?? [];\n if (!params.search || !params.search.query || searchFields.length === 0) return \"\";\n const escaped = escapeIlike(params.search.query);\n const safeFieldPattern = /^[a-zA-Z_][a-zA-Z0-9_.]*$/;\n return searchFields\n .filter((f) => safeFieldPattern.test(f))\n // Quoted, so commas, dots and parens in the query stay literal (also\n // when nested inside the keyset's `and(or(…))`).\n .map((f) => `${f}.ilike.${quoteFilterValue(`%${escaped}%`)}`)\n .join(\",\");\n }\n\n /** A cursor request this provider can't serve: `invalid`, with why as the cause. */\n function refuseCursor(resource: string, why: string): Promise<never> {\n return reportReadError(\n new DataReadError(\n \"invalid\",\n readFailureMessage(\"invalid\", nounFor(resource), false, configFor(resource).nounPlural),\n { cause: new Error(`[SupabaseProvider] \"${resource}\": ${why}`) },\n ),\n resource,\n \"getList\",\n );\n }\n\n /**\n * One page by keyset: ordered by the sort column and then the key, the\n * rows after the cursor's row, plus one more to tell whether a next page\n * exists. Counted only on the first page.\n */\n async function getCursorPage(\n resource: string,\n params: ListParams,\n key: string | false,\n ): Promise<{ data: unknown[]; total: number; nextCursor: string | null }> {\n const { cursor } = params.pagination!;\n // The look-ahead row must fit under PostgREST's max-rows (maxPerPage), or\n // it is dropped and the list would end after one page. A keyset page can\n // be shorter than asked without skipping or repeating rows.\n const perPage = Math.max(1, Math.min(params.pagination!.perPage, maxPerPage - 1));\n if (!key) {\n return refuseCursor(resource, \"cursor paging needs a unique key column to order by; its orderKey is false. Set orderKey to a unique, non-null column, or page by offset.\");\n }\n if (!PLAIN_COLUMN.test(key)) return refuseCursor(resource, `the key column \"${key}\" can't be used in a cursor.`);\n const sort = params.sort && params.sort.field !== key ? params.sort : undefined;\n if (sort && !PLAIN_COLUMN.test(sort.field)) {\n return refuseCursor(resource, `cursor paging can sort only by a plain column, not \"${sort.field}\".`);\n }\n const order: \"asc\" | \"desc\" = params.sort?.order ?? \"asc\";\n const sortField = sort ? sort.field : null;\n\n let after: CursorState | undefined;\n if (cursor) {\n after = decodeCursor(cursor);\n if (!after) return refuseCursor(resource, \"the cursor is not one this provider made.\");\n if (after.s !== sortField || after.o !== order || after.k !== key) {\n return refuseCursor(resource, \"the cursor was made for a different sort; start again from the first page (cursor: null).\");\n }\n }\n\n let query = from(resource).select(\n params.select ?? \"*\",\n ...(cursor ? [] : [{ count: \"exact\" as const }]),\n );\n query = applyFilters(query, params.filters);\n const search = searchClauses(resource, params);\n const keyset = after ? keysetClauses(after) : \"\";\n // Both are OR groups that must hold together: nest them in one `or`.\n if (search && keyset) query = query.or(`and(or(${search}),or(${keyset}))`);\n else if (search || keyset) query = query.or(search || keyset);\n\n if (sortField) {\n // Pinned to Postgres's default null placement, which the keyset assumes.\n query = query.order(sortField, { ascending: order === \"asc\", nullsFirst: order === \"desc\" });\n query = query.order(key, { ascending: true });\n } else {\n query = query.order(key, { ascending: order === \"asc\" });\n }\n query = query.range(0, perPage);\n\n const result = (await query) as unknown as { data: unknown[] | null; error: unknown; count?: number | null };\n await throwIfReadError(result, resource, \"getList\");\n const rows = (result.data ?? []) as Record<string, unknown>[];\n const page = rows.slice(0, perPage);\n let nextCursor: string | null = null;\n if (rows.length > perPage) {\n const last = page[page.length - 1]!;\n const id = last[key];\n const v = sortField ? last[sortField] : undefined;\n if (!isIdentifier(id) || (sortField && !(sortField in last))) {\n return refuseCursor(resource, `the selected columns must include \"${key}\"${sortField ? ` and \"${sortField}\"` : \"\"} to page by cursor.`);\n }\n if (v !== undefined && v !== null && typeof v === \"object\") {\n return refuseCursor(resource, `cursor paging can't sort by \"${sortField}\": its values aren't plain (text, number, date, boolean).`);\n }\n nextCursor = encodeCursor({\n s: sortField,\n o: order,\n k: key,\n ...(sortField ? { v: (v ?? null) as CursorState[\"v\"] } : {}),\n id,\n });\n }\n return { data: page, total: cursor ? -1 : (result.count ?? 0), nextCursor };\n }\n\n const provider: DataProvider = {\n async getList(resource, params) {\n // Refused, not cut short: a shorter page than the caller asked for\n // would shift every later page's boundary and skip or repeat rows.\n if (params.pagination && params.pagination.perPage > maxPerPage) {\n const { perPage } = params.pagination;\n await reportReadError(\n new DataReadError(\n \"invalid\",\n readFailureMessage(\"invalid\", nounFor(resource), false, configFor(resource).nounPlural),\n {\n cause: new Error(\n `[SupabaseProvider] \"${resource}\" asked for ${perPage} rows per page; the most is ${maxPerPage} (maxPerPage). Ask for at most ${maxPerPage} and page through the rest.`,\n ),\n },\n ),\n resource,\n \"getList\",\n );\n }\n\n const configuredKey = configFor(resource).orderKey;\n if (params.pagination && params.pagination.cursor !== undefined) {\n return getCursorPage(resource, params, configuredKey === undefined ? \"id\" : configuredKey) as never;\n }\n const run = (key: string | false) => {\n let query = (client.from(resource) as SupabaseQueryBuilder).select(\n params.select ?? \"*\",\n { count: \"exact\" },\n );\n\n query = applyFilters(query, params.filters);\n\n // Search — convert to OR of ilike. A resource's configured\n // `searchFields` win over the caller's.\n const clauses = searchClauses(resource, params);\n if (clauses) {\n query = query.or(clauses);\n }\n\n // Sort, then the key column, so equal sort values keep one order\n // across pages (otherwise a row can repeat on page 2 or be skipped).\n // An unsorted page is ordered by the key alone: without an ORDER BY\n // the database may return pages in any order.\n if (params.sort) {\n query = query.order(params.sort.field, {\n ascending: params.sort.order === \"asc\",\n });\n if (key && key !== params.sort.field) query = query.order(key, { ascending: true });\n } else if (params.pagination && key) {\n query = query.order(key, { ascending: true });\n }\n\n if (params.pagination) {\n const { page, perPage } = params.pagination;\n const from = (page - 1) * perPage;\n const to = from + perPage - 1;\n query = query.range(from, to);\n }\n\n return query as unknown as Promise<{\n data: unknown[];\n error: unknown;\n count?: number | null;\n }>;\n };\n\n // The default key (\"id\") is a guess: a view without that column reads\n // as before, without the key order, and is not ordered by it again.\n const guessKey = configuredKey === undefined && !keylessResources.has(resource);\n let result = await run(configuredKey ?? (keylessResources.has(resource) ? false : \"id\"));\n if (guessKey && isMissingColumn(result.error, resource, \"id\")) {\n keylessResources.add(resource);\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[SupabaseProvider] \"${resource}\" has no \"id\" column, so its pages have no stable order. Set resources.${resource}.orderKey to a unique column (or false to silence this).`,\n );\n }\n result = await run(false);\n }\n await throwIfReadError(result, resource, \"getList\");\n\n return { data: result.data ?? [], total: result.count ?? 0 } as never;\n },\n\n async getOne(resource, params) {\n const result = (await (client.from(resource) as SupabaseQueryBuilder)\n .select(params.select ?? \"*\")\n .eq(\"id\", params.id)\n .single()) as { data: unknown; error: unknown };\n await throwIfReadError(result, resource, \"getOne\");\n return { data: result.data } as never;\n },\n\n async getMany(resource, params) {\n if (params.ids.length === 0) return { data: [] } as never;\n const result = (await (client.from(resource) as SupabaseQueryBuilder)\n .select(\"*\")\n .in(\"id\", params.ids)) as { data: unknown[]; error: unknown };\n await throwIfReadError(result, resource, \"getMany\");\n return { data: result.data ?? [] } as never;\n },\n\n async capabilities(resource?: string): Promise<ProviderCapabilities> {\n return {\n search: resource ? configFor(resource).searchFields?.length !== 0 : true,\n sort: true,\n filterOperators: SERVED_OPERATORS,\n bulkWrites: false,\n versionedWrites: false,\n compositeKeys: false,\n multiSort: false,\n create: true,\n delete: true,\n maxPerPage,\n softDelete: resource ? isBinTable(resource) : false,\n cursorPagination: resource ? configFor(resource).orderKey !== false : true,\n realtime: resource\n ? realtimeEnabled(resource)\n : typeof client.channel === \"function\" &&\n (!!options.realtime ||\n Object.values(options.resources ?? {}).some((r) => r.realtime === true)),\n };\n },\n\n subscribe(resource, params, callback) {\n if (!realtimeEnabled(resource)) {\n if (process.env.NODE_ENV !== \"production\" && !warnedRealtime.has(resource)) {\n warnedRealtime.add(resource);\n console.warn(\n typeof client.channel !== \"function\"\n ? `[SupabaseProvider] \"${resource}\" was subscribed to, but the client has no channel() (Supabase Realtime), so nothing will be reported.`\n : `[SupabaseProvider] \"${resource}\" was subscribed to, but realtime is off for it. Set resources.${resource}.realtime (or the realtime option) to true.`,\n );\n }\n return () => {};\n }\n const { schema, table } = realtimeTable(resource);\n // No server-side `id=eq.` filter for one record: Realtime never\n // delivers DELETE events through a filter, so the id is matched below.\n // A unique topic: supabase-js hands back an existing channel for a\n // topic already open, and removing it would end the other subscriber.\n const channel = client.channel!(\n `genesis:${resource}:${++realtimeChannelSeq}`,\n ) as SupabaseRealtimeChannel;\n let closed = false;\n let subscribedOnce = false;\n let interrupted = false;\n const emit = (event: ResourceChangeEvent) => {\n if (closed) return;\n try {\n callback(event);\n } catch (error) {\n console.error(`[SupabaseProvider] a realtime callback for \"${resource}\" threw:`, error);\n }\n };\n channel\n .on(\n \"postgres_changes\",\n { event: \"*\", schema, table },\n (payload) => {\n // Only the id: the payload is a hint, never data to show. Realtime\n // applies RLS to inserts and updates, but a delete's old key is\n // sent to every subscriber, so nothing else is passed on.\n const row = payload.eventType === \"DELETE\" ? payload.old : payload.new;\n const id = row?.[\"id\"];\n if (params.id != null && isIdentifier(id) && String(id) !== String(params.id)) return;\n const type =\n payload.eventType === \"INSERT\" ? \"created\" : payload.eventType === \"UPDATE\" ? \"updated\" : \"deleted\";\n emit(isIdentifier(id) ? { type, id } : { type });\n },\n )\n .subscribe((status) => {\n if (status === \"SUBSCRIBED\") {\n // Back after a drop: changes made meanwhile were not sent.\n if (subscribedOnce && interrupted) emit({ type: \"changed\" });\n subscribedOnce = true;\n interrupted = false;\n } else if (status === \"CHANNEL_ERROR\" || status === \"TIMED_OUT\" || status === \"CLOSED\") {\n interrupted = true;\n }\n });\n return () => {\n if (closed) return;\n closed = true;\n try {\n const done =\n typeof client.removeChannel === \"function\"\n ? client.removeChannel(channel)\n : channel.unsubscribe?.();\n // A failed removal (socket already gone) is nothing to report.\n if (done && typeof (done as Promise<unknown>).catch === \"function\") {\n (done as Promise<unknown>).catch(() => {});\n }\n } catch {\n // As above.\n }\n };\n },\n\n async create(resource, params) {\n const row = await prepare(resource, params.data as Record<string, unknown>, {\n resource,\n action: \"create\",\n });\n const override = configFor(resource).create;\n let record: BaseRecord;\n if (override) {\n let returned: BaseRecord | Identifier;\n try {\n returned = await override(row);\n } catch (error) {\n throw toDataWriteError(error);\n }\n if (isIdentifier(returned)) {\n // The row exists from here on. A failed read-back must not report\n // the create as failed: the user would retry and make a second one.\n record = (await readBack(resource, returned).catch(() => undefined)) ?? { id: returned };\n } else if (returned && typeof returned === \"object\" && isIdentifier(returned.id)) {\n record = returned;\n } else {\n throw new DataWriteError(\n \"error\",\n `[SupabaseProvider] The create rule for \"${resource}\" returned neither the new row nor its id.`,\n );\n }\n } else {\n const rows = await run(from(resource).insert(row).select(\"*\").single());\n record = rows[0] as BaseRecord;\n }\n await committed({ resource, kind: \"create\", id: record.id, record });\n return { data: record } as never;\n },\n\n async update(resource, params) {\n const { id } = params;\n const row = await prepare(resource, params.data as Record<string, unknown>, {\n resource,\n action: \"update\",\n id,\n });\n const override = configFor(resource).update;\n let record: BaseRecord;\n if (override) {\n let returned: BaseRecord | Identifier | boolean | null | undefined | void;\n try {\n returned = await override(id, row);\n } catch (error) {\n throw toDataWriteError(error);\n }\n const result: unknown = returned;\n if (result == null || result === false) throw await noRowsError(resource, id, \"change\");\n if (isIdentifier(result) || result === true) {\n // The change committed; a failed read-back still reports it saved.\n const readId = result === true ? id : result;\n record = (await readBack(resource, readId).catch(() => undefined)) ?? { ...row, id: readId };\n } else if (typeof result === \"object\") {\n record = { id, ...(result as Record<string, unknown>) } as BaseRecord;\n } else {\n throw new DataWriteError(\n \"error\",\n `[SupabaseProvider] The update rule for \"${resource}\" returned neither the row, its id, nor nothing.`,\n );\n }\n } else {\n const rows = await run(from(resource).update(row).eq(\"id\", id).select(\"*\"));\n if (rows.length === 0) throw await noRowsError(resource, id, \"change\");\n record = rows[0] as BaseRecord;\n }\n await committed({ resource, kind: \"update\", id, record });\n return { data: record } as never;\n },\n\n async deleteOne(resource, params) {\n const { id } = params;\n let deletedId: Identifier = id;\n if (isBinTable(resource)) {\n // A binned delete reports zero rows whether or not it worked, so the\n // answer comes from visibility before and after.\n if (!(await isVisible(resource, id))) throw goneError(resource);\n await run(from(resource).delete().eq(\"id\", id));\n let stillVisible: boolean;\n try {\n stillVisible = await isVisible(resource, id);\n } catch (error) {\n const cause = toDataWriteError(error);\n throw new DataWriteError(\n \"error\",\n `The ${nounFor(resource)} may not have been deleted: checking it failed (${cause.message}).`,\n { code: cause.code, cause: error },\n );\n }\n if (stillVisible) {\n throw new DataWriteError(\"forbidden\", `You can't delete this ${nounFor(resource)}.`);\n }\n } else {\n const rows = await run(from(resource).delete().eq(\"id\", id).select(\"id\"));\n if (rows.length === 0) throw await noRowsError(resource, id, \"delete\");\n const returnedId = (rows[0] as { id?: unknown }).id;\n if (isIdentifier(returnedId)) deletedId = returnedId;\n }\n await committed({ resource, kind: \"delete\", id: deletedId });\n return { data: { id: deletedId } };\n },\n\n toFormValues(resource, record) {\n const map = configFor(resource).toFormValues;\n return map ? map(record) : record;\n },\n\n invalidates(event) {\n const keys = configFor(event.resource).invalidates;\n if (!keys) return [];\n return typeof keys === \"function\" ? keys(event) : keys;\n },\n };\n\n return provider;\n}\n"]}
|