@pyreon/feature 0.7.0 → 0.9.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.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"bed719e7-1","name":"schema.ts"},{"uid":"bed719e7-3","name":"define-feature.ts"},{"uid":"bed719e7-5","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"bed719e7-1":{"renderedLength":5145,"gzipLength":1847,"brotliLength":0,"metaUid":"bed719e7-0"},"bed719e7-3":{"renderedLength":7576,"gzipLength":2435,"brotliLength":0,"metaUid":"bed719e7-2"},"bed719e7-5":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"bed719e7-4"}},"nodeMetas":{"bed719e7-0":{"id":"/src/schema.ts","moduleParts":{"index.js":"bed719e7-1"},"imported":[],"importedBy":[{"uid":"bed719e7-4"},{"uid":"bed719e7-2"}]},"bed719e7-2":{"id":"/src/define-feature.ts","moduleParts":{"index.js":"bed719e7-3"},"imported":[{"uid":"bed719e7-6"},{"uid":"bed719e7-7"},{"uid":"bed719e7-8"},{"uid":"bed719e7-9"},{"uid":"bed719e7-10"},{"uid":"bed719e7-11"},{"uid":"bed719e7-0"}],"importedBy":[{"uid":"bed719e7-4"}]},"bed719e7-4":{"id":"/src/index.ts","moduleParts":{"index.js":"bed719e7-5"},"imported":[{"uid":"bed719e7-2"},{"uid":"bed719e7-0"}],"importedBy":[],"isEntry":true},"bed719e7-6":{"id":"@pyreon/form","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]},"bed719e7-7":{"id":"@pyreon/query","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]},"bed719e7-8":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]},"bed719e7-9":{"id":"@pyreon/store","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]},"bed719e7-10":{"id":"@pyreon/table","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]},"bed719e7-11":{"id":"@pyreon/validation","moduleParts":{},"imported":[],"importedBy":[{"uid":"bed719e7-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"0259433e-1","name":"schema.ts"},{"uid":"0259433e-3","name":"define-feature.ts"},{"uid":"0259433e-5","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"0259433e-1":{"renderedLength":5178,"gzipLength":1861,"brotliLength":0,"metaUid":"0259433e-0"},"0259433e-3":{"renderedLength":7725,"gzipLength":2458,"brotliLength":0,"metaUid":"0259433e-2"},"0259433e-5":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"0259433e-4"}},"nodeMetas":{"0259433e-0":{"id":"/src/schema.ts","moduleParts":{"index.js":"0259433e-1"},"imported":[],"importedBy":[{"uid":"0259433e-4"},{"uid":"0259433e-2"}]},"0259433e-2":{"id":"/src/define-feature.ts","moduleParts":{"index.js":"0259433e-3"},"imported":[{"uid":"0259433e-6"},{"uid":"0259433e-7"},{"uid":"0259433e-8"},{"uid":"0259433e-9"},{"uid":"0259433e-10"},{"uid":"0259433e-11"},{"uid":"0259433e-0"}],"importedBy":[{"uid":"0259433e-4"}]},"0259433e-4":{"id":"/src/index.ts","moduleParts":{"index.js":"0259433e-5"},"imported":[{"uid":"0259433e-2"},{"uid":"0259433e-0"}],"importedBy":[],"isEntry":true},"0259433e-6":{"id":"@pyreon/form","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]},"0259433e-7":{"id":"@pyreon/query","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]},"0259433e-8":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]},"0259433e-9":{"id":"@pyreon/store","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]},"0259433e-10":{"id":"@pyreon/table","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]},"0259433e-11":{"id":"@pyreon/validation","moduleParts":{},"imported":[],"importedBy":[{"uid":"0259433e-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -118,7 +118,7 @@ function detectFieldType(zodField) {
118
118
  return {
119
119
  type,
120
120
  optional,
121
- enumValues
121
+ ...enumValues != null ? { enumValues } : {}
122
122
  };
123
123
  }
124
124
  /**
@@ -319,8 +319,8 @@ function defineFeature(config) {
319
319
  params
320
320
  ],
321
321
  queryFn: () => http.list(api, Object.keys(params).length > 0 ? params : void 0),
322
- staleTime: options?.staleTime,
323
- enabled: options?.enabled
322
+ ...options?.staleTime != null ? { staleTime: options.staleTime } : {},
323
+ ...options?.enabled != null ? { enabled: options.enabled } : {}
324
324
  };
325
325
  });
326
326
  },
@@ -343,7 +343,7 @@ function defineFeature(config) {
343
343
  q: searchTerm()
344
344
  }),
345
345
  enabled: searchTerm().length > 0,
346
- staleTime: options?.staleTime
346
+ ...options?.staleTime != null ? { staleTime: options.staleTime } : {}
347
347
  }));
348
348
  },
349
349
  useCreate() {
@@ -396,7 +396,7 @@ function defineFeature(config) {
396
396
  ...initialValues,
397
397
  ...options?.initialValues ?? {}
398
398
  },
399
- schema: validate,
399
+ ...validate != null ? { schema: validate } : {},
400
400
  validateOn: options?.validateOn ?? "blur",
401
401
  onSubmit: async (values) => {
402
402
  try {
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_useQuery","_useMutation","_useForm","_useTable"],"sources":["../src/schema.ts","../src/define-feature.ts"],"sourcesContent":["/**\n * Schema introspection utilities.\n *\n * Extracts field names, types, and metadata from Zod schemas at runtime\n * without importing Zod types directly (duck-typed).\n */\n\nexport interface FieldInfo {\n /** Field name (key in the schema object). */\n name: string\n /** Inferred type: 'string' | 'number' | 'boolean' | 'date' | 'enum' | 'array' | 'object' | 'reference' | 'unknown'. */\n type: FieldType\n /** Whether the field is optional. */\n optional: boolean\n /** For enum fields, the list of allowed values. */\n enumValues?: (string | number)[]\n /** For reference fields, the name of the referenced feature. */\n referenceTo?: string\n /** Human-readable label derived from field name. */\n label: string\n}\n\nexport type FieldType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'enum'\n | 'array'\n | 'object'\n | 'reference'\n | 'unknown'\n\n/** Symbol used to tag reference schema objects. */\nconst REFERENCE_TAG = Symbol.for('pyreon:feature:reference')\n\n/**\n * Metadata carried by a reference schema.\n */\nexport interface ReferenceSchema {\n /** Marker symbol for detection. */\n [key: symbol]: true\n /** Name of the referenced feature. */\n _featureName: string\n /** Duck-typed Zod-like interface: validates as string | number. */\n safeParse: (value: unknown) => {\n success: boolean\n error?: { issues: { message: string }[] }\n }\n /** Async variant for compatibility. */\n safeParseAsync: (\n value: unknown,\n ) => Promise<{ success: boolean; error?: { issues: { message: string }[] } }>\n /** Shape-like marker for schema introspection. */\n _def: { typeName: string }\n}\n\n/**\n * Check if a value is a reference schema created by `reference()`.\n */\nexport function isReference(value: unknown): value is ReferenceSchema {\n return (\n value !== null &&\n typeof value === 'object' &&\n (value as Record<symbol, unknown>)[REFERENCE_TAG] === true\n )\n}\n\n/**\n * Create a reference field that links to another feature.\n *\n * Returns a Zod-compatible schema that validates as `string | number` and\n * carries metadata about the referenced feature for form dropdowns and table links.\n *\n * @example\n * ```ts\n * import { defineFeature, reference } from '@pyreon/feature'\n *\n * const posts = defineFeature({\n * name: 'posts',\n * schema: z.object({\n * title: z.string(),\n * authorId: reference(users),\n * }),\n * api: '/api/posts',\n * })\n * ```\n */\nexport function reference(feature: { name: string }): ReferenceSchema {\n const featureName = feature.name\n\n function validateRef(value: unknown): {\n success: boolean\n error?: { issues: { message: string }[] }\n } {\n if (typeof value === 'string' || typeof value === 'number') {\n return { success: true }\n }\n return {\n success: false,\n error: {\n issues: [\n {\n message: `Expected string or number reference to ${featureName}, got ${typeof value}`,\n },\n ],\n },\n }\n }\n\n return {\n [REFERENCE_TAG]: true,\n _featureName: featureName,\n safeParse: validateRef,\n safeParseAsync: async (value: unknown) => validateRef(value),\n _def: { typeName: 'ZodString' },\n }\n}\n\n/**\n * Convert a field name to a human-readable label.\n * e.g., 'firstName' → 'First Name', 'created_at' → 'Created At'\n */\nfunction nameToLabel(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase → camel Case\n .replace(/[_-]/g, ' ') // snake_case/kebab-case → spaces\n .replace(/\\b\\w/g, (c) => c.toUpperCase()) // capitalize words\n}\n\n/**\n * Detect the field type from a Zod schema shape entry.\n * Duck-typed — works with Zod v3 and v4 without importing Zod.\n */\nfunction detectFieldType(zodField: unknown): {\n type: FieldType\n optional: boolean\n enumValues?: (string | number)[]\n referenceTo?: string\n} {\n // Check for reference fields first\n if (isReference(zodField)) {\n return {\n type: 'reference',\n optional: false,\n referenceTo: zodField._featureName,\n }\n }\n\n if (!zodField || typeof zodField !== 'object') {\n return { type: 'unknown', optional: false }\n }\n\n const field = zodField as Record<string, unknown>\n\n // Check for optional wrapper (ZodOptional or ZodNullable)\n let inner = field\n let optional = false\n\n // Zod v3: _def.typeName, Zod v4: _zod.def.type\n const getTypeName = (obj: Record<string, unknown>): string | undefined => {\n // v3 path\n const def = obj._def as Record<string, unknown> | undefined\n if (def?.typeName && typeof def.typeName === 'string') {\n return def.typeName\n }\n // v4 path\n const zod = obj._zod as Record<string, unknown> | undefined\n const zodDef = zod?.def as Record<string, unknown> | undefined\n if (zodDef?.type && typeof zodDef.type === 'string') {\n return zodDef.type\n }\n return undefined\n }\n\n const typeName = getTypeName(inner)\n\n // Unwrap optional/nullable\n if (\n typeName === 'ZodOptional' ||\n typeName === 'ZodNullable' ||\n typeName === 'optional' ||\n typeName === 'nullable'\n ) {\n optional = true\n const def = inner._def as Record<string, unknown> | undefined\n const innerType =\n def?.innerType ?? (inner._zod as Record<string, unknown>)?.def\n if (innerType && typeof innerType === 'object') {\n inner = innerType as Record<string, unknown>\n }\n }\n\n const innerTypeName = getTypeName(inner) ?? typeName\n\n // Map Zod type names to our FieldType\n if (!innerTypeName) return { type: 'unknown', optional }\n\n const typeMap: Record<string, FieldType> = {\n ZodString: 'string',\n ZodNumber: 'number',\n ZodBoolean: 'boolean',\n ZodDate: 'date',\n ZodEnum: 'enum',\n ZodNativeEnum: 'enum',\n ZodArray: 'array',\n ZodObject: 'object',\n // v4 names\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n date: 'date',\n enum: 'enum',\n array: 'array',\n object: 'object',\n }\n\n const type = typeMap[innerTypeName] ?? 'string'\n\n // Extract enum values\n let enumValues: (string | number)[] | undefined\n if (type === 'enum') {\n const def = inner._def as Record<string, unknown> | undefined\n if (def?.values && Array.isArray(def.values)) {\n enumValues = def.values as (string | number)[]\n }\n // v4 path\n const zodDef = (inner._zod as Record<string, unknown>)?.def as\n | Record<string, unknown>\n | undefined\n if (zodDef?.values && Array.isArray(zodDef.values)) {\n enumValues = zodDef.values as (string | number)[]\n }\n }\n\n return { type, optional, enumValues }\n}\n\n/**\n * Extract field information from a Zod object schema.\n * Returns an array of FieldInfo objects describing each field.\n *\n * @example\n * ```ts\n * const schema = z.object({ name: z.string(), age: z.number().optional() })\n * const fields = extractFields(schema)\n * // [\n * // { name: 'name', type: 'string', optional: false, label: 'Name' },\n * // { name: 'age', type: 'number', optional: true, label: 'Age' },\n * // ]\n * ```\n */\nexport function extractFields(schema: unknown): FieldInfo[] {\n if (!schema || typeof schema !== 'object') return []\n\n const s = schema as Record<string, unknown>\n\n // Get the shape object from the schema\n // Zod v3: schema._def.shape() or schema.shape\n // Zod v4: schema._zod.def.shape or schema.shape\n let shape: Record<string, unknown> | undefined\n\n // Try schema.shape (works for both v3 and v4)\n if (s.shape && typeof s.shape === 'object') {\n shape = s.shape as Record<string, unknown>\n }\n\n // Try _def.shape (v3 — can be a function)\n if (!shape) {\n const def = s._def as Record<string, unknown> | undefined\n if (def?.shape) {\n shape =\n typeof def.shape === 'function'\n ? (def.shape as () => Record<string, unknown>)()\n : (def.shape as Record<string, unknown>)\n }\n }\n\n // Try _zod.def.shape (v4)\n if (!shape) {\n const zod = s._zod as Record<string, unknown> | undefined\n const zodDef = zod?.def as Record<string, unknown> | undefined\n if (zodDef?.shape && typeof zodDef.shape === 'object') {\n shape = zodDef.shape as Record<string, unknown>\n }\n }\n\n if (!shape) return []\n\n return Object.entries(shape).map(([name, fieldSchema]) => {\n const { type, optional, enumValues, referenceTo } =\n detectFieldType(fieldSchema)\n const info: FieldInfo = {\n name,\n type,\n optional,\n label: nameToLabel(name),\n }\n if (enumValues) info.enumValues = enumValues\n if (referenceTo) info.referenceTo = referenceTo\n return info\n })\n}\n\n/**\n * Generate default initial values from a schema's field types.\n */\nexport function defaultInitialValues(\n fields: FieldInfo[],\n): Record<string, unknown> {\n const values: Record<string, unknown> = {}\n for (const field of fields) {\n switch (field.type) {\n case 'string':\n values[field.name] = ''\n break\n case 'number':\n values[field.name] = 0\n break\n case 'boolean':\n values[field.name] = false\n break\n case 'enum':\n values[field.name] = field.enumValues?.[0] ?? ''\n break\n case 'date':\n values[field.name] = ''\n break\n default:\n values[field.name] = ''\n }\n }\n return values\n}\n","import type { SchemaValidateFn } from '@pyreon/form'\nimport { useForm as _useForm } from '@pyreon/form'\nimport type { QueryKey } from '@pyreon/query'\nimport {\n useMutation as _useMutation,\n useQuery as _useQuery,\n useQueryClient,\n} from '@pyreon/query'\nimport { batch, signal } from '@pyreon/reactivity'\nimport { defineStore } from '@pyreon/store'\nimport type { ColumnDef, SortingState } from '@pyreon/table'\nimport {\n useTable as _useTable,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n} from '@pyreon/table'\nimport { zodSchema } from '@pyreon/validation'\nimport { defaultInitialValues, extractFields } from './schema'\nimport type {\n Feature,\n FeatureConfig,\n FeatureFormOptions,\n FeatureStore,\n FeatureTableOptions,\n ListOptions,\n} from './types'\n\n// ─── Fetch wrapper ────────────────────────────────────────────────────────────\n\nfunction createFetcher(baseFetcher: typeof fetch = fetch) {\n async function request<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await baseFetcher(url, init)\n\n if (!res.ok) {\n let message = `${init?.method ?? 'GET'} ${url} failed: ${res.status}`\n try {\n const body = await res.json()\n if (body?.message) message = body.message\n if (body?.errors) {\n throw Object.assign(new Error(message), {\n status: res.status,\n errors: body.errors,\n })\n }\n } catch (e) {\n if (e instanceof Error && 'errors' in e) throw e\n }\n throw Object.assign(new Error(message), { status: res.status })\n }\n\n if (res.status === 204) return undefined as T\n return res.json()\n }\n\n return {\n list<T>(\n url: string,\n params?: Record<string, string | number | boolean>,\n ): Promise<T[]> {\n const query = params\n ? `?${new URLSearchParams(Object.entries(params).map(([k, v]) => [k, String(v)])).toString()}`\n : ''\n return request<T[]>(`${url}${query}`)\n },\n getById<T>(url: string, id: string | number): Promise<T> {\n return request<T>(`${url}/${id}`)\n },\n create<T>(url: string, data: unknown): Promise<T> {\n return request<T>(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n },\n update<T>(url: string, id: string | number, data: unknown): Promise<T> {\n return request<T>(`${url}/${id}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n },\n delete(url: string, id: string | number): Promise<void> {\n return request<void>(`${url}/${id}`, { method: 'DELETE' })\n },\n }\n}\n\n// ─── Schema validation ────────────────────────────────────────────────────────\n\nfunction createValidator<TValues extends Record<string, unknown>>(\n schema: unknown,\n customValidate?: SchemaValidateFn<TValues>,\n): SchemaValidateFn<TValues> | undefined {\n if (customValidate) return customValidate\n\n if (\n schema &&\n typeof schema === 'object' &&\n 'safeParseAsync' in schema &&\n typeof (schema as Record<string, unknown>).safeParseAsync === 'function'\n ) {\n return zodSchema(\n schema as Parameters<typeof zodSchema>[0],\n ) as SchemaValidateFn<TValues>\n }\n\n return undefined\n}\n\n// ─── Resolve page value ───────────────────────────────────────────────────────\n\nfunction resolvePageValue(\n page: number | (() => number) | undefined,\n): number | undefined {\n if (page === undefined) return undefined\n if (typeof page === 'function') return page()\n return page\n}\n\n// ─── defineFeature ────────────────────────────────────────────────────────────\n\n/**\n * Define a schema-driven feature with auto-generated CRUD hooks.\n *\n * @example\n * ```ts\n * import { defineFeature } from '@pyreon/feature'\n * import { z } from 'zod'\n *\n * const users = defineFeature({\n * name: 'users',\n * schema: z.object({\n * name: z.string().min(2),\n * email: z.string().email(),\n * role: z.enum(['admin', 'editor', 'viewer']),\n * }),\n * api: '/api/users',\n * })\n * ```\n */\nexport function defineFeature<TValues extends Record<string, unknown>>(\n config: FeatureConfig<TValues>,\n): Feature<TValues> {\n const { name, schema, api, fetcher: customFetcher } = config\n const http = createFetcher(customFetcher)\n\n // Introspect schema fields\n const fields = extractFields(schema)\n const autoInitialValues = defaultInitialValues(fields) as TValues\n const initialValues = config.initialValues\n ? { ...autoInitialValues, ...config.initialValues }\n : autoInitialValues\n\n const validate = createValidator<TValues>(schema, config.validate)\n\n const queryKeyBase = [name] as const\n const queryKey = (suffix?: string | number): QueryKey =>\n suffix !== undefined ? [name, suffix] : [name]\n\n // ─── Store definition ──────────────────────────────────────────────\n\n const useStoreHook = defineStore<FeatureStore<TValues>>(name, () => {\n const items = signal<TValues[]>([])\n const selected = signal<TValues | null>(null)\n const loading = signal(false)\n\n const select = (id: string | number) => {\n const found = items.peek().find((item) => {\n const record = item as Record<string, unknown>\n return record.id === id\n })\n selected.set(found ?? null)\n }\n\n const clear = () => {\n selected.set(null)\n }\n\n return { items, selected, loading, select, clear }\n })\n\n return {\n name,\n api,\n schema,\n fields,\n queryKey,\n\n // ─── Store ───────────────────────────────────────────────────────\n\n useStore: useStoreHook,\n\n // ─── Queries ────────────────────────────────────────────────────\n\n useList(options?: ListOptions) {\n return _useQuery(() => {\n const pageValue = resolvePageValue(options?.page)\n const pageSize = options?.pageSize ?? 20\n\n const params: Record<string, string | number | boolean> = {\n ...(options?.params ?? {}),\n }\n\n if (pageValue !== undefined) {\n params.page = pageValue\n params.pageSize = pageSize\n }\n\n const queryKeyParts: unknown[] = [...queryKeyBase, 'list', params]\n\n return {\n queryKey: queryKeyParts as QueryKey,\n queryFn: () =>\n http.list<TValues>(\n api,\n Object.keys(params).length > 0 ? params : undefined,\n ),\n staleTime: options?.staleTime,\n enabled: options?.enabled,\n }\n })\n },\n\n useById(id: string | number) {\n return _useQuery(() => ({\n queryKey: [name, id],\n queryFn: () => http.getById<TValues>(api, id),\n enabled: id !== undefined && id !== null,\n }))\n },\n\n useSearch(searchTerm, options?: ListOptions) {\n return _useQuery(() => ({\n queryKey: [...queryKeyBase, 'search', searchTerm()],\n queryFn: () =>\n http.list<TValues>(api, { ...options?.params, q: searchTerm() }),\n enabled: searchTerm().length > 0,\n staleTime: options?.staleTime,\n }))\n },\n\n // ─── Mutations ──────────────────────────────────────────────────\n\n useCreate() {\n const client = useQueryClient()\n return _useMutation({\n mutationFn: (data: Partial<TValues>) => http.create<TValues>(api, data),\n onSuccess: () => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n },\n })\n },\n\n useUpdate() {\n type TVariables = { id: string | number; data: Partial<TValues> }\n const client = useQueryClient()\n return _useMutation<TValues, unknown, TVariables, { previous?: unknown }>(\n {\n mutationFn: ({ id, data }: TVariables) =>\n http.update<TValues>(api, id, data),\n onMutate: async (variables) => {\n await client.cancelQueries({ queryKey: [name, variables.id] })\n const previous = client.getQueryData([name, variables.id])\n client.setQueryData([name, variables.id], (old: unknown) => {\n if (old && typeof old === 'object') {\n return { ...old, ...variables.data }\n }\n return variables.data\n })\n return { previous }\n },\n onError: (_err, variables, context) => {\n if (context?.previous) {\n client.setQueryData([name, variables.id], context.previous)\n }\n },\n onSuccess: (_data, variables) => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n client.invalidateQueries({ queryKey: [name, variables.id] })\n },\n },\n ) as ReturnType<Feature<TValues>['useUpdate']>\n },\n\n useDelete() {\n const client = useQueryClient()\n return _useMutation({\n mutationFn: (id: string | number) => http.delete(api, id),\n onSuccess: () => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n },\n })\n },\n\n // ─── Form ───────────────────────────────────────────────────────\n\n useForm(options?: FeatureFormOptions<TValues>) {\n const mode = options?.mode ?? 'create'\n const mergedInitial = {\n ...initialValues,\n ...(options?.initialValues ?? {}),\n } as TValues\n\n const form = _useForm<TValues>({\n initialValues: mergedInitial,\n schema: validate,\n validateOn: options?.validateOn ?? 'blur',\n onSubmit: async (values) => {\n try {\n let result: unknown\n if (mode === 'edit' && options?.id !== undefined) {\n result = await http.update<TValues>(api, options.id, values)\n } else {\n result = await http.create<TValues>(api, values)\n }\n options?.onSuccess?.(result)\n } catch (err) {\n options?.onError?.(err)\n throw err\n }\n },\n })\n\n // Auto-fetch in edit mode\n if (mode === 'edit' && options?.id !== undefined) {\n form.isSubmitting.set(true)\n http.getById<TValues>(api, options.id).then(\n (data) => {\n batch(() => {\n for (const key of Object.keys(data)) {\n form.setFieldValue(\n key as keyof TValues & string,\n (data as Record<string, unknown>)[\n key\n ] as TValues[keyof TValues],\n )\n }\n form.isSubmitting.set(false)\n })\n },\n () => {\n form.isSubmitting.set(false)\n },\n )\n }\n\n return form\n },\n\n // ─── Table ──────────────────────────────────────────────────────\n\n useTable(\n data: TValues[] | (() => TValues[]),\n options?: FeatureTableOptions<TValues>,\n ) {\n const visibleFields = options?.columns\n ? fields.filter((f) =>\n options.columns!.includes(f.name as keyof TValues & string),\n )\n : fields\n\n const columns: ColumnDef<TValues, unknown>[] = visibleFields.map(\n (field) => ({\n accessorKey: field.name,\n header: field.label,\n ...(options?.columnOverrides?.[\n field.name as keyof TValues & string\n ] ?? {}),\n }),\n )\n\n const sorting = signal<SortingState>([])\n const globalFilter = signal('')\n\n const table = _useTable(() => ({\n data: typeof data === 'function' ? data() : data,\n columns,\n state: {\n sorting: sorting(),\n globalFilter: globalFilter(),\n },\n onSortingChange: (updater: unknown) => {\n sorting.set(\n typeof updater === 'function'\n ? (updater as (prev: SortingState) => SortingState)(sorting())\n : (updater as SortingState),\n )\n },\n onGlobalFilterChange: (updater: unknown) => {\n globalFilter.set(\n typeof updater === 'function'\n ? (updater as (prev: string) => string)(globalFilter())\n : (updater as string),\n )\n },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n ...(options?.pageSize\n ? { getPaginationRowModel: getPaginationRowModel() }\n : {}),\n }))\n\n return {\n table,\n sorting,\n globalFilter,\n columns: visibleFields,\n }\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_useQuery","_useMutation","_useForm","_useTable"],"sources":["../src/schema.ts","../src/define-feature.ts"],"sourcesContent":["/**\n * Schema introspection utilities.\n *\n * Extracts field names, types, and metadata from Zod schemas at runtime\n * without importing Zod types directly (duck-typed).\n */\n\nexport interface FieldInfo {\n /** Field name (key in the schema object). */\n name: string\n /** Inferred type: 'string' | 'number' | 'boolean' | 'date' | 'enum' | 'array' | 'object' | 'reference' | 'unknown'. */\n type: FieldType\n /** Whether the field is optional. */\n optional: boolean\n /** For enum fields, the list of allowed values. */\n enumValues?: (string | number)[]\n /** For reference fields, the name of the referenced feature. */\n referenceTo?: string\n /** Human-readable label derived from field name. */\n label: string\n}\n\nexport type FieldType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'enum'\n | 'array'\n | 'object'\n | 'reference'\n | 'unknown'\n\n/** Symbol used to tag reference schema objects. */\nconst REFERENCE_TAG = Symbol.for('pyreon:feature:reference')\n\n/**\n * Metadata carried by a reference schema.\n */\nexport interface ReferenceSchema {\n /** Marker symbol for detection. */\n [key: symbol]: true\n /** Name of the referenced feature. */\n _featureName: string\n /** Duck-typed Zod-like interface: validates as string | number. */\n safeParse: (value: unknown) => {\n success: boolean\n error?: { issues: { message: string }[] }\n }\n /** Async variant for compatibility. */\n safeParseAsync: (\n value: unknown,\n ) => Promise<{ success: boolean; error?: { issues: { message: string }[] } }>\n /** Shape-like marker for schema introspection. */\n _def: { typeName: string }\n}\n\n/**\n * Check if a value is a reference schema created by `reference()`.\n */\nexport function isReference(value: unknown): value is ReferenceSchema {\n return (\n value !== null &&\n typeof value === 'object' &&\n (value as Record<symbol, unknown>)[REFERENCE_TAG] === true\n )\n}\n\n/**\n * Create a reference field that links to another feature.\n *\n * Returns a Zod-compatible schema that validates as `string | number` and\n * carries metadata about the referenced feature for form dropdowns and table links.\n *\n * @example\n * ```ts\n * import { defineFeature, reference } from '@pyreon/feature'\n *\n * const posts = defineFeature({\n * name: 'posts',\n * schema: z.object({\n * title: z.string(),\n * authorId: reference(users),\n * }),\n * api: '/api/posts',\n * })\n * ```\n */\nexport function reference(feature: { name: string }): ReferenceSchema {\n const featureName = feature.name\n\n function validateRef(value: unknown): {\n success: boolean\n error?: { issues: { message: string }[] }\n } {\n if (typeof value === 'string' || typeof value === 'number') {\n return { success: true }\n }\n return {\n success: false,\n error: {\n issues: [\n {\n message: `Expected string or number reference to ${featureName}, got ${typeof value}`,\n },\n ],\n },\n }\n }\n\n return {\n [REFERENCE_TAG]: true,\n _featureName: featureName,\n safeParse: validateRef,\n safeParseAsync: async (value: unknown) => validateRef(value),\n _def: { typeName: 'ZodString' },\n }\n}\n\n/**\n * Convert a field name to a human-readable label.\n * e.g., 'firstName' → 'First Name', 'created_at' → 'Created At'\n */\nfunction nameToLabel(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase → camel Case\n .replace(/[_-]/g, ' ') // snake_case/kebab-case → spaces\n .replace(/\\b\\w/g, (c) => c.toUpperCase()) // capitalize words\n}\n\n/**\n * Detect the field type from a Zod schema shape entry.\n * Duck-typed — works with Zod v3 and v4 without importing Zod.\n */\nfunction detectFieldType(zodField: unknown): {\n type: FieldType\n optional: boolean\n enumValues?: (string | number)[]\n referenceTo?: string\n} {\n // Check for reference fields first\n if (isReference(zodField)) {\n return {\n type: 'reference',\n optional: false,\n referenceTo: zodField._featureName,\n }\n }\n\n if (!zodField || typeof zodField !== 'object') {\n return { type: 'unknown', optional: false }\n }\n\n const field = zodField as Record<string, unknown>\n\n // Check for optional wrapper (ZodOptional or ZodNullable)\n let inner = field\n let optional = false\n\n // Zod v3: _def.typeName, Zod v4: _zod.def.type\n const getTypeName = (obj: Record<string, unknown>): string | undefined => {\n // v3 path\n const def = obj._def as Record<string, unknown> | undefined\n if (def?.typeName && typeof def.typeName === 'string') {\n return def.typeName\n }\n // v4 path\n const zod = obj._zod as Record<string, unknown> | undefined\n const zodDef = zod?.def as Record<string, unknown> | undefined\n if (zodDef?.type && typeof zodDef.type === 'string') {\n return zodDef.type\n }\n return undefined\n }\n\n const typeName = getTypeName(inner)\n\n // Unwrap optional/nullable\n if (\n typeName === 'ZodOptional' ||\n typeName === 'ZodNullable' ||\n typeName === 'optional' ||\n typeName === 'nullable'\n ) {\n optional = true\n const def = inner._def as Record<string, unknown> | undefined\n const innerType =\n def?.innerType ?? (inner._zod as Record<string, unknown>)?.def\n if (innerType && typeof innerType === 'object') {\n inner = innerType as Record<string, unknown>\n }\n }\n\n const innerTypeName = getTypeName(inner) ?? typeName\n\n // Map Zod type names to our FieldType\n if (!innerTypeName) return { type: 'unknown', optional }\n\n const typeMap: Record<string, FieldType> = {\n ZodString: 'string',\n ZodNumber: 'number',\n ZodBoolean: 'boolean',\n ZodDate: 'date',\n ZodEnum: 'enum',\n ZodNativeEnum: 'enum',\n ZodArray: 'array',\n ZodObject: 'object',\n // v4 names\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n date: 'date',\n enum: 'enum',\n array: 'array',\n object: 'object',\n }\n\n const type = typeMap[innerTypeName] ?? 'string'\n\n // Extract enum values\n let enumValues: (string | number)[] | undefined\n if (type === 'enum') {\n const def = inner._def as Record<string, unknown> | undefined\n if (def?.values && Array.isArray(def.values)) {\n enumValues = def.values as (string | number)[]\n }\n // v4 path\n const zodDef = (inner._zod as Record<string, unknown>)?.def as\n | Record<string, unknown>\n | undefined\n if (zodDef?.values && Array.isArray(zodDef.values)) {\n enumValues = zodDef.values as (string | number)[]\n }\n }\n\n return {\n type,\n optional,\n ...(enumValues != null ? { enumValues } : {}),\n }\n}\n\n/**\n * Extract field information from a Zod object schema.\n * Returns an array of FieldInfo objects describing each field.\n *\n * @example\n * ```ts\n * const schema = z.object({ name: z.string(), age: z.number().optional() })\n * const fields = extractFields(schema)\n * // [\n * // { name: 'name', type: 'string', optional: false, label: 'Name' },\n * // { name: 'age', type: 'number', optional: true, label: 'Age' },\n * // ]\n * ```\n */\nexport function extractFields(schema: unknown): FieldInfo[] {\n if (!schema || typeof schema !== 'object') return []\n\n const s = schema as Record<string, unknown>\n\n // Get the shape object from the schema\n // Zod v3: schema._def.shape() or schema.shape\n // Zod v4: schema._zod.def.shape or schema.shape\n let shape: Record<string, unknown> | undefined\n\n // Try schema.shape (works for both v3 and v4)\n if (s.shape && typeof s.shape === 'object') {\n shape = s.shape as Record<string, unknown>\n }\n\n // Try _def.shape (v3 — can be a function)\n if (!shape) {\n const def = s._def as Record<string, unknown> | undefined\n if (def?.shape) {\n shape =\n typeof def.shape === 'function'\n ? (def.shape as () => Record<string, unknown>)()\n : (def.shape as Record<string, unknown>)\n }\n }\n\n // Try _zod.def.shape (v4)\n if (!shape) {\n const zod = s._zod as Record<string, unknown> | undefined\n const zodDef = zod?.def as Record<string, unknown> | undefined\n if (zodDef?.shape && typeof zodDef.shape === 'object') {\n shape = zodDef.shape as Record<string, unknown>\n }\n }\n\n if (!shape) return []\n\n return Object.entries(shape).map(([name, fieldSchema]) => {\n const { type, optional, enumValues, referenceTo } =\n detectFieldType(fieldSchema)\n const info: FieldInfo = {\n name,\n type,\n optional,\n label: nameToLabel(name),\n }\n if (enumValues) info.enumValues = enumValues\n if (referenceTo) info.referenceTo = referenceTo\n return info\n })\n}\n\n/**\n * Generate default initial values from a schema's field types.\n */\nexport function defaultInitialValues(\n fields: FieldInfo[],\n): Record<string, unknown> {\n const values: Record<string, unknown> = {}\n for (const field of fields) {\n switch (field.type) {\n case 'string':\n values[field.name] = ''\n break\n case 'number':\n values[field.name] = 0\n break\n case 'boolean':\n values[field.name] = false\n break\n case 'enum':\n values[field.name] = field.enumValues?.[0] ?? ''\n break\n case 'date':\n values[field.name] = ''\n break\n default:\n values[field.name] = ''\n }\n }\n return values\n}\n","import type { SchemaValidateFn } from '@pyreon/form'\nimport { useForm as _useForm } from '@pyreon/form'\nimport type { QueryKey } from '@pyreon/query'\nimport {\n useMutation as _useMutation,\n useQuery as _useQuery,\n useQueryClient,\n} from '@pyreon/query'\nimport { batch, signal } from '@pyreon/reactivity'\nimport { defineStore } from '@pyreon/store'\nimport type { ColumnDef, SortingState } from '@pyreon/table'\nimport {\n useTable as _useTable,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n} from '@pyreon/table'\nimport { zodSchema } from '@pyreon/validation'\nimport { defaultInitialValues, extractFields } from './schema'\nimport type {\n Feature,\n FeatureConfig,\n FeatureFormOptions,\n FeatureStore,\n FeatureTableOptions,\n ListOptions,\n} from './types'\n\n// ─── Fetch wrapper ────────────────────────────────────────────────────────────\n\nfunction createFetcher(baseFetcher: typeof fetch = fetch) {\n async function request<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await baseFetcher(url, init)\n\n if (!res.ok) {\n let message = `${init?.method ?? 'GET'} ${url} failed: ${res.status}`\n try {\n const body = await res.json()\n if (body?.message) message = body.message\n if (body?.errors) {\n throw Object.assign(new Error(message), {\n status: res.status,\n errors: body.errors,\n })\n }\n } catch (e) {\n if (e instanceof Error && 'errors' in e) throw e\n }\n throw Object.assign(new Error(message), { status: res.status })\n }\n\n if (res.status === 204) return undefined as T\n return res.json()\n }\n\n return {\n list<T>(\n url: string,\n params?: Record<string, string | number | boolean>,\n ): Promise<T[]> {\n const query = params\n ? `?${new URLSearchParams(Object.entries(params).map(([k, v]) => [k, String(v)])).toString()}`\n : ''\n return request<T[]>(`${url}${query}`)\n },\n getById<T>(url: string, id: string | number): Promise<T> {\n return request<T>(`${url}/${id}`)\n },\n create<T>(url: string, data: unknown): Promise<T> {\n return request<T>(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n },\n update<T>(url: string, id: string | number, data: unknown): Promise<T> {\n return request<T>(`${url}/${id}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n },\n delete(url: string, id: string | number): Promise<void> {\n return request<void>(`${url}/${id}`, { method: 'DELETE' })\n },\n }\n}\n\n// ─── Schema validation ────────────────────────────────────────────────────────\n\nfunction createValidator<TValues extends Record<string, unknown>>(\n schema: unknown,\n customValidate?: SchemaValidateFn<TValues>,\n): SchemaValidateFn<TValues> | undefined {\n if (customValidate) return customValidate\n\n if (\n schema &&\n typeof schema === 'object' &&\n 'safeParseAsync' in schema &&\n typeof (schema as Record<string, unknown>).safeParseAsync === 'function'\n ) {\n return zodSchema(\n schema as Parameters<typeof zodSchema>[0],\n ) as SchemaValidateFn<TValues>\n }\n\n return undefined\n}\n\n// ─── Resolve page value ───────────────────────────────────────────────────────\n\nfunction resolvePageValue(\n page: number | (() => number) | undefined,\n): number | undefined {\n if (page === undefined) return undefined\n if (typeof page === 'function') return page()\n return page\n}\n\n// ─── defineFeature ────────────────────────────────────────────────────────────\n\n/**\n * Define a schema-driven feature with auto-generated CRUD hooks.\n *\n * @example\n * ```ts\n * import { defineFeature } from '@pyreon/feature'\n * import { z } from 'zod'\n *\n * const users = defineFeature({\n * name: 'users',\n * schema: z.object({\n * name: z.string().min(2),\n * email: z.string().email(),\n * role: z.enum(['admin', 'editor', 'viewer']),\n * }),\n * api: '/api/users',\n * })\n * ```\n */\nexport function defineFeature<TValues extends Record<string, unknown>>(\n config: FeatureConfig<TValues>,\n): Feature<TValues> {\n const { name, schema, api, fetcher: customFetcher } = config\n const http = createFetcher(customFetcher)\n\n // Introspect schema fields\n const fields = extractFields(schema)\n const autoInitialValues = defaultInitialValues(fields) as TValues\n const initialValues = config.initialValues\n ? { ...autoInitialValues, ...config.initialValues }\n : autoInitialValues\n\n const validate = createValidator<TValues>(schema, config.validate)\n\n const queryKeyBase = [name] as const\n const queryKey = (suffix?: string | number): QueryKey =>\n suffix !== undefined ? [name, suffix] : [name]\n\n // ─── Store definition ──────────────────────────────────────────────\n\n const useStoreHook = defineStore<FeatureStore<TValues>>(name, () => {\n const items = signal<TValues[]>([])\n const selected = signal<TValues | null>(null)\n const loading = signal(false)\n\n const select = (id: string | number) => {\n const found = items.peek().find((item) => {\n const record = item as Record<string, unknown>\n return record.id === id\n })\n selected.set(found ?? null)\n }\n\n const clear = () => {\n selected.set(null)\n }\n\n return { items, selected, loading, select, clear }\n })\n\n return {\n name,\n api,\n schema,\n fields,\n queryKey,\n\n // ─── Store ───────────────────────────────────────────────────────\n\n useStore: useStoreHook,\n\n // ─── Queries ────────────────────────────────────────────────────\n\n useList(options?: ListOptions) {\n return _useQuery(() => {\n const pageValue = resolvePageValue(options?.page)\n const pageSize = options?.pageSize ?? 20\n\n const params: Record<string, string | number | boolean> = {\n ...(options?.params ?? {}),\n }\n\n if (pageValue !== undefined) {\n params.page = pageValue\n params.pageSize = pageSize\n }\n\n const queryKeyParts: unknown[] = [...queryKeyBase, 'list', params]\n\n return {\n queryKey: queryKeyParts as QueryKey,\n queryFn: () =>\n http.list<TValues>(\n api,\n Object.keys(params).length > 0 ? params : undefined,\n ),\n ...(options?.staleTime != null\n ? { staleTime: options.staleTime }\n : {}),\n ...(options?.enabled != null ? { enabled: options.enabled } : {}),\n }\n })\n },\n\n useById(id: string | number) {\n return _useQuery(() => ({\n queryKey: [name, id],\n queryFn: () => http.getById<TValues>(api, id),\n enabled: id !== undefined && id !== null,\n }))\n },\n\n useSearch(searchTerm, options?: ListOptions) {\n return _useQuery(() => ({\n queryKey: [...queryKeyBase, 'search', searchTerm()],\n queryFn: () =>\n http.list<TValues>(api, { ...options?.params, q: searchTerm() }),\n enabled: searchTerm().length > 0,\n ...(options?.staleTime != null ? { staleTime: options.staleTime } : {}),\n }))\n },\n\n // ─── Mutations ──────────────────────────────────────────────────\n\n useCreate() {\n const client = useQueryClient()\n return _useMutation({\n mutationFn: (data: Partial<TValues>) => http.create<TValues>(api, data),\n onSuccess: () => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n },\n })\n },\n\n useUpdate() {\n type TVariables = { id: string | number; data: Partial<TValues> }\n const client = useQueryClient()\n return _useMutation<TValues, unknown, TVariables, { previous?: unknown }>(\n {\n mutationFn: ({ id, data }: TVariables) =>\n http.update<TValues>(api, id, data),\n onMutate: async (variables) => {\n await client.cancelQueries({ queryKey: [name, variables.id] })\n const previous = client.getQueryData([name, variables.id])\n client.setQueryData([name, variables.id], (old: unknown) => {\n if (old && typeof old === 'object') {\n return { ...old, ...variables.data }\n }\n return variables.data\n })\n return { previous }\n },\n onError: (_err, variables, context) => {\n if (context?.previous) {\n client.setQueryData([name, variables.id], context.previous)\n }\n },\n onSuccess: (_data, variables) => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n client.invalidateQueries({ queryKey: [name, variables.id] })\n },\n },\n ) as ReturnType<Feature<TValues>['useUpdate']>\n },\n\n useDelete() {\n const client = useQueryClient()\n return _useMutation({\n mutationFn: (id: string | number) => http.delete(api, id),\n onSuccess: () => {\n client.invalidateQueries({\n queryKey: queryKeyBase as unknown as QueryKey,\n })\n },\n })\n },\n\n // ─── Form ───────────────────────────────────────────────────────\n\n useForm(options?: FeatureFormOptions<TValues>) {\n const mode = options?.mode ?? 'create'\n const mergedInitial = {\n ...initialValues,\n ...(options?.initialValues ?? {}),\n } as TValues\n\n const form = _useForm<TValues>({\n initialValues: mergedInitial,\n ...(validate != null ? { schema: validate } : {}),\n validateOn: options?.validateOn ?? 'blur',\n onSubmit: async (values) => {\n try {\n let result: unknown\n if (mode === 'edit' && options?.id !== undefined) {\n result = await http.update<TValues>(api, options.id, values)\n } else {\n result = await http.create<TValues>(api, values)\n }\n options?.onSuccess?.(result)\n } catch (err) {\n options?.onError?.(err)\n throw err\n }\n },\n })\n\n // Auto-fetch in edit mode\n if (mode === 'edit' && options?.id !== undefined) {\n form.isSubmitting.set(true)\n http.getById<TValues>(api, options.id).then(\n (data) => {\n batch(() => {\n for (const key of Object.keys(data)) {\n form.setFieldValue(\n key as keyof TValues & string,\n (data as Record<string, unknown>)[\n key\n ] as TValues[keyof TValues],\n )\n }\n form.isSubmitting.set(false)\n })\n },\n () => {\n form.isSubmitting.set(false)\n },\n )\n }\n\n return form\n },\n\n // ─── Table ──────────────────────────────────────────────────────\n\n useTable(\n data: TValues[] | (() => TValues[]),\n options?: FeatureTableOptions<TValues>,\n ) {\n const visibleFields = options?.columns\n ? fields.filter((f) =>\n options.columns!.includes(f.name as keyof TValues & string),\n )\n : fields\n\n const columns: ColumnDef<TValues, unknown>[] = visibleFields.map(\n (field) => ({\n accessorKey: field.name,\n header: field.label,\n ...(options?.columnOverrides?.[\n field.name as keyof TValues & string\n ] ?? {}),\n }),\n )\n\n const sorting = signal<SortingState>([])\n const globalFilter = signal('')\n\n const table = _useTable(() => ({\n data: typeof data === 'function' ? data() : data,\n columns,\n state: {\n sorting: sorting(),\n globalFilter: globalFilter(),\n },\n onSortingChange: (updater: unknown) => {\n sorting.set(\n typeof updater === 'function'\n ? (updater as (prev: SortingState) => SortingState)(sorting())\n : (updater as SortingState),\n )\n },\n onGlobalFilterChange: (updater: unknown) => {\n globalFilter.set(\n typeof updater === 'function'\n ? (updater as (prev: string) => string)(globalFilter())\n : (updater as string),\n )\n },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n ...(options?.pageSize\n ? { getPaginationRowModel: getPaginationRowModel() }\n : {}),\n }))\n\n return {\n table,\n sorting,\n globalFilter,\n columns: visibleFields,\n }\n },\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/schema.ts","../../../src/types.ts","../../../src/define-feature.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/schema.ts","../../../src/types.ts","../../../src/define-feature.ts"],"mappings":";;;;;;;;;;;;;;UAOiB,SAAA;;EAEf,IAAA;EAFwB;EAIxB,IAAA,EAAM,SAAA;EAAS;EAEf,QAAA;EAFA;EAIA,UAAA;EAFA;EAIA,WAAA;EAAA;EAEA,KAAA;AAAA;AAAA,KAGU,SAAA;AAAZ;;;AAAA,UAiBiB,eAAA;EAjBI;EAAA,CAmBlB,GAAA;EAF6B;EAI9B,YAAA;EASY;EAPZ,SAAA,GAAY,KAAA;IACV,OAAA;IACA,KAAA;MAAU,MAAA;QAAU,OAAA;MAAA;IAAA;EAAA;EAGtB;EAAA,cAAA,GACE,KAAA,cACG,OAAA;IAAU,OAAA;IAAkB,KAAA;MAAU,MAAA;QAAU,OAAA;MAAA;IAAA;EAAA;EAErC;EAAhB,IAAA;IAAQ,QAAA;EAAA;AAAA;;;;iBAMM,WAAA,CAAY,KAAA,YAAiB,KAAA,IAAS,eAAA;;;AA4BtD;;;;;;;;;AAwKA;;;;;AAuDA;;;;iBA/NgB,SAAA,CAAU,OAAA;EAAW,IAAA;AAAA,IAAiB,eAAA;;;;;;AC9EtD;;;;;;;;;iBDsPgB,aAAA,CAAc,MAAA,YAAkB,SAAA;;;;iBAuDhC,oBAAA,CACd,MAAA,EAAQ,SAAA,KACP,MAAA;;;;;AAlTH;UCGiB,aAAA,iBAA8B,MAAA;;EAE7C,IAAA;EDHA;ECKA,MAAA;EDHM;ECKN,QAAA,GAAW,gBAAA,CAAiB,OAAA;EDD5B;ECGA,GAAA;EDCA;ECCA,aAAA,GAAgB,OAAA,CAAQ,OAAA;EDDnB;ECGL,OAAA,UAAiB,KAAA;AAAA;;;;UAMF,WAAA;EDWe;ECT9B,MAAA,GAAS,MAAA;EDsBG;ECpBZ,IAAA,YAAgB,MAAA;EDWhB;ECTA,QAAA;EDWY;ECTZ,SAAA;EDWE;ECTF,OAAA;AAAA;;;;UAMe,kBAAA,iBAAmC,MAAA;EDQjB;ECNjC,IAAA;EDMqD;ECJrD,EAAA;EDMQ;ECJR,aAAA,GAAgB,OAAA,CAAQ,OAAA;EDIR;ECFhB,UAAA;EDQyB;ECNzB,SAAA,IAAa,MAAA;EDMsD;ECJnE,OAAA,IAAW,KAAA;AAAA;;;;UAMI,mBAAA,iBAAoC,MAAA;ED0B5B;ECxBvB,OAAA,UAAiB,OAAA;EDwBkD;ECtBnE,eAAA,GAAkB,OAAA,CAChB,MAAA,OAAa,OAAA,WAAkB,MAAA;EDqBT;EClBxB,QAAA;AAAA;;AD0LF;;UCpLiB,kBAAA,iBAAmC,MAAA;EDoLtB;EClL5B,KAAA,EAAO,QAAA,CAA8C,cAAA,CAAb,KAAA,CAAM,OAAA;EDyOhC;ECvOd,OAAA,EAAS,MAAA,CAAO,YAAA;;EAEhB,YAAA,EAAc,MAAA;EDsON;ECpOR,OAAA,EAAS,SAAA;AAAA;;;;UAMM,YAAA,iBAA6B,MAAA;;EAE5C,KAAA,EAAO,MAAA,CAAO,OAAA;EAlFc;EAoF5B,QAAA,EAAU,MAAA,CAAO,OAAA;EApF4B;EAsF7C,OAAA,EAAS,MAAA;EAhFE;EAkFX,MAAA,GAAS,EAAA;EA9EO;EAgFhB,KAAA;EA9EsB;EAAA,CAgFrB,GAAA;AAAA;;;;UAMc,OAAA,iBAAwB,MAAA;EA5F5B;EA8FX,IAAA;EA5FA;EA8FA,GAAA;EA5FgB;EA8FhB,MAAA;EA5FA;EA8FA,MAAA,EAAQ,SAAA;EA9Fc;EAiGtB,OAAA,GAAU,OAAA,GAAU,WAAA,KAAgB,cAAA,CAAe,OAAA;EA3FpC;EA8Ff,OAAA,GAAU,EAAA,sBAAwB,cAAA,CAAe,OAAA;;EAGjD,SAAA,GACE,UAAA,EAAY,MAAA,UACZ,OAAA,GAAU,WAAA,KACP,cAAA,CAAe,OAAA;EAlGpB;EAqGA,SAAA,QAAiB,iBAAA,CAAkB,OAAA,WAAkB,OAAA,CAAQ,OAAA;EAnG7D;EAsGA,SAAA,QAAiB,iBAAA,CACf,OAAA;IAEE,EAAA;IAAqB,IAAA,EAAM,OAAA,CAAQ,OAAA;EAAA;EAnGhC;EAuGP,SAAA,QAAiB,iBAAA;EAjGF;EAoGf,OAAA,GAAU,OAAA,GAAU,kBAAA,CAAmB,OAAA,MAAa,SAAA,CAAU,OAAA;EApG7B;EAuGjC,QAAA,GACE,IAAA,EAAM,OAAA,YAAmB,OAAA,KACzB,OAAA,GAAU,mBAAA,CAAoB,OAAA,MAC3B,kBAAA,CAAmB,OAAA;EApGA;EAuGxB,QAAA,QAAgB,QAAA,CAAS,YAAA,CAAa,OAAA;EAvGf;EA0GvB,QAAA,GAAW,MAAA,uBAA6B,QAAA;AAAA;;;;;;;;;;ADrJ1C;;;;;;;;;;;;iBEuIgB,aAAA,iBAA8B,MAAA,kBAAA,CAC5C,MAAA,EAAQ,aAAA,CAAc,OAAA,IACrB,OAAA,CAAQ,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/feature",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Schema-driven feature primitives — define once, get CRUD hooks, forms, tables, and stores",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,14 +40,14 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "peerDependencies": {
43
- "@pyreon/core": ">=0.5.0 <1.0.0",
44
- "@pyreon/reactivity": ">=0.5.0 <1.0.0"
43
+ "@pyreon/core": ">=0.7.0 <0.8.0",
44
+ "@pyreon/reactivity": ">=0.7.0 <0.8.0"
45
45
  },
46
46
  "dependencies": {
47
- "@pyreon/form": "^0.7.0",
48
- "@pyreon/query": "^0.7.0",
49
- "@pyreon/store": "^0.7.0",
50
- "@pyreon/table": "^0.7.0",
51
- "@pyreon/validation": "^0.7.0"
47
+ "@pyreon/form": "^0.9.0",
48
+ "@pyreon/query": "^0.9.0",
49
+ "@pyreon/store": "^0.9.0",
50
+ "@pyreon/table": "^0.9.0",
51
+ "@pyreon/validation": "^0.9.0"
52
52
  }
53
53
  }
@@ -217,8 +217,10 @@ export function defineFeature<TValues extends Record<string, unknown>>(
217
217
  api,
218
218
  Object.keys(params).length > 0 ? params : undefined,
219
219
  ),
220
- staleTime: options?.staleTime,
221
- enabled: options?.enabled,
220
+ ...(options?.staleTime != null
221
+ ? { staleTime: options.staleTime }
222
+ : {}),
223
+ ...(options?.enabled != null ? { enabled: options.enabled } : {}),
222
224
  }
223
225
  })
224
226
  },
@@ -237,7 +239,7 @@ export function defineFeature<TValues extends Record<string, unknown>>(
237
239
  queryFn: () =>
238
240
  http.list<TValues>(api, { ...options?.params, q: searchTerm() }),
239
241
  enabled: searchTerm().length > 0,
240
- staleTime: options?.staleTime,
242
+ ...(options?.staleTime != null ? { staleTime: options.staleTime } : {}),
241
243
  }))
242
244
  },
243
245
 
@@ -311,7 +313,7 @@ export function defineFeature<TValues extends Record<string, unknown>>(
311
313
 
312
314
  const form = _useForm<TValues>({
313
315
  initialValues: mergedInitial,
314
- schema: validate,
316
+ ...(validate != null ? { schema: validate } : {}),
315
317
  validateOn: options?.validateOn ?? 'blur',
316
318
  onSubmit: async (values) => {
317
319
  try {
package/src/schema.ts CHANGED
@@ -233,7 +233,11 @@ function detectFieldType(zodField: unknown): {
233
233
  }
234
234
  }
235
235
 
236
- return { type, optional, enumValues }
236
+ return {
237
+ type,
238
+ optional,
239
+ ...(enumValues != null ? { enumValues } : {}),
240
+ }
237
241
  }
238
242
 
239
243
  /**