@procedures/splay 0.0.0-stage → 0.1.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/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +408 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/components/define.d.ts +134 -0
- package/dist/components/define.d.ts.map +1 -0
- package/dist/components/define.js +486 -0
- package/dist/components/define.js.map +1 -0
- package/dist/components/index.d.ts +39 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +38 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/types.d.ts +264 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +46 -0
- package/dist/components/types.js.map +1 -0
- package/dist/hydrate.d.ts +126 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +226 -0
- package/dist/hydrate.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +16 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +58 -0
- package/dist/module.js.map +1 -0
- package/dist/register.d.ts +8 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +15 -0
- package/dist/register.js.map +1 -0
- package/dist/registry.d.ts +60 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +191 -0
- package/dist/registry.js.map +1 -0
- package/dist/streaming.d.ts +94 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +422 -0
- package/dist/streaming.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +73 -3
- package/src/components/define.ts +600 -0
- package/src/components/index.ts +78 -0
- package/src/components/types.ts +357 -0
- package/src/hydrate.ts +355 -0
- package/src/index.ts +111 -0
- package/src/module.ts +81 -0
- package/src/register.ts +18 -0
- package/src/registry.ts +257 -0
- package/src/streaming.ts +554 -0
- package/src/types.ts +114 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Types
|
|
3
|
+
*
|
|
4
|
+
* Components are procedures that return serializable UI descriptors.
|
|
5
|
+
* This enables SSR, caching, and transport over wire.
|
|
6
|
+
*
|
|
7
|
+
* Components integrate with splay's rendering model where a renderer
|
|
8
|
+
* produces output based on data, size, and path context.
|
|
9
|
+
*/
|
|
10
|
+
import type { ZodLike } from "@procedures/client/client";
|
|
11
|
+
import type { ProcedureMetadata, ProcedurePath } from "@procedures/client";
|
|
12
|
+
import type { IEventBus as EventBus } from "@procedures/client";
|
|
13
|
+
/**
|
|
14
|
+
* Serializable component output descriptor.
|
|
15
|
+
* Can be transported over wire, cached, and hydrated by any framework.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const descriptor: ComponentOutput = {
|
|
20
|
+
* type: "user-card",
|
|
21
|
+
* props: {
|
|
22
|
+
* name: "John Doe",
|
|
23
|
+
* avatar: "/images/john.png",
|
|
24
|
+
* },
|
|
25
|
+
* children: [
|
|
26
|
+
* { type: "badge", props: { label: "Admin" } },
|
|
27
|
+
* ],
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export interface ComponentOutput {
|
|
32
|
+
/** Component type identifier (maps to registered component) */
|
|
33
|
+
type: string;
|
|
34
|
+
/** Serializable props for the component */
|
|
35
|
+
props: Record<string, unknown>;
|
|
36
|
+
/** Nested child descriptors (optional) */
|
|
37
|
+
children?: ComponentOutput[];
|
|
38
|
+
/** Component key for reconciliation (optional) */
|
|
39
|
+
key?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Fragment output - multiple components without wrapper.
|
|
43
|
+
*/
|
|
44
|
+
export interface FragmentOutput {
|
|
45
|
+
type: "__fragment__";
|
|
46
|
+
children: ComponentOutput[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Null output - render nothing.
|
|
50
|
+
*/
|
|
51
|
+
export interface NullOutput {
|
|
52
|
+
type: "__null__";
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Any valid component output.
|
|
56
|
+
*/
|
|
57
|
+
export type AnyComponentOutput = ComponentOutput | FragmentOutput | NullOutput;
|
|
58
|
+
/**
|
|
59
|
+
* Size information for responsive rendering.
|
|
60
|
+
*/
|
|
61
|
+
export interface Size {
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Context passed to component factories.
|
|
67
|
+
* Compatible with splay's RenderContext.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* factory: (ctx) => ({
|
|
72
|
+
* type: "user-card",
|
|
73
|
+
* props: {
|
|
74
|
+
* user: ctx.data,
|
|
75
|
+
* compact: ctx.size.width < 400,
|
|
76
|
+
* },
|
|
77
|
+
* children: ctx.data.posts?.map((post, i) =>
|
|
78
|
+
* ctx.render(post, ctx.size, `${ctx.path}.posts[${i}]`)
|
|
79
|
+
* ),
|
|
80
|
+
* })
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export interface ComponentContext<TData = unknown> {
|
|
84
|
+
/** Input data for the component */
|
|
85
|
+
data: TData;
|
|
86
|
+
/** Available rendering size */
|
|
87
|
+
size: Size;
|
|
88
|
+
/** Path in the render tree (for debugging and keys) */
|
|
89
|
+
path: string;
|
|
90
|
+
/** Current depth in the render tree */
|
|
91
|
+
depth: number;
|
|
92
|
+
/**
|
|
93
|
+
* Render a child component.
|
|
94
|
+
* Delegates to the renderer to produce a ComponentOutput.
|
|
95
|
+
*
|
|
96
|
+
* @param data - Data for the child component
|
|
97
|
+
* @param size - Size available for the child
|
|
98
|
+
* @param path - Path for the child (for keys and debugging)
|
|
99
|
+
* @returns ComponentOutput from the child render
|
|
100
|
+
*/
|
|
101
|
+
render: (data: unknown, size: Size, path: string) => ComponentOutput | Promise<ComponentOutput>;
|
|
102
|
+
/**
|
|
103
|
+
* Event bus for streaming coordination.
|
|
104
|
+
* Available when executing in a procedure context.
|
|
105
|
+
*/
|
|
106
|
+
bus?: EventBus;
|
|
107
|
+
/**
|
|
108
|
+
* Additional metadata from the procedure context.
|
|
109
|
+
*/
|
|
110
|
+
metadata?: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Component factory function (single output).
|
|
114
|
+
* Returns a serializable component descriptor.
|
|
115
|
+
*/
|
|
116
|
+
export type ComponentFactory<TData = unknown> = (ctx: ComponentContext<TData>) => ComponentOutput | Promise<ComponentOutput>;
|
|
117
|
+
/**
|
|
118
|
+
* Streaming component factory (multi-yield).
|
|
119
|
+
* Yields descriptors over time for live updates.
|
|
120
|
+
*/
|
|
121
|
+
export type StreamingComponentFactory<TData = unknown> = (ctx: ComponentContext<TData>) => AsyncGenerator<ComponentOutput, void, unknown>;
|
|
122
|
+
/**
|
|
123
|
+
* Any component factory (single or streaming).
|
|
124
|
+
*/
|
|
125
|
+
export type AnyComponentFactory<TData = unknown> = ComponentFactory<TData> | StreamingComponentFactory<TData>;
|
|
126
|
+
/**
|
|
127
|
+
* Component metadata (extends ProcedureMetadata).
|
|
128
|
+
*/
|
|
129
|
+
export interface ComponentMetadata extends ProcedureMetadata {
|
|
130
|
+
/** Component category for organization */
|
|
131
|
+
category?: string;
|
|
132
|
+
/** Whether the component supports streaming updates */
|
|
133
|
+
streaming?: boolean;
|
|
134
|
+
/** Default size constraints */
|
|
135
|
+
defaultSize?: Size;
|
|
136
|
+
/** Minimum size constraints */
|
|
137
|
+
minSize?: Size;
|
|
138
|
+
/** Maximum size constraints */
|
|
139
|
+
maxSize?: Size;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Component definition.
|
|
143
|
+
* Wraps a factory function with type information and metadata.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const userCard: ComponentDefinition<User> = {
|
|
148
|
+
* type: "user-card",
|
|
149
|
+
* namespace: "ui",
|
|
150
|
+
* input: userSchema,
|
|
151
|
+
* metadata: {
|
|
152
|
+
* description: "Displays user information",
|
|
153
|
+
* category: "profile",
|
|
154
|
+
* },
|
|
155
|
+
* factory: (ctx) => ({
|
|
156
|
+
* type: "user-card",
|
|
157
|
+
* props: { user: ctx.data },
|
|
158
|
+
* }),
|
|
159
|
+
* };
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export interface ComponentDefinition<TData = unknown> {
|
|
163
|
+
/** Component type identifier */
|
|
164
|
+
type: string;
|
|
165
|
+
/**
|
|
166
|
+
* Namespace for the component (optional).
|
|
167
|
+
* Results in path: ["components", namespace, type]
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* namespace: "ui" → ["components", "ui", "user-card"]
|
|
171
|
+
*/
|
|
172
|
+
namespace?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Input schema for validating component data.
|
|
175
|
+
* Optional - if not provided, accepts any data.
|
|
176
|
+
*/
|
|
177
|
+
input?: ZodLike<TData>;
|
|
178
|
+
/**
|
|
179
|
+
* Component metadata for documentation and tooling.
|
|
180
|
+
*/
|
|
181
|
+
metadata?: ComponentMetadata;
|
|
182
|
+
/**
|
|
183
|
+
* Whether this component streams updates.
|
|
184
|
+
* When true, factory is expected to be a generator.
|
|
185
|
+
*/
|
|
186
|
+
streaming?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Component factory function.
|
|
189
|
+
* Can be a regular function (single output) or generator (streaming).
|
|
190
|
+
*/
|
|
191
|
+
factory: AnyComponentFactory<TData>;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Any component definition (type-erased for storage).
|
|
195
|
+
*/
|
|
196
|
+
export type AnyComponentDefinition = ComponentDefinition<unknown>;
|
|
197
|
+
/**
|
|
198
|
+
* Registered component with resolved path.
|
|
199
|
+
*/
|
|
200
|
+
export interface RegisteredComponent<TData = unknown> {
|
|
201
|
+
/** Full procedure path */
|
|
202
|
+
path: ProcedurePath;
|
|
203
|
+
/** Original component definition */
|
|
204
|
+
definition: ComponentDefinition<TData>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Component bundle - collection of components with shared namespace.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const uiComponents: ComponentBundle = {
|
|
212
|
+
* namespace: "ui",
|
|
213
|
+
* components: [
|
|
214
|
+
* buttonComponent,
|
|
215
|
+
* cardComponent,
|
|
216
|
+
* modalComponent,
|
|
217
|
+
* ],
|
|
218
|
+
* };
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export interface ComponentBundle {
|
|
222
|
+
/** Shared namespace for all components in bundle */
|
|
223
|
+
namespace: string;
|
|
224
|
+
/** Component definitions */
|
|
225
|
+
components: AnyComponentDefinition[];
|
|
226
|
+
/** Bundle metadata */
|
|
227
|
+
metadata?: {
|
|
228
|
+
/** Bundle name */
|
|
229
|
+
name?: string;
|
|
230
|
+
/** Bundle description */
|
|
231
|
+
description?: string;
|
|
232
|
+
/** Bundle version */
|
|
233
|
+
version?: string;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Infer input type from a component definition.
|
|
238
|
+
*/
|
|
239
|
+
export type InferComponentInput<T> = T extends ComponentDefinition<infer TData> ? TData : unknown;
|
|
240
|
+
/**
|
|
241
|
+
* Infer whether a component is streaming.
|
|
242
|
+
*/
|
|
243
|
+
export type IsStreamingComponent<T> = T extends ComponentDefinition<unknown> ? T["streaming"] extends true ? true : false : false;
|
|
244
|
+
/**
|
|
245
|
+
* Create a null output (render nothing).
|
|
246
|
+
*/
|
|
247
|
+
export declare function nullOutput(): NullOutput;
|
|
248
|
+
/**
|
|
249
|
+
* Create a fragment output (multiple children without wrapper).
|
|
250
|
+
*/
|
|
251
|
+
export declare function fragment(...children: ComponentOutput[]): FragmentOutput;
|
|
252
|
+
/**
|
|
253
|
+
* Check if output is a fragment.
|
|
254
|
+
*/
|
|
255
|
+
export declare function isFragment(output: AnyComponentOutput): output is FragmentOutput;
|
|
256
|
+
/**
|
|
257
|
+
* Check if output is null.
|
|
258
|
+
*/
|
|
259
|
+
export declare function isNullOutput(output: AnyComponentOutput): output is NullOutput;
|
|
260
|
+
/**
|
|
261
|
+
* Check if a factory is a streaming generator.
|
|
262
|
+
*/
|
|
263
|
+
export declare function isStreamingFactory<TData>(factory: AnyComponentFactory<TData>): factory is StreamingComponentFactory<TData>;
|
|
264
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Types
|
|
3
|
+
*
|
|
4
|
+
* Components are procedures that return serializable UI descriptors.
|
|
5
|
+
* This enables SSR, caching, and transport over wire.
|
|
6
|
+
*
|
|
7
|
+
* Components integrate with splay's rendering model where a renderer
|
|
8
|
+
* produces output based on data, size, and path context.
|
|
9
|
+
*/
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Output Helpers
|
|
12
|
+
// =============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Create a null output (render nothing).
|
|
15
|
+
*/
|
|
16
|
+
export function nullOutput() {
|
|
17
|
+
return { type: "__null__" };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a fragment output (multiple children without wrapper).
|
|
21
|
+
*/
|
|
22
|
+
export function fragment(...children) {
|
|
23
|
+
return { type: "__fragment__", children };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if output is a fragment.
|
|
27
|
+
*/
|
|
28
|
+
export function isFragment(output) {
|
|
29
|
+
return output.type === "__fragment__";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if output is null.
|
|
33
|
+
*/
|
|
34
|
+
export function isNullOutput(output) {
|
|
35
|
+
return output.type === "__null__";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a factory is a streaming generator.
|
|
39
|
+
*/
|
|
40
|
+
export function isStreamingFactory(factory) {
|
|
41
|
+
// The tag of the prototype, not `constructor.name`: an own `constructor` property, or a
|
|
42
|
+
// bundler that renames classes, does not change it. A plain function that returns a
|
|
43
|
+
// generator is not detected here: the handler of a component streams its result anyway.
|
|
44
|
+
return Object.prototype.toString.call(factory) === "[object AsyncGeneratorFunction]";
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkTH,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAG,QAA2B;IACrD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAA0B;IACnD,OAAO,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAA0B;IACrD,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAmC;IAEnC,wFAAwF;IACxF,oFAAoF;IACpF,wFAAwF;IACxF,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,iCAAiC,CAAC;AACvF,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydration
|
|
3
|
+
*
|
|
4
|
+
* Converts serializable ComponentOutput descriptors into framework-specific
|
|
5
|
+
* components (React, Vue, Svelte, etc.).
|
|
6
|
+
*
|
|
7
|
+
* This enables the following flow:
|
|
8
|
+
* 1. Server renders ComponentOutput (serializable)
|
|
9
|
+
* 2. Output is sent over wire (JSON)
|
|
10
|
+
* 3. Client hydrates to React/Vue/Svelte components
|
|
11
|
+
*/
|
|
12
|
+
import type { ComponentOutput } from "./components/index.js";
|
|
13
|
+
import type { ComponentMap, HydrateOptions } from "./types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Create a hydrate function for a specific framework.
|
|
16
|
+
*
|
|
17
|
+
* @param options - Hydration options including component map
|
|
18
|
+
* @returns Hydrate function that converts descriptors to framework components
|
|
19
|
+
*
|
|
20
|
+
* @example React:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { createElement } from "react";
|
|
23
|
+
* import { createHydrate } from "@procedures/splay";
|
|
24
|
+
*
|
|
25
|
+
* const hydrate = createHydrate({
|
|
26
|
+
* components: {
|
|
27
|
+
* "user-card": UserCard,
|
|
28
|
+
* "badge": Badge,
|
|
29
|
+
* },
|
|
30
|
+
* fallback: UnknownComponent,
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Use with React
|
|
34
|
+
* function App({ descriptor }) {
|
|
35
|
+
* return hydrate(descriptor, createElement);
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function createHydrate<TComponent>(options: HydrateOptions<TComponent>): (descriptor: ComponentOutput | null, createElement: CreateElement<TComponent>) => TComponent | null;
|
|
40
|
+
/**
|
|
41
|
+
* createElement function signature (React-compatible).
|
|
42
|
+
*/
|
|
43
|
+
export type CreateElement<TComponent> = (type: TComponent, props: Record<string, unknown> | null, children?: (TComponent | null)[]) => TComponent;
|
|
44
|
+
/**
|
|
45
|
+
* Generic React-like component type (works with any framework that has createElement).
|
|
46
|
+
*/
|
|
47
|
+
type ReactLikeComponent = (props: Record<string, unknown>) => unknown;
|
|
48
|
+
/**
|
|
49
|
+
* React-specific hydration options.
|
|
50
|
+
*/
|
|
51
|
+
export interface ReactHydrateOptions {
|
|
52
|
+
/** Map of component types to React components */
|
|
53
|
+
components: ComponentMap<ReactLikeComponent>;
|
|
54
|
+
/** Fallback component for unknown types */
|
|
55
|
+
fallback?: ReactLikeComponent;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* React-like module interface.
|
|
59
|
+
*/
|
|
60
|
+
interface ReactLike {
|
|
61
|
+
createElement(type: ReactLikeComponent | symbol, props: Record<string, unknown> | null, ...children: unknown[]): unknown;
|
|
62
|
+
Fragment: symbol;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a React-specific hydrate function.
|
|
66
|
+
*
|
|
67
|
+
* @param react - React module (import * as React from "react")
|
|
68
|
+
* @param options - Hydration options
|
|
69
|
+
* @returns Hydrate function for React
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import * as React from "react";
|
|
74
|
+
* import { createReactHydrate } from "@procedures/splay";
|
|
75
|
+
*
|
|
76
|
+
* const hydrate = createReactHydrate(React, {
|
|
77
|
+
* components: {
|
|
78
|
+
* "user-card": UserCard,
|
|
79
|
+
* "badge": Badge,
|
|
80
|
+
* },
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* function App({ descriptor }) {
|
|
84
|
+
* return hydrate(descriptor);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function createReactHydrate(react: ReactLike, options: ReactHydrateOptions): (descriptor: ComponentOutput | null) => unknown;
|
|
89
|
+
/**
|
|
90
|
+
* Walk a descriptor tree and apply a visitor to each node.
|
|
91
|
+
*/
|
|
92
|
+
export declare function walkDescriptor(descriptor: ComponentOutput, visitor: (node: ComponentOutput, path: string[]) => void, path?: string[]): void;
|
|
93
|
+
/**
|
|
94
|
+
* Transform a descriptor tree.
|
|
95
|
+
*/
|
|
96
|
+
export declare function transformDescriptor(descriptor: ComponentOutput, transform: (node: ComponentOutput) => ComponentOutput): ComponentOutput;
|
|
97
|
+
/**
|
|
98
|
+
* Find all nodes in a descriptor tree matching a predicate.
|
|
99
|
+
*/
|
|
100
|
+
export declare function findInDescriptor(descriptor: ComponentOutput, predicate: (node: ComponentOutput) => boolean): ComponentOutput[];
|
|
101
|
+
/**
|
|
102
|
+
* Get all component types used in a descriptor tree.
|
|
103
|
+
*/
|
|
104
|
+
export declare function getUsedTypes(descriptor: ComponentOutput): Set<string>;
|
|
105
|
+
/**
|
|
106
|
+
* Validate that all component types in a descriptor are known.
|
|
107
|
+
*/
|
|
108
|
+
export declare function validateDescriptor(descriptor: ComponentOutput, knownTypes: Set<string> | string[]): {
|
|
109
|
+
valid: boolean;
|
|
110
|
+
unknownTypes: string[];
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Serialize a descriptor to JSON string.
|
|
114
|
+
*/
|
|
115
|
+
export declare function serializeDescriptor(descriptor: ComponentOutput): string;
|
|
116
|
+
/**
|
|
117
|
+
* Parse a descriptor from JSON string.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseDescriptor(json: string): ComponentOutput;
|
|
120
|
+
/**
|
|
121
|
+
* Create a compact representation of a descriptor.
|
|
122
|
+
* Removes undefined values and empty arrays.
|
|
123
|
+
*/
|
|
124
|
+
export declare function compactDescriptor(descriptor: ComponentOutput): ComponentOutput;
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=hydrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAc/D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,UAAU,EACtC,OAAO,EAAE,cAAc,CAAC,UAAU,CAAC,GAClC,CACD,UAAU,EAAE,eAAe,GAAG,IAAI,EAClC,aAAa,EAAE,aAAa,CAAC,UAAU,CAAC,KACrC,UAAU,GAAG,IAAI,CAmDrB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,UAAU,IAAI,CACtC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACrC,QAAQ,CAAC,EAAE,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,KAC7B,UAAU,CAAC;AAMhB;;GAEG;AACH,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,UAAU,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAC7C,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;GAEG;AACH,UAAU,SAAS;IACjB,aAAa,CACX,IAAI,EAAE,kBAAkB,GAAG,MAAM,EACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACrC,GAAG,QAAQ,EAAE,OAAO,EAAE,GACrB,OAAO,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,mBAAmB,GAC3B,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,KAAK,OAAO,CAwCjD;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,EACxD,IAAI,GAAE,MAAM,EAAO,GAClB,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,eAAe,GACpD,eAAe,CAajB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,GAC5C,eAAe,EAAE,CAUnB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC,CAUrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,eAAe,EAC3B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,GACjC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAe5C;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAE7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,eAAe,GAAG,eAAe,CAe9E"}
|
package/dist/hydrate.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydration
|
|
3
|
+
*
|
|
4
|
+
* Converts serializable ComponentOutput descriptors into framework-specific
|
|
5
|
+
* components (React, Vue, Svelte, etc.).
|
|
6
|
+
*
|
|
7
|
+
* This enables the following flow:
|
|
8
|
+
* 1. Server renders ComponentOutput (serializable)
|
|
9
|
+
* 2. Output is sent over wire (JSON)
|
|
10
|
+
* 3. Client hydrates to React/Vue/Svelte components
|
|
11
|
+
*/
|
|
12
|
+
const log = globalThis.console;
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Hydration Core
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Create a hydrate function for a specific framework.
|
|
18
|
+
*
|
|
19
|
+
* @param options - Hydration options including component map
|
|
20
|
+
* @returns Hydrate function that converts descriptors to framework components
|
|
21
|
+
*
|
|
22
|
+
* @example React:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { createElement } from "react";
|
|
25
|
+
* import { createHydrate } from "@procedures/splay";
|
|
26
|
+
*
|
|
27
|
+
* const hydrate = createHydrate({
|
|
28
|
+
* components: {
|
|
29
|
+
* "user-card": UserCard,
|
|
30
|
+
* "badge": Badge,
|
|
31
|
+
* },
|
|
32
|
+
* fallback: UnknownComponent,
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Use with React
|
|
36
|
+
* function App({ descriptor }) {
|
|
37
|
+
* return hydrate(descriptor, createElement);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function createHydrate(options) {
|
|
42
|
+
const { components, fallback, onNull, onFragment } = options;
|
|
43
|
+
return function hydrate(descriptor, createElement) {
|
|
44
|
+
// Handle null
|
|
45
|
+
if (descriptor === null) {
|
|
46
|
+
return onNull?.() ?? null;
|
|
47
|
+
}
|
|
48
|
+
// Handle null output type
|
|
49
|
+
if (descriptor.type === "__null__") {
|
|
50
|
+
return onNull?.() ?? null;
|
|
51
|
+
}
|
|
52
|
+
// Handle fragment
|
|
53
|
+
if (descriptor.type === "__fragment__") {
|
|
54
|
+
const children = (descriptor.children ?? []).map((child) => hydrate(child, createElement));
|
|
55
|
+
if (onFragment) {
|
|
56
|
+
return onFragment(children.filter((c) => c !== null));
|
|
57
|
+
}
|
|
58
|
+
// Default: return first child or null
|
|
59
|
+
return children[0] ?? null;
|
|
60
|
+
}
|
|
61
|
+
// Look up component
|
|
62
|
+
const Component = components[descriptor.type] ?? fallback;
|
|
63
|
+
if (!Component) {
|
|
64
|
+
log.warn(`Unknown component type: ${descriptor.type}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
// Hydrate children recursively
|
|
68
|
+
const hydratedChildren = descriptor.children?.map((child) => hydrate(child, createElement));
|
|
69
|
+
// Create the component
|
|
70
|
+
return createElement(Component, { ...descriptor.props, key: descriptor.key }, hydratedChildren);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a React-specific hydrate function.
|
|
75
|
+
*
|
|
76
|
+
* @param react - React module (import * as React from "react")
|
|
77
|
+
* @param options - Hydration options
|
|
78
|
+
* @returns Hydrate function for React
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* import * as React from "react";
|
|
83
|
+
* import { createReactHydrate } from "@procedures/splay";
|
|
84
|
+
*
|
|
85
|
+
* const hydrate = createReactHydrate(React, {
|
|
86
|
+
* components: {
|
|
87
|
+
* "user-card": UserCard,
|
|
88
|
+
* "badge": Badge,
|
|
89
|
+
* },
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* function App({ descriptor }) {
|
|
93
|
+
* return hydrate(descriptor);
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function createReactHydrate(react, options) {
|
|
98
|
+
const { components, fallback } = options;
|
|
99
|
+
function hydrate(descriptor) {
|
|
100
|
+
if (descriptor === null) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (descriptor.type === "__null__") {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
if (descriptor.type === "__fragment__") {
|
|
107
|
+
const children = (descriptor.children ?? []).map((child) => hydrate(child));
|
|
108
|
+
return react.createElement(react.Fragment, null, ...children);
|
|
109
|
+
}
|
|
110
|
+
const Component = components[descriptor.type];
|
|
111
|
+
if (!Component) {
|
|
112
|
+
if (fallback) {
|
|
113
|
+
return react.createElement(fallback, {
|
|
114
|
+
type: descriptor.type,
|
|
115
|
+
props: descriptor.props,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
log.warn(`Unknown component type: ${descriptor.type}`);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const hydratedChildren = descriptor.children?.map((child) => hydrate(child));
|
|
122
|
+
return react.createElement(Component, { ...descriptor.props, key: descriptor.key }, ...(hydratedChildren ?? []));
|
|
123
|
+
}
|
|
124
|
+
return hydrate;
|
|
125
|
+
}
|
|
126
|
+
// =============================================================================
|
|
127
|
+
// Descriptor Utilities
|
|
128
|
+
// =============================================================================
|
|
129
|
+
/**
|
|
130
|
+
* Walk a descriptor tree and apply a visitor to each node.
|
|
131
|
+
*/
|
|
132
|
+
export function walkDescriptor(descriptor, visitor, path = []) {
|
|
133
|
+
visitor(descriptor, path);
|
|
134
|
+
if (descriptor.children) {
|
|
135
|
+
descriptor.children.forEach((child, index) => {
|
|
136
|
+
walkDescriptor(child, visitor, [...path, `children[${index}]`]);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Transform a descriptor tree.
|
|
142
|
+
*/
|
|
143
|
+
export function transformDescriptor(descriptor, transform) {
|
|
144
|
+
const transformed = transform(descriptor);
|
|
145
|
+
if (transformed.children) {
|
|
146
|
+
return {
|
|
147
|
+
...transformed,
|
|
148
|
+
children: transformed.children.map((child) => transformDescriptor(child, transform)),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return transformed;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find all nodes in a descriptor tree matching a predicate.
|
|
155
|
+
*/
|
|
156
|
+
export function findInDescriptor(descriptor, predicate) {
|
|
157
|
+
const results = [];
|
|
158
|
+
walkDescriptor(descriptor, (node) => {
|
|
159
|
+
if (predicate(node)) {
|
|
160
|
+
results.push(node);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return results;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get all component types used in a descriptor tree.
|
|
167
|
+
*/
|
|
168
|
+
export function getUsedTypes(descriptor) {
|
|
169
|
+
const types = new Set();
|
|
170
|
+
walkDescriptor(descriptor, (node) => {
|
|
171
|
+
if (node.type !== "__null__" && node.type !== "__fragment__") {
|
|
172
|
+
types.add(node.type);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return types;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Validate that all component types in a descriptor are known.
|
|
179
|
+
*/
|
|
180
|
+
export function validateDescriptor(descriptor, knownTypes) {
|
|
181
|
+
const known = knownTypes instanceof Set ? knownTypes : new Set(knownTypes);
|
|
182
|
+
const used = getUsedTypes(descriptor);
|
|
183
|
+
const unknownTypes = [];
|
|
184
|
+
for (const type of used) {
|
|
185
|
+
if (!known.has(type)) {
|
|
186
|
+
unknownTypes.push(type);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
valid: unknownTypes.length === 0,
|
|
191
|
+
unknownTypes,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// =============================================================================
|
|
195
|
+
// Serialization Helpers
|
|
196
|
+
// =============================================================================
|
|
197
|
+
/**
|
|
198
|
+
* Serialize a descriptor to JSON string.
|
|
199
|
+
*/
|
|
200
|
+
export function serializeDescriptor(descriptor) {
|
|
201
|
+
return JSON.stringify(descriptor);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Parse a descriptor from JSON string.
|
|
205
|
+
*/
|
|
206
|
+
export function parseDescriptor(json) {
|
|
207
|
+
return JSON.parse(json);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Create a compact representation of a descriptor.
|
|
211
|
+
* Removes undefined values and empty arrays.
|
|
212
|
+
*/
|
|
213
|
+
export function compactDescriptor(descriptor) {
|
|
214
|
+
const result = {
|
|
215
|
+
type: descriptor.type,
|
|
216
|
+
props: descriptor.props,
|
|
217
|
+
};
|
|
218
|
+
if (descriptor.children && descriptor.children.length > 0) {
|
|
219
|
+
result.children = descriptor.children.map(compactDescriptor);
|
|
220
|
+
}
|
|
221
|
+
if (descriptor.key !== undefined) {
|
|
222
|
+
result.key = descriptor.key;
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=hydrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"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"}
|