@json-render/core 0.2.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -85,7 +85,7 @@ type LogicExpression = {
85
85
  /**
86
86
  * Flat UI tree structure (optimized for LLM generation)
87
87
  */
88
- interface UITree {
88
+ interface Spec {
89
89
  /** Root element key */
90
90
  root: string;
91
91
  /** Flat map of elements by key */
@@ -131,9 +131,106 @@ declare function resolveDynamicValue<T>(value: DynamicValue<T>, dataModel: DataM
131
131
  */
132
132
  declare function getByPath(obj: unknown, path: string): unknown;
133
133
  /**
134
- * Set a value in an object by JSON Pointer path
134
+ * Set a value in an object by JSON Pointer path.
135
+ * Automatically creates arrays when the path segment is a numeric index.
135
136
  */
136
137
  declare function setByPath(obj: Record<string, unknown>, path: string, value: unknown): void;
138
+ /**
139
+ * Find a form value from params and/or data.
140
+ * Useful in action handlers to locate form input values regardless of path format.
141
+ *
142
+ * Checks in order:
143
+ * 1. Direct param key (if not a path reference)
144
+ * 2. Param keys ending with the field name
145
+ * 3. Data keys ending with the field name (dot notation)
146
+ * 4. Data paths using getByPath (slash notation)
147
+ *
148
+ * @example
149
+ * // Find "name" from params or data
150
+ * const name = findFormValue("name", params, data);
151
+ *
152
+ * // Will find from: params.name, params["form.name"], data["customerForm.name"], data.customerForm.name
153
+ */
154
+ declare function findFormValue(fieldName: string, params?: Record<string, unknown>, data?: Record<string, unknown>): unknown;
155
+ /**
156
+ * A SpecStream line - a single patch operation in the stream.
157
+ */
158
+ type SpecStreamLine = JsonPatch;
159
+ /**
160
+ * Parse a single SpecStream line into a patch operation.
161
+ * Returns null if the line is invalid or empty.
162
+ *
163
+ * SpecStream is json-render's streaming format where each line is a JSON patch
164
+ * operation that progressively builds up the final spec.
165
+ */
166
+ declare function parseSpecStreamLine(line: string): SpecStreamLine | null;
167
+ /**
168
+ * Apply a single SpecStream patch to an object.
169
+ * Mutates the object in place.
170
+ */
171
+ declare function applySpecStreamPatch<T extends Record<string, unknown>>(obj: T, patch: SpecStreamLine): T;
172
+ /**
173
+ * Compile a SpecStream string into a JSON object.
174
+ * Each line should be a patch operation.
175
+ *
176
+ * @example
177
+ * const stream = `{"op":"set","path":"/name","value":"Alice"}
178
+ * {"op":"set","path":"/age","value":30}`;
179
+ * const result = compileSpecStream(stream);
180
+ * // { name: "Alice", age: 30 }
181
+ */
182
+ declare function compileSpecStream<T extends Record<string, unknown> = Record<string, unknown>>(stream: string, initial?: T): T;
183
+ /**
184
+ * Streaming SpecStream compiler.
185
+ * Useful for processing SpecStream data as it streams in from AI.
186
+ *
187
+ * @example
188
+ * const compiler = createSpecStreamCompiler<MySpec>();
189
+ *
190
+ * // As chunks arrive:
191
+ * const { result, newPatches } = compiler.push(chunk);
192
+ * if (newPatches.length > 0) {
193
+ * updateUI(result);
194
+ * }
195
+ *
196
+ * // When done:
197
+ * const finalResult = compiler.getResult();
198
+ */
199
+ interface SpecStreamCompiler<T> {
200
+ /** Push a chunk of text. Returns the current result and any new patches applied. */
201
+ push(chunk: string): {
202
+ result: T;
203
+ newPatches: SpecStreamLine[];
204
+ };
205
+ /** Get the current compiled result */
206
+ getResult(): T;
207
+ /** Get all patches that have been applied */
208
+ getPatches(): SpecStreamLine[];
209
+ /** Reset the compiler to initial state */
210
+ reset(initial?: Partial<T>): void;
211
+ }
212
+ /**
213
+ * Create a streaming SpecStream compiler.
214
+ *
215
+ * SpecStream is json-render's streaming format. AI outputs patch operations
216
+ * line by line, and this compiler progressively builds the final spec.
217
+ *
218
+ * @example
219
+ * const compiler = createSpecStreamCompiler<TimelineSpec>();
220
+ *
221
+ * // Process streaming response
222
+ * const reader = response.body.getReader();
223
+ * while (true) {
224
+ * const { done, value } = await reader.read();
225
+ * if (done) break;
226
+ *
227
+ * const { result, newPatches } = compiler.push(decoder.decode(value));
228
+ * if (newPatches.length > 0) {
229
+ * setSpec(result); // Update UI with partial result
230
+ * }
231
+ * }
232
+ */
233
+ declare function createSpecStreamCompiler<T = Record<string, unknown>>(initial?: Partial<T>): SpecStreamCompiler<T>;
137
234
 
138
235
  /**
139
236
  * Logic expression schema (recursive)
@@ -485,6 +582,200 @@ declare const check: {
485
582
  matches: (otherPath: string, message?: string) => ValidationCheck;
486
583
  };
487
584
 
585
+ /**
586
+ * Schema builder primitives
587
+ */
588
+ interface SchemaBuilder {
589
+ /** String type */
590
+ string(): SchemaType<"string">;
591
+ /** Number type */
592
+ number(): SchemaType<"number">;
593
+ /** Boolean type */
594
+ boolean(): SchemaType<"boolean">;
595
+ /** Array of type */
596
+ array<T extends SchemaType>(item: T): SchemaType<"array", T>;
597
+ /** Object with shape */
598
+ object<T extends Record<string, SchemaType>>(shape: T): SchemaType<"object", T>;
599
+ /** Record/map with value type */
600
+ record<T extends SchemaType>(value: T): SchemaType<"record", T>;
601
+ /** Any type */
602
+ any(): SchemaType<"any">;
603
+ /** Placeholder for user-provided Zod schema */
604
+ zod(): SchemaType<"zod">;
605
+ /** Reference to catalog key (e.g., 'catalog.components') */
606
+ ref(path: string): SchemaType<"ref", string>;
607
+ /** Props from referenced catalog entry */
608
+ propsOf(path: string): SchemaType<"propsOf", string>;
609
+ /** Map of named entries with shared shape */
610
+ map<T extends Record<string, SchemaType>>(entryShape: T): SchemaType<"map", T>;
611
+ /** Optional modifier */
612
+ optional(): {
613
+ optional: true;
614
+ };
615
+ }
616
+ /**
617
+ * Schema type representation
618
+ */
619
+ interface SchemaType<TKind extends string = string, TInner = unknown> {
620
+ kind: TKind;
621
+ inner?: TInner;
622
+ optional?: boolean;
623
+ }
624
+ /**
625
+ * Schema definition shape
626
+ */
627
+ interface SchemaDefinition<TSpec extends SchemaType = SchemaType, TCatalog extends SchemaType = SchemaType> {
628
+ /** What the AI-generated spec looks like */
629
+ spec: TSpec;
630
+ /** What the catalog must provide */
631
+ catalog: TCatalog;
632
+ }
633
+ /**
634
+ * Schema instance with methods
635
+ */
636
+ interface Schema<TDef extends SchemaDefinition = SchemaDefinition> {
637
+ /** The schema definition */
638
+ readonly definition: TDef;
639
+ /** Custom prompt template for this schema */
640
+ readonly promptTemplate?: PromptTemplate;
641
+ /** Create a catalog from this schema */
642
+ createCatalog<TCatalog extends InferCatalogInput<TDef["catalog"]>>(catalog: TCatalog): Catalog$1<TDef, TCatalog>;
643
+ }
644
+ /**
645
+ * Catalog instance with methods
646
+ */
647
+ interface Catalog$1<TDef extends SchemaDefinition = SchemaDefinition, TCatalog = unknown> {
648
+ /** The schema this catalog is based on */
649
+ readonly schema: Schema<TDef>;
650
+ /** The catalog data */
651
+ readonly data: TCatalog;
652
+ /** Component names */
653
+ readonly componentNames: string[];
654
+ /** Action names */
655
+ readonly actionNames: string[];
656
+ /** Generate system prompt for AI */
657
+ prompt(options?: PromptOptions): string;
658
+ /** Export as JSON Schema for structured outputs */
659
+ jsonSchema(): object;
660
+ /** Validate a spec against this catalog */
661
+ validate(spec: unknown): SpecValidationResult<InferSpec<TDef, TCatalog>>;
662
+ /** Get the Zod schema for the spec */
663
+ zodSchema(): z.ZodType<InferSpec<TDef, TCatalog>>;
664
+ /** Type helper for the spec type */
665
+ readonly _specType: InferSpec<TDef, TCatalog>;
666
+ }
667
+ /**
668
+ * Prompt generation options
669
+ */
670
+ interface PromptOptions {
671
+ /** Custom system message intro */
672
+ system?: string;
673
+ /** Additional rules to append */
674
+ customRules?: string[];
675
+ }
676
+ /**
677
+ * Context provided to prompt templates
678
+ */
679
+ interface PromptContext<TCatalog = unknown> {
680
+ /** The catalog data */
681
+ catalog: TCatalog;
682
+ /** Component names from the catalog */
683
+ componentNames: string[];
684
+ /** Action names from the catalog (if any) */
685
+ actionNames: string[];
686
+ /** Prompt options provided by the user */
687
+ options: PromptOptions;
688
+ /** Helper to format a Zod type as a human-readable string */
689
+ formatZodType: (schema: z.ZodType) => string;
690
+ }
691
+ /**
692
+ * Prompt template function type
693
+ */
694
+ type PromptTemplate<TCatalog = unknown> = (context: PromptContext<TCatalog>) => string;
695
+ /**
696
+ * Schema options
697
+ */
698
+ interface SchemaOptions<TCatalog = unknown> {
699
+ /** Custom prompt template for this schema */
700
+ promptTemplate?: PromptTemplate<TCatalog>;
701
+ }
702
+ /**
703
+ * Spec validation result
704
+ */
705
+ interface SpecValidationResult<T> {
706
+ success: boolean;
707
+ data?: T;
708
+ error?: z.ZodError;
709
+ }
710
+ /**
711
+ * Extract the components map type from a catalog
712
+ * @example type Components = InferCatalogComponents<typeof myCatalog>;
713
+ */
714
+ type InferCatalogComponents<C extends Catalog$1> = C extends Catalog$1<SchemaDefinition, infer TCatalog> ? TCatalog extends {
715
+ components: infer Comps;
716
+ } ? Comps : never : never;
717
+ /**
718
+ * Extract the actions map type from a catalog
719
+ * @example type Actions = InferCatalogActions<typeof myCatalog>;
720
+ */
721
+ type InferCatalogActions<C extends Catalog$1> = C extends Catalog$1<SchemaDefinition, infer TCatalog> ? TCatalog extends {
722
+ actions: infer Acts;
723
+ } ? Acts : never : never;
724
+ /**
725
+ * Infer component props from a catalog by component name
726
+ * @example type ButtonProps = InferComponentProps<typeof myCatalog, 'Button'>;
727
+ */
728
+ type InferComponentProps<C extends Catalog$1, K extends keyof InferCatalogComponents<C>> = InferCatalogComponents<C>[K] extends {
729
+ props: z.ZodType<infer P>;
730
+ } ? P : never;
731
+ /**
732
+ * Infer action params from a catalog by action name
733
+ * @example type ViewCustomersParams = InferActionParams<typeof myCatalog, 'viewCustomers'>;
734
+ */
735
+ type InferActionParams<C extends Catalog$1, K extends keyof InferCatalogActions<C>> = InferCatalogActions<C>[K] extends {
736
+ params: z.ZodType<infer P>;
737
+ } ? P : never;
738
+ type InferCatalogInput<T> = T extends SchemaType<"object", infer Shape> ? {
739
+ [K in keyof Shape]: InferCatalogField<Shape[K]>;
740
+ } : never;
741
+ type InferCatalogField<T> = T extends SchemaType<"map", infer EntryShape> ? Record<string, InferMapEntryRequired<EntryShape> & Partial<InferMapEntryOptional<EntryShape>>> : T extends SchemaType<"zod"> ? z.ZodType : T extends SchemaType<"string"> ? string : T extends SchemaType<"number"> ? number : T extends SchemaType<"boolean"> ? boolean : T extends SchemaType<"array", infer Item> ? InferCatalogField<Item>[] : T extends SchemaType<"object", infer Shape> ? {
742
+ [K in keyof Shape]: InferCatalogField<Shape[K]>;
743
+ } : unknown;
744
+ type InferMapEntryRequired<T> = {
745
+ [K in keyof T as K extends "props" ? K : never]: InferMapEntryField<T[K]>;
746
+ };
747
+ type InferMapEntryOptional<T> = {
748
+ [K in keyof T as K extends "props" ? never : K]: InferMapEntryField<T[K]>;
749
+ };
750
+ type InferMapEntryField<T> = T extends SchemaType<"zod"> ? z.ZodType : T extends SchemaType<"string"> ? string : T extends SchemaType<"number"> ? number : T extends SchemaType<"boolean"> ? boolean : T extends SchemaType<"array", infer Item> ? InferMapEntryField<Item>[] : T extends SchemaType<"object", infer Shape> ? {
751
+ [K in keyof Shape]: InferMapEntryField<Shape[K]>;
752
+ } : unknown;
753
+ type InferSpec<TDef extends SchemaDefinition, TCatalog> = TDef extends {
754
+ spec: SchemaType<"object", infer Shape>;
755
+ } ? InferSpecObject<Shape, TCatalog> : unknown;
756
+ type InferSpecObject<Shape, TCatalog> = {
757
+ [K in keyof Shape]: InferSpecField<Shape[K], TCatalog>;
758
+ };
759
+ type InferSpecField<T, TCatalog> = T extends SchemaType<"string"> ? string : T extends SchemaType<"number"> ? number : T extends SchemaType<"boolean"> ? boolean : T extends SchemaType<"array", infer Item> ? InferSpecField<Item, TCatalog>[] : T extends SchemaType<"object", infer Shape> ? InferSpecObject<Shape, TCatalog> : T extends SchemaType<"record", infer Value> ? Record<string, InferSpecField<Value, TCatalog>> : T extends SchemaType<"ref", infer Path> ? InferRefType<Path, TCatalog> : T extends SchemaType<"propsOf", infer Path> ? InferPropsOfType<Path, TCatalog> : T extends SchemaType<"any"> ? unknown : unknown;
760
+ type InferRefType<Path, TCatalog> = Path extends "catalog.components" ? TCatalog extends {
761
+ components: infer C;
762
+ } ? keyof C : string : Path extends "catalog.actions" ? TCatalog extends {
763
+ actions: infer A;
764
+ } ? keyof A : string : string;
765
+ type InferPropsOfType<Path, TCatalog> = Path extends "catalog.components" ? TCatalog extends {
766
+ components: infer C;
767
+ } ? C extends Record<string, {
768
+ props: z.ZodType<infer P>;
769
+ }> ? P : Record<string, unknown> : Record<string, unknown> : Record<string, unknown>;
770
+ /**
771
+ * Define a schema using the builder pattern
772
+ */
773
+ declare function defineSchema<TDef extends SchemaDefinition>(builder: (s: SchemaBuilder) => TDef, options?: SchemaOptions): Schema<TDef>;
774
+ /**
775
+ * Shorthand: Define a catalog directly from a schema
776
+ */
777
+ declare function defineCatalog<TDef extends SchemaDefinition, TCatalog extends InferCatalogInput<TDef["catalog"]>>(schema: Schema<TDef>, catalog: TCatalog): Catalog$1<TDef, TCatalog>;
778
+
488
779
  /**
489
780
  * Component definition with visibility and validation support
490
781
  */
@@ -533,8 +824,8 @@ interface Catalog<TComponents extends Record<string, ComponentDefinition> = Reco
533
824
  readonly functions: TFunctions;
534
825
  /** Full element schema for AI generation */
535
826
  readonly elementSchema: z.ZodType<UIElement>;
536
- /** Full UI tree schema */
537
- readonly treeSchema: z.ZodType<UITree>;
827
+ /** Full UI spec schema */
828
+ readonly specSchema: z.ZodType<Spec>;
538
829
  /** Check if component exists */
539
830
  hasComponent(type: string): boolean;
540
831
  /** Check if action exists */
@@ -547,10 +838,10 @@ interface Catalog<TComponents extends Record<string, ComponentDefinition> = Reco
547
838
  data?: UIElement;
548
839
  error?: z.ZodError;
549
840
  };
550
- /** Validate a UI tree */
551
- validateTree(tree: unknown): {
841
+ /** Validate a UI spec */
842
+ validateSpec(spec: unknown): {
552
843
  success: boolean;
553
- data?: UITree;
844
+ data?: Spec;
554
845
  error?: z.ZodError;
555
846
  };
556
847
  }
@@ -568,5 +859,19 @@ declare function generateCatalogPrompt<TComponents extends Record<string, Compon
568
859
  type InferCatalogComponentProps<C extends Catalog<Record<string, ComponentDefinition>>> = {
569
860
  [K in keyof C["components"]]: z.infer<C["components"][K]["props"]>;
570
861
  };
862
+ /**
863
+ * Options for generating system prompts
864
+ */
865
+ interface SystemPromptOptions {
866
+ /** System message intro (replaces default) */
867
+ system?: string;
868
+ /** Additional rules to append to the rules section */
869
+ customRules?: string[];
870
+ }
871
+ /**
872
+ * Generate a complete system prompt for AI that can generate UI from a catalog.
873
+ * This produces a ready-to-use prompt that stays in sync with the catalog definition.
874
+ */
875
+ declare function generateSystemPrompt<TComponents extends Record<string, ComponentDefinition>, TActions extends Record<string, ActionDefinition>, TFunctions extends Record<string, ValidationFunction>>(catalog: Catalog<TComponents, TActions, TFunctions>, options?: SystemPromptOptions): string;
571
876
 
572
- export { type Action, type ActionConfirm, ActionConfirmSchema, type ActionDefinition, type ActionExecutionContext, type ActionHandler, type ActionOnError, ActionOnErrorSchema, type ActionOnSuccess, ActionOnSuccessSchema, ActionSchema, type AuthState, type Catalog, type CatalogConfig, type ComponentDefinition, type ComponentSchema, type DataModel, type DynamicBoolean, DynamicBooleanSchema, type DynamicNumber, DynamicNumberSchema, type DynamicString, DynamicStringSchema, type DynamicValue, DynamicValueSchema, type InferCatalogComponentProps, type JsonPatch, type LogicExpression, LogicExpressionSchema, type PatchOp, type ResolvedAction, type UIElement, type UITree, type ValidationCheck, type ValidationCheckResult, ValidationCheckSchema, type ValidationConfig, ValidationConfigSchema, type ValidationContext, type ValidationFunction, type ValidationFunctionDefinition, type ValidationMode, type ValidationResult, type VisibilityCondition, VisibilityConditionSchema, type VisibilityContext, action, builtInValidationFunctions, check, createCatalog, evaluateLogicExpression, evaluateVisibility, executeAction, generateCatalogPrompt, getByPath, interpolateString, resolveAction, resolveDynamicValue, runValidation, runValidationCheck, setByPath, visibility };
877
+ export { type Action, type ActionConfirm, ActionConfirmSchema, type ActionDefinition, type ActionExecutionContext, type ActionHandler, type ActionOnError, ActionOnErrorSchema, type ActionOnSuccess, ActionOnSuccessSchema, ActionSchema, type AuthState, type Catalog$1 as Catalog, type CatalogConfig, type ComponentDefinition, type ComponentSchema, type DataModel, type DynamicBoolean, DynamicBooleanSchema, type DynamicNumber, DynamicNumberSchema, type DynamicString, DynamicStringSchema, type DynamicValue, DynamicValueSchema, type InferActionParams, type InferCatalogActions, type InferCatalogComponentProps, type InferCatalogComponents, type InferCatalogInput, type InferComponentProps, type InferSpec, type JsonPatch, type Catalog as LegacyCatalog, type LogicExpression, LogicExpressionSchema, type PatchOp, type PromptContext, type PromptOptions, type PromptTemplate, type ResolvedAction, type Schema, type SchemaBuilder, type SchemaDefinition, type SchemaOptions, type SchemaType, type Spec, type SpecStreamCompiler, type SpecStreamLine, type SpecValidationResult, type SystemPromptOptions, type UIElement, type ValidationCheck, type ValidationCheckResult, ValidationCheckSchema, type ValidationConfig, ValidationConfigSchema, type ValidationContext, type ValidationFunction, type ValidationFunctionDefinition, type ValidationMode, type ValidationResult, type VisibilityCondition, VisibilityConditionSchema, type VisibilityContext, action, applySpecStreamPatch, builtInValidationFunctions, check, compileSpecStream, createCatalog, createSpecStreamCompiler, defineCatalog, defineSchema, evaluateLogicExpression, evaluateVisibility, executeAction, findFormValue, generateCatalogPrompt, generateSystemPrompt, getByPath, interpolateString, parseSpecStreamLine, resolveAction, resolveDynamicValue, runValidation, runValidationCheck, setByPath, visibility };