@pyreon/feature 0.6.0 → 0.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/lib/analysis/index.js.html +1 -1
- package/lib/index.js +5 -5
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +238 -480
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/define-feature.ts +6 -4
- package/src/schema.ts +5 -1
- package/lib/types/index2.d.ts +0 -259
- package/lib/types/index2.d.ts.map +0 -1
|
@@ -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":"
|
|
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
|
|
323
|
-
enabled: options
|
|
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
|
|
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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"}
|