@urun-sh/core 0.2.2 → 0.2.4

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/README.md CHANGED
@@ -22,33 +22,64 @@ const app = App('my-app', {
22
22
 
23
23
  const session = app.generate({ prompt: 'A sunset' })
24
24
 
25
+ // Consume the stream the runtime produces (direction is decided by first use). Tracks
26
+ // arrive ASYNCHRONOUSLY — subscribe with `.on('track', …)`; never read `.track` once.
25
27
  const video = session.stream('video')
26
- if (video.track) {
27
- videoElement.srcObject = new MediaStream([video.track])
28
- }
28
+ video.on('track', (track) => {
29
+ videoElement.srcObject = new MediaStream([track])
30
+ })
29
31
 
30
- session.doc('control').set({ prompt: { text: 'A forest' } })
32
+ // Drive the app by writing DESIRED state into the control doc; the runtime reactively
33
+ // reconciles it (cheap config via an inline live read, structural change via `doc.bind`).
34
+ session.doc('control').set({ desired: { prompt: { text: 'A forest' } } })
31
35
  ```
32
36
 
33
- The names mirror the Python side:
37
+ The names mirror the Python side 1:1:
34
38
 
35
39
  - `App('my-app')` mirrors `urun.App('my-app')`
36
40
  - `app.generate()` mirrors `@app.function def generate(...)`
37
- - `session.stream('video')` mirrors `ctx.stream('video')`
41
+ - `session.stream('video')` mirrors `ctx.stream('video', codec=...)`
38
42
  - `session.doc('control')` mirrors `ctx.doc('control')`
43
+ - `createStore()` mirrors the runtime `store = app.store`
44
+
45
+ ## Streams are symmetric (produce-or-consume by first use)
46
+
47
+ `session.stream(name)` is one symmetric primitive — the **first producer decides the
48
+ direction** and the peer consumes (full-duplex = two named streams). On the runtime,
49
+ `ctx.stream("name")` is the polymorphic I/O endpoint: the pipeline HEAD when it drives and the
50
+ TAIL when it sinks. `attach(track)` makes the client the producer of that name (the inbound HEAD
51
+ the runtime composes with `ctx.stream(name) | …`); calling `stream(name)` without attaching
52
+ consumes the runtime's output. A second producer on the same name fails loud with
53
+ `StreamDirectionConflict` — never a silent merge. The runtime `ctx.stream(codec=…)` sink owns
54
+ media encode; the client only attaches the inbound `track` to a media element. Tracks arrive
55
+ asynchronously — subscribe with `.on('track', …)`.
56
+
57
+ ## The control doc is the reactive desired-state surface
58
+
59
+ The client does NOT call an imperative `start/update/stop`. It writes `desired.*` keys into a
60
+ control doc with `session.doc(name).set(...)`. The runtime reads CHEAP config inline from the
61
+ live `doc.desired.*` props and uses `doc.bind(construct, [live props])` (React `useMemo`) to
62
+ reconstruct a stage on STRUCTURAL change — the single reconcile lane, no field-mapping, no
63
+ second hand-poll (`pipeline.bind` / `stage.bind(doc, mapping)` are retired). Keep the
64
+ `desired.<path>` names the client writes consistent with what the runtime reads.
39
65
 
40
66
  ## API
41
67
 
42
68
  - `App(appId, options)` — reference a deployed urun app.
43
69
  - `app.<function>(args?)` — call a Python function and get a session handle.
44
- - `session.stream(name)` — get or create a named media stream.
45
- - `session.stream(name).track` — read the latest inbound browser track.
46
- - `session.stream(name).attach(track)` — send a local browser track upstream.
47
- - `session.stream(name).detach()` — stop sending the local browser track.
70
+ - `session.stream(name)` — get a named symmetric stream (media or data); first use decides direction.
71
+ - `session.stream(name).track` — read the latest inbound track (consume side).
72
+ - `session.stream(name).on('track', cb)` — subscribe to inbound tracks as they arrive.
73
+ - `session.stream(name).attach(track)` — produce: send a local browser track upstream.
74
+ - `session.stream(name).detach()` — stop producing the local browser track.
48
75
  - `session.stream(name).seek(seconds)` — seek a persisted finite stream to seconds from start.
49
76
  - `session.stream(name).seek('live')` — return a live stream to the live edge.
50
- - `session.doc(name).set(patch)` — update a session document.
51
- - `createStore(options)` — advanced global key/value access.
77
+ - `session.doc(name).get()` — read the merged document snapshot.
78
+ - `session.doc(name).set(patch)` — write desired state into a session document.
79
+ - `session.doc(name).on('change', cb)` — react to runtime-published document changes.
80
+ - `createStore(options)` — content-addressed global store: `get(key)` / `has(key)` reads and
81
+ `on(name, cb)` / `emit(name, data)` global streams. (App-scoped `store.cache` is a runtime
82
+ concern; content-addressed blobs — `store.model`/`store.path`/`store.repo` — are not app-scoped.)
52
83
 
53
84
  ## Authentication
54
85