@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +408 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/components/define.d.ts +134 -0
  6. package/dist/components/define.d.ts.map +1 -0
  7. package/dist/components/define.js +486 -0
  8. package/dist/components/define.js.map +1 -0
  9. package/dist/components/index.d.ts +39 -0
  10. package/dist/components/index.d.ts.map +1 -0
  11. package/dist/components/index.js +38 -0
  12. package/dist/components/index.js.map +1 -0
  13. package/dist/components/types.d.ts +264 -0
  14. package/dist/components/types.d.ts.map +1 -0
  15. package/dist/components/types.js +46 -0
  16. package/dist/components/types.js.map +1 -0
  17. package/dist/hydrate.d.ts +126 -0
  18. package/dist/hydrate.d.ts.map +1 -0
  19. package/dist/hydrate.js +226 -0
  20. package/dist/hydrate.js.map +1 -0
  21. package/dist/index.d.ts +40 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +54 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/module.d.ts +16 -0
  26. package/dist/module.d.ts.map +1 -0
  27. package/dist/module.js +58 -0
  28. package/dist/module.js.map +1 -0
  29. package/dist/register.d.ts +8 -0
  30. package/dist/register.d.ts.map +1 -0
  31. package/dist/register.js +15 -0
  32. package/dist/register.js.map +1 -0
  33. package/dist/registry.d.ts +60 -0
  34. package/dist/registry.d.ts.map +1 -0
  35. package/dist/registry.js +191 -0
  36. package/dist/registry.js.map +1 -0
  37. package/dist/streaming.d.ts +94 -0
  38. package/dist/streaming.d.ts.map +1 -0
  39. package/dist/streaming.js +422 -0
  40. package/dist/streaming.js.map +1 -0
  41. package/dist/types.d.ts +85 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +7 -0
  44. package/dist/types.js.map +1 -0
  45. package/package.json +73 -3
  46. package/src/components/define.ts +600 -0
  47. package/src/components/index.ts +78 -0
  48. package/src/components/types.ts +357 -0
  49. package/src/hydrate.ts +355 -0
  50. package/src/index.ts +111 -0
  51. package/src/module.ts +81 -0
  52. package/src/register.ts +18 -0
  53. package/src/registry.ts +257 -0
  54. package/src/streaming.ts +554 -0
  55. package/src/types.ts +114 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @procedures/splay
2
+
3
+ ## 0.1.0
4
+
5
+ The first release on npm. The packages of the client monorepo have one version together.
6
+
7
+ - The procedure components moved here from `@procedures/client` (roadmap 3.4): `defineComponent`, `componentToProcedure`, `simpleComponent`, `namespacedComponent`, `streamingComponent`, the bundles and the output helpers. Import them from the root of this package.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Mark Russell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,409 @@
1
- # Temporary Holding Version
1
+ # @procedures/splay
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/@procedures/splay?color=2346c4&label=npm)](https://www.npmjs.com/package/@procedures/splay)
4
+
5
+ ```sh
6
+ npm install @procedures/splay
7
+ ```
8
+
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
11
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D25-green.svg)](https://nodejs.org/)
12
+
13
+ > Bridge between splay's rendering model and client's procedure system. Enables server-side component rendering via RPC.
14
+
15
+ ## Table of Contents
16
+
17
+ - [Overview](#overview)
18
+ - [Installation](#installation)
19
+ - [Architecture](#architecture)
20
+ - [Quick Start](#quick-start)
21
+ - [API Reference](#api-reference)
22
+ - [Registry](#registry)
23
+ - [Hydration](#hydration)
24
+ - [Descriptor Utilities](#descriptor-utilities)
25
+ - [Stream Utilities](#stream-utilities)
26
+ - [ComponentOutput Format](#componentoutput-format)
27
+ - [Integration](#integration)
28
+ - [Requirements](#requirements)
29
+ - [License](#license)
30
+
31
+ ---
32
+
33
+ ## Overview
34
+
35
+ **client-splay** bridges the splay rendering model with the RPC procedure system:
36
+
37
+ - **Client Registry** - Call component procedures via RPC
38
+ - **Streaming Registry** - Handle async component streams
39
+ - **Hydration** - Convert descriptors to framework elements (React, etc.)
40
+ - **Utilities** - Walk, transform, and validate descriptor trees
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ npm install github:mark1russell7/client-splay#main
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Architecture
53
+
54
+ ### System Overview
55
+
56
+ ```mermaid
57
+ graph TB
58
+ subgraph "Application"
59
+ App[Your Application]
60
+ end
61
+
62
+ subgraph "client-splay"
63
+ subgraph "Registry Layer"
64
+ ClientReg[ClientRegistry<br/>Sync calls]
65
+ StreamReg[StreamingRegistry<br/>Async iterables]
66
+ DualReg[DualRegistry<br/>Both modes]
67
+ end
68
+
69
+ subgraph "Hydration Layer"
70
+ Hydrate[createHydrate]
71
+ ReactHydrate[createReactHydrate]
72
+ end
73
+ end
74
+
75
+ subgraph "RPC Layer"
76
+ Client[client.call]
77
+ Stream[client.stream]
78
+ end
79
+
80
+ subgraph "Output"
81
+ Descriptor[ComponentOutput]
82
+ Element[React Element]
83
+ end
84
+
85
+ App --> ClientReg
86
+ App --> StreamReg
87
+ ClientReg --> Client
88
+ StreamReg --> Stream
89
+ Client --> Descriptor
90
+ Stream --> Descriptor
91
+ Descriptor --> Hydrate
92
+ Descriptor --> ReactHydrate
93
+ ReactHydrate --> Element
94
+ ```
95
+
96
+ ### Component Rendering Flow
97
+
98
+ ```mermaid
99
+ sequenceDiagram
100
+ participant App as Application
101
+ participant Reg as ClientRegistry
102
+ participant RPC as client.call
103
+ participant Server as Procedure Server
104
+ participant Hydrate as Hydrator
105
+
106
+ App->>Reg: registry.get("user-card")(ctx)
107
+ Reg->>RPC: call(["ui", "user-card"], input)
108
+ RPC->>Server: Execute procedure
109
+ Server-->>RPC: ComponentOutput
110
+ RPC-->>Reg: Descriptor
111
+ Reg-->>App: ComponentOutput
112
+
113
+ App->>Hydrate: hydrate(descriptor)
114
+ Hydrate->>Hydrate: Map to React components
115
+ Hydrate-->>App: React.Element
116
+ ```
117
+
118
+ ### Registry Types
119
+
120
+ ```mermaid
121
+ graph TB
122
+ subgraph "ClientRegistry"
123
+ CR[Sync calls]
124
+ CROut[Single ComponentOutput]
125
+ end
126
+
127
+ subgraph "StreamingRegistry"
128
+ SR[Async streams]
129
+ SROut[AsyncIterable of ComponentOutput]
130
+ end
131
+
132
+ subgraph "DualRegistry"
133
+ DR[Both modes]
134
+ DROut[Sync + Streaming]
135
+ end
136
+
137
+ CR --> CROut
138
+ SR --> SROut
139
+ DR --> DROut
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Quick Start
145
+
146
+ ```typescript
147
+ import { createClientRegistry, createReactHydrate } from "@procedures/splay";
148
+ import { call } from "client";
149
+
150
+ // 1. Create registry backed by client procedures
151
+ const registry = createClientRegistry(call, { namespace: "ui" });
152
+
153
+ // 2. Create hydrator for React
154
+ const hydrate = createReactHydrate(React, {
155
+ components: {
156
+ "user-card": UserCard,
157
+ "badge": Badge,
158
+ },
159
+ });
160
+
161
+ // 3. Render a component
162
+ const ctx = { data: { userId: 123 }, size: { width: 400, height: 300 } };
163
+ const descriptor = await registry.get("user-card")!(ctx);
164
+ const element = hydrate(descriptor);
165
+ ```
166
+
167
+ ---
168
+
169
+ ## API Reference
170
+
171
+ ### Registry
172
+
173
+ #### ClientRegistry
174
+
175
+ Sync registry for single-response component calls.
176
+
177
+ ```typescript
178
+ const registry = createClientRegistry(call, {
179
+ namespace?: string, // Procedure path prefix (e.g., "ui")
180
+ });
181
+
182
+ // Usage
183
+ const descriptor = await registry.get("user-card")!(ctx);
184
+ ```
185
+
186
+ #### StreamingRegistry
187
+
188
+ Streaming registry for multiple responses over time.
189
+
190
+ ```typescript
191
+ const streaming = createStreamingRegistry(stream, {
192
+ namespace?: string,
193
+ bufferSize?: number, // Default: 16
194
+ });
195
+
196
+ // Usage
197
+ for await (const descriptor of streaming.get("live-feed")!(ctx)) {
198
+ render(descriptor);
199
+ }
200
+ ```
201
+
202
+ #### DualRegistry
203
+
204
+ Combined registry supporting both sync and streaming.
205
+
206
+ ```typescript
207
+ const dual = createDualRegistry(call, stream, isStreaming, options);
208
+
209
+ // Automatically chooses based on component type
210
+ const result = await dual.get("component-name")!(ctx);
211
+ ```
212
+
213
+ ---
214
+
215
+ ### Hydration
216
+
217
+ #### createHydrate (Generic)
218
+
219
+ Framework-agnostic hydration.
220
+
221
+ ```typescript
222
+ const hydrate = createHydrate<TComponent>({
223
+ components: ComponentMap, // Map of type -> component
224
+ fallback?: Component, // For unknown types
225
+ onNull?: () => TComponent, // Handle null descriptors
226
+ onFragment?: (children) => TComponent, // Handle fragments
227
+ });
228
+ ```
229
+
230
+ #### createReactHydrate
231
+
232
+ React-specific hydration with createElement integration.
233
+
234
+ ```typescript
235
+ const hydrate = createReactHydrate(React, {
236
+ components: {
237
+ "user-card": UserCard,
238
+ "badge": Badge,
239
+ "button": Button,
240
+ },
241
+ fallback?: UnknownComponent,
242
+ });
243
+
244
+ // Usage
245
+ const element = hydrate(descriptor);
246
+ // Returns: React.Element
247
+ ```
248
+
249
+ ---
250
+
251
+ ### Descriptor Utilities
252
+
253
+ ```typescript
254
+ // Traverse descriptor tree
255
+ walkDescriptor(descriptor, (node, path) => {
256
+ console.log(`Node at ${path.join(".")}: ${node.type}`);
257
+ });
258
+
259
+ // Transform nodes
260
+ const transformed = transformDescriptor(descriptor, node => ({
261
+ ...node,
262
+ props: { ...node.props, className: "styled" }
263
+ }));
264
+
265
+ // Find matching nodes
266
+ const buttons = findInDescriptor(descriptor, n => n.type === "button");
267
+
268
+ // Get all component types used
269
+ const types: Set<string> = getUsedTypes(descriptor);
270
+
271
+ // Validate against known types
272
+ const { valid, unknownTypes } = validateDescriptor(descriptor, knownTypes);
273
+
274
+ // Serialization
275
+ const json = serializeDescriptor(descriptor);
276
+ const parsed = parseDescriptor(json);
277
+ const compact = compactDescriptor(descriptor); // Remove empty values
278
+ ```
279
+
280
+ ---
281
+
282
+ ### Stream Utilities
283
+
284
+ ```typescript
285
+ // Merge multiple component streams
286
+ for await (const output of mergeStreams(stream1, stream2)) {
287
+ render(output);
288
+ }
289
+
290
+ // Rate limiting
291
+ for await (const output of throttleStream(stream, 100)) {
292
+ // Max 1 update per 100ms
293
+ render(output);
294
+ }
295
+
296
+ for await (const output of debounceStream(stream, 200)) {
297
+ // Wait 200ms of quiet before emitting
298
+ render(output);
299
+ }
300
+ ```
301
+
302
+ ---
303
+
304
+ ## ComponentOutput Format
305
+
306
+ The wire format for component descriptors:
307
+
308
+ ```typescript
309
+ interface ComponentOutput {
310
+ type: string; // Component type or "__null__" / "__fragment__"
311
+ props: Record<string, unknown>; // Component props
312
+ children?: ComponentOutput[]; // Nested children
313
+ key?: string | number; // React key
314
+ }
315
+ ```
316
+
317
+ ### Special Types
318
+
319
+ ```mermaid
320
+ graph LR
321
+ subgraph "Standard"
322
+ Component["type: 'user-card'"]
323
+ end
324
+
325
+ subgraph "Null"
326
+ Null["type: '__null__'<br/>Renders nothing"]
327
+ end
328
+
329
+ subgraph "Fragment"
330
+ Fragment["type: '__fragment__'<br/>Wraps children"]
331
+ end
332
+ ```
333
+
334
+ ### Example Descriptor
335
+
336
+ ```json
337
+ {
338
+ "type": "user-card",
339
+ "props": { "userId": 123, "showBadge": true },
340
+ "children": [
341
+ {
342
+ "type": "badge",
343
+ "props": { "label": "Admin" }
344
+ }
345
+ ]
346
+ }
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Integration
352
+
353
+ ### Built-in Procedures
354
+
355
+ | Path | Description |
356
+ |------|-------------|
357
+ | `splay.bridge.info` | Package information |
358
+ | `splay.bridge.health` | Health check |
359
+
360
+ ### Re-exports from client/components
361
+
362
+ ```typescript
363
+ import {
364
+ // Types
365
+ ComponentOutput, FragmentOutput, NullOutput, Size,
366
+ ComponentContext, ComponentFactory, ComponentDefinition,
367
+
368
+ // Helpers
369
+ nullOutput, fragment, isFragment, isNullOutput,
370
+ defineComponent, simpleComponent, streamingComponent,
371
+ } from "@procedures/splay";
372
+ ```
373
+
374
+ ### Package Hierarchy
375
+
376
+ ```mermaid
377
+ graph BT
378
+ subgraph "UI Layer"
379
+ SplayReact[splay-react]
380
+ end
381
+
382
+ subgraph "Bridge"
383
+ ClientSplay[client-splay]
384
+ end
385
+
386
+ subgraph "Core"
387
+ Splay[splay]
388
+ Client[client]
389
+ end
390
+
391
+ SplayReact --> ClientSplay
392
+ ClientSplay --> Splay
393
+ ClientSplay --> Client
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Requirements
399
+
400
+ - **Node.js** >= 25
401
+ - **Dependencies:**
402
+ - `@procedures/client`
403
+ - `@mark1russell7/splay`
404
+
405
+ ---
406
+
407
+ ## License
408
+
409
+ MIT