reflow_rt_capi 0.2.1

C ABI bindings for the Reflow runtime — the shared native surface consumed by Go (cgo), Kotlin/Java (JNI), and other non-Rust callers.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
#ifndef REFLOW_RT_H
#define REFLOW_RT_H

/* GENERATED FILE — edit src/lib.rs and rerun `cargo build --features generate-header`. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

/**
 * Variant tag — matches the `Message` enum in `reflow_actor`.
 */
typedef enum rfl_message_kind {
  rfl_message_kind_Flow = 0,
  rfl_message_kind_Boolean = 1,
  rfl_message_kind_Integer = 2,
  rfl_message_kind_Float = 3,
  rfl_message_kind_String = 4,
  rfl_message_kind_Object = 5,
  rfl_message_kind_Array = 6,
  rfl_message_kind_Bytes = 7,
  rfl_message_kind_Error = 8,
  rfl_message_kind_StreamHandle = 9,
  rfl_message_kind_Optional = 10,
  /**
   * Anything else — use `rfl_message_as_json` to inspect.
   */
  rfl_message_kind_Other = 99,
} rfl_message_kind;

typedef enum rfl_status {
  /**
   * Success.
   */
  rfl_status_Ok = 0,
  /**
   * A required argument was NULL.
   */
  rfl_status_NullArg = -1,
  /**
   * A C string was not valid UTF-8.
   */
  rfl_status_InvalidUtf8 = -2,
  /**
   * A JSON payload failed to parse or deserialize.
   */
  rfl_status_InvalidJson = -3,
  /**
   * The runtime refused the operation (see `rfl_last_error_message`).
   */
  rfl_status_Runtime = -4,
  /**
   * The network has already been started or is in a state that forbids
   * the operation.
   */
  rfl_status_InvalidState = -5,
} rfl_status;

/**
 * Variant tag returned by `rfl_stream_recv_next`.
 */
typedef enum rfl_stream_frame_kind {
  rfl_stream_frame_kind_Begin = 0,
  rfl_stream_frame_kind_Data = 1,
  rfl_stream_frame_kind_End = 2,
  rfl_stream_frame_kind_Error = 3,
  rfl_stream_frame_kind_Timeout = 4,
  rfl_stream_frame_kind_Closed = 5,
} rfl_stream_frame_kind;

/**
 * Opaque handle to an actor template. Produced by `rfl_actor_new`
 * (callback-driven actor), `rfl_template_actor_new` (bundled component),
 * or `rfl_subgraph_actor_new_from_json` (embedded subgraph). Hand to
 * `rfl_network_register_actor` to publish under a template id, or to
 * `rfl_actor_free` to release without registering.
 */
typedef struct rfl_actor rfl_actor;

/**
 * Opaque per-call context handed to a callback actor.
 */
typedef struct rfl_actor_ctx rfl_actor_ctx;

/**
 * Opaque handle to a subscriber on the network's event stream. One
 * subscriber per handle — create as many as you need.
 */
typedef struct rfl_events rfl_events;

/**
 * Opaque handle to a `reflow_graph::Graph`.
 */
typedef struct rfl_graph rfl_graph;

/**
 * Opaque Reflow message handle.
 */
typedef struct rfl_message rfl_message;

/**
 * Opaque handle to a `reflow_network::Network`, wrapped so the C side can
 * share it across threads without touching its internal `Arc<Mutex<_>>`.
 */
typedef struct rfl_network rfl_network;

/**
 * Opaque producer handle to a stream. Create with `rfl_stream_new`, hand
 * chunks in via `rfl_stream_send_bytes`, terminate with
 * `rfl_stream_end` / `rfl_stream_error`. Free with `rfl_stream_free`.
 */
typedef struct rfl_stream rfl_stream;

/**
 * Opaque receiver for a stream's data channel.
 */
typedef struct rfl_stream_recv rfl_stream_recv;

/**
 * Builder for a `SubgraphActor` with an explicit actor map.
 */
typedef struct rfl_subgraph_builder rfl_subgraph_builder;

/**
 * Function pointer: the body of a callback actor.
 *
 * The callback is invoked every time the runtime has inputs for the actor.
 * Return `rfl_status::Ok` to commit whatever was emitted via
 * `rfl_ctx_emit`; any other status aborts the tick with an error in the
 * network event stream.
 */
typedef enum rfl_status (*rfl_actor_fn)(void *user_data, struct rfl_actor_ctx *ctx);

/**
 * Function pointer: released when the runtime drops the last reference to
 * the actor. Use it to decrement a Node/Python/JVM GC root.
 */
typedef void (*rfl_actor_drop_fn)(void *user_data);

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

/**
 * Returns the last thread-local error message as a newly allocated C string.
 * Caller frees with `rfl_string_free`. Returns NULL if there is no error.
 */
char *rfl_last_error_message(void);

/**
 * Free a string returned by this library. Passing NULL is a no-op.
 */
void rfl_string_free(char *s);

/**
 * Explicitly tear down the shared tokio runtime.
 *
 * Safe to call more than once. Normally this happens automatically on
 * library unload; call it from long-lived embedders that want to release
 * threads early.
 */
void rfl_runtime_shutdown(void);

/**
 * Create a new empty graph.
 *
 * `name` and `case_sensitive` follow `Graph::new`. Pass NULL for `name`
 * to use an empty name.
 */
struct rfl_graph *rfl_graph_new(const char *name, int case_sensitive);

/**
 * Load a graph from a `GraphExport` JSON document.
 *
 * Returns NULL on failure (check `rfl_last_error_message`).
 */
struct rfl_graph *rfl_graph_load_json(const char *json);

/**
 * Free a graph handle. Safe on NULL.
 */
void rfl_graph_free(struct rfl_graph *g);

/**
 * Create a new network with `NetworkConfig::default()`.
 */
struct rfl_network *rfl_network_new(void);

/**
 * Create a new network from a serialized `NetworkConfig` JSON. Returns
 * NULL on parse error. Unknown fields are rejected.
 */
struct rfl_network *rfl_network_new_with_config(const char *config_json);

/**
 * Create a network from an already-loaded graph. The graph is consumed.
 */
struct rfl_network *rfl_network_from_graph(struct rfl_graph *g);

/**
 * Start the network. Non-blocking; returns immediately after scheduling
 * the actors.
 */
enum rfl_status rfl_network_start(struct rfl_network *n);

/**
 * Signal the network to shut down. Non-blocking.
 */
enum rfl_status rfl_network_shutdown(struct rfl_network *n);

/**
 * Free a network handle. Safe on NULL. Implies shutdown.
 */
void rfl_network_free(struct rfl_network *n);

/**
 * Subscribe to the network's event stream. Call **before**
 * `rfl_network_start` for full coverage.
 */
struct rfl_events *rfl_network_events(struct rfl_network *n);

/**
 * Poll for the next event, blocking up to `timeout_ms` milliseconds.
 *
 * On success, writes a newly allocated JSON-encoded event string to
 * `*out_json`. Caller frees with `rfl_string_free`.
 *
 * Returns:
 * - `rfl_status::Ok` on success.
 * - `rfl_status::Runtime` if the channel is closed (network dropped).
 * - `rfl_status::InvalidState` on timeout (no event, channel still open).
 */
enum rfl_status rfl_events_recv(struct rfl_events *e, uint32_t timeout_ms, char **out_json);

/**
 * Free an events handle. Safe on NULL.
 */
void rfl_events_free(struct rfl_events *e);

/**
 * Runtime version string (newly allocated; free with `rfl_string_free`).
 */
char *rfl_version(void);

/**
 * Add a node.
 * `metadata_json` may be NULL or a JSON object string (`{"key": ...}`).
 */
enum rfl_status rfl_graph_add_node(struct rfl_graph *g,
                                   const char *id,
                                   const char *component,
                                   const char *metadata_json);

enum rfl_status rfl_graph_remove_node(struct rfl_graph *g, const char *id);

/**
 * Replace the metadata for an existing node.
 */
enum rfl_status rfl_graph_set_node_metadata(struct rfl_graph *g,
                                            const char *id,
                                            const char *metadata_json);

enum rfl_status rfl_graph_add_connection(struct rfl_graph *g,
                                         const char *out_node,
                                         const char *out_port,
                                         const char *in_node,
                                         const char *in_port,
                                         const char *metadata_json);

enum rfl_status rfl_graph_remove_connection(struct rfl_graph *g,
                                            const char *out_node,
                                            const char *out_port,
                                            const char *in_node,
                                            const char *in_port);

/**
 * Add an initial packet. `data_json` is the JSON representation of the
 * value (not a `Message`) — matches `Graph::add_initial`.
 */
enum rfl_status rfl_graph_add_initial(struct rfl_graph *g,
                                      const char *node,
                                      const char *port,
                                      const char *data_json,
                                      const char *metadata_json);

enum rfl_status rfl_graph_remove_initial(struct rfl_graph *g, const char *node, const char *port);

/**
 * Expose an inport on the graph (used when this graph is embedded as a
 * subgraph). `port_type_json` is optional; pass NULL for `PortType::Any`
 * or `"\"All\""` / `"\"Flow\""` etc.
 */
enum rfl_status rfl_graph_add_inport(struct rfl_graph *g,
                                     const char *port_id,
                                     const char *node_id,
                                     const char *port_key,
                                     const char *port_type_json,
                                     const char *metadata_json);

enum rfl_status rfl_graph_add_outport(struct rfl_graph *g,
                                      const char *port_id,
                                      const char *node_id,
                                      const char *port_key,
                                      const char *port_type_json,
                                      const char *metadata_json);

enum rfl_status rfl_graph_remove_inport(struct rfl_graph *g, const char *port_id);

enum rfl_status rfl_graph_remove_outport(struct rfl_graph *g, const char *port_id);

/**
 * Serialize a graph back to its `GraphExport` JSON form.
 * Caller frees via `rfl_string_free`.
 */
char *rfl_graph_to_json(struct rfl_graph *g);

/**
 * Rename a node. Updates every connection that referenced the old id.
 */
enum rfl_status rfl_graph_rename_node(struct rfl_graph *g, const char *old_id, const char *new_id);

/**
 * Rename an exposed inport (subgraph boundary).
 */
enum rfl_status rfl_graph_rename_inport(struct rfl_graph *g,
                                        const char *old_port,
                                        const char *new_port);

/**
 * Rename an exposed outport (subgraph boundary).
 */
enum rfl_status rfl_graph_rename_outport(struct rfl_graph *g,
                                         const char *old_port,
                                         const char *new_port);

/**
 * `add_initial` with an explicit slot index for arrays/streams. Mirrors
 * `Graph::add_initial_index`.
 */
enum rfl_status rfl_graph_add_initial_index(struct rfl_graph *g,
                                            const char *node,
                                            const char *port,
                                            const char *data_json,
                                            uintptr_t index,
                                            const char *metadata_json);

/**
 * Push a packet into one of the graph's exposed inports.
 */
enum rfl_status rfl_graph_add_graph_initial(struct rfl_graph *g,
                                            const char *inport,
                                            const char *data_json,
                                            const char *metadata_json);

/**
 * Indexed variant of `rfl_graph_add_graph_initial`.
 */
enum rfl_status rfl_graph_add_graph_initial_index(struct rfl_graph *g,
                                                  const char *inport,
                                                  const char *data_json,
                                                  uintptr_t index,
                                                  const char *metadata_json);

/**
 * Remove an initial packet attached to a graph-level inport.
 */
enum rfl_status rfl_graph_remove_graph_initial(struct rfl_graph *g, const char *inport);

/**
 * Create a group containing the given node ids.
 * `nodes_json` must be a JSON array of strings, e.g. `["a","b"]`.
 */
enum rfl_status rfl_graph_add_group(struct rfl_graph *g,
                                    const char *group_id,
                                    const char *nodes_json,
                                    const char *metadata_json);

enum rfl_status rfl_graph_remove_group(struct rfl_graph *g, const char *group_id);

enum rfl_status rfl_graph_add_to_group(struct rfl_graph *g,
                                       const char *group_id,
                                       const char *node_id);

enum rfl_status rfl_graph_remove_from_group(struct rfl_graph *g,
                                            const char *group_id,
                                            const char *node_id);

/**
 * Replace the metadata on a connection. NULL `metadata_json` clears it.
 */
enum rfl_status rfl_graph_set_connection_metadata(struct rfl_graph *g,
                                                  const char *out_node,
                                                  const char *out_port,
                                                  const char *in_node,
                                                  const char *in_port,
                                                  const char *metadata_json);

enum rfl_status rfl_graph_set_inport_metadata(struct rfl_graph *g,
                                              const char *port_id,
                                              const char *metadata_json);

enum rfl_status rfl_graph_set_outport_metadata(struct rfl_graph *g,
                                               const char *port_id,
                                               const char *metadata_json);

enum rfl_status rfl_graph_set_group_metadata(struct rfl_graph *g,
                                             const char *group_id,
                                             const char *metadata_json);

/**
 * Replace the graph's properties dict. NULL clears it.
 */
enum rfl_status rfl_graph_set_properties(struct rfl_graph *g, const char *properties_json);

/**
 * Merge a `GraphExport` JSON document into the existing graph
 * (additive — does not clear).
 */
enum rfl_status rfl_graph_import(struct rfl_graph *g, const char *export_json);

/**
 * Look up a node by id. Returns the JSON of the GraphNode, or NULL if
 * the id is unknown (last error explains).
 */
char *rfl_graph_get_node_json(struct rfl_graph *g, const char *id);

/**
 * JSON array of every node in the graph.
 */
char *rfl_graph_list_nodes_json(struct rfl_graph *g);

/**
 * Look up a connection by both endpoints. NULL if no such edge.
 */
char *rfl_graph_get_connection_json(struct rfl_graph *g,
                                    const char *out_node,
                                    const char *out_port,
                                    const char *in_node,
                                    const char *in_port);

char *rfl_graph_list_connections_json(struct rfl_graph *g);

char *rfl_graph_list_groups_json(struct rfl_graph *g);

char *rfl_graph_list_inports_json(struct rfl_graph *g);

char *rfl_graph_list_outports_json(struct rfl_graph *g);

char *rfl_graph_list_initializers_json(struct rfl_graph *g);

char *rfl_graph_get_properties_json(struct rfl_graph *g);

/**
 * Add a node to a running or pending network. The `template_id`'s actor
 * must have been registered first (via the component catalog or a custom
 * `rfl_actor_register` once available).
 */
enum rfl_status rfl_network_add_node(struct rfl_network *n,
                                     const char *id,
                                     const char *template_id,
                                     const char *config_json);

enum rfl_status rfl_network_add_connection(struct rfl_network *n,
                                           const char *from_actor,
                                           const char *from_port,
                                           const char *to_actor,
                                           const char *to_port);

/**
 * Seed an initial packet. `message_json` must parse as a `Message`
 * (e.g. `"\"Flow\""`, `{"Integer": 3}`, `{"String": "hi"}`).
 */
enum rfl_status rfl_network_add_initial(struct rfl_network *n,
                                        const char *actor,
                                        const char *port,
                                        const char *message_json);

/**
 * Create a callback-driven actor.
 *
 * `inports` / `outports` arrays point to `n_*` C strings each (UTF-8).
 * `await_all_inports` = 1 makes the runtime buffer packets until every
 * declared inport has data; 0 fires on any input.
 *
 * `user_data_drop` may be NULL if no cleanup is needed.
 */
struct rfl_actor *rfl_actor_new(const char *component_name,
                                const char *const *inports,
                                uintptr_t n_inports,
                                const char *const *outports,
                                uintptr_t n_outports,
                                int await_all_inports,
                                rfl_actor_fn callback,
                                void *user_data,
                                rfl_actor_drop_fn user_data_drop);

/**
 * Free an actor handle that was never registered. NULL-safe.
 */
void rfl_actor_free(struct rfl_actor *a);

/**
 * Register a callback actor as a template on the network. The network
 * takes ownership; the caller must **not** continue to use the handle
 * afterwards (treat it as freed).
 */
enum rfl_status rfl_network_register_actor(struct rfl_network *n,
                                           const char *template_id,
                                           struct rfl_actor *a);

/**
 * 1 if a packet is available on `port`, 0 otherwise. Does not consume.
 */
int rfl_ctx_has_input(struct rfl_actor_ctx *ctx, const char *port);

/**
 * Take the input packet on `port` as a typed message handle, removing
 * it from the context. Returns NULL if no packet is available. Caller
 * frees via `rfl_message_free` (or transfers ownership via
 * `rfl_ctx_emit_message`).
 */
struct rfl_message *rfl_ctx_take_input_message(struct rfl_actor_ctx *ctx, const char *port);

/**
 * Return the input packet on `port` as a JSON-encoded `Message`, or NULL
 * if no packet is available. Caller frees via `rfl_string_free`.
 */
char *rfl_ctx_input_json(struct rfl_actor_ctx *ctx, const char *port);

/**
 * Return the current config as a JSON object string. Caller frees via
 * `rfl_string_free`. Returns NULL on error.
 */
char *rfl_ctx_config_json(struct rfl_actor_ctx *ctx);

/**
 * Fetch a state entry as JSON. Returns NULL if absent.
 * Caller frees via `rfl_string_free`.
 *
 * Only works against `MemoryState` (the default state backend) — custom
 * backends will yield NULL.
 */
char *rfl_ctx_state_get(struct rfl_actor_ctx *ctx, const char *key);

/**
 * Set a state entry. `value_json` is a JSON value (any shape).
 */
enum rfl_status rfl_ctx_state_set(struct rfl_actor_ctx *ctx,
                                  const char *key,
                                  const char *value_json);

/**
 * Emit a typed message on `port`. Transfers ownership of the message —
 * do **not** call `rfl_message_free` afterwards. Prefer this over the
 * JSON variant for hot-path emits.
 */
enum rfl_status rfl_ctx_emit_message(struct rfl_actor_ctx *ctx,
                                     const char *port,
                                     struct rfl_message *msg);

/**
 * Emit a packet on `port`. `message_json` must parse as a Reflow
 * `Message` (e.g. `{"type":"Flow"}`, `{"type":"Integer","data":1}`).
 * Prefer `rfl_ctx_emit_message` for hot-path emits — this variant
 * serializes JSON per call.
 */
enum rfl_status rfl_ctx_emit(struct rfl_actor_ctx *ctx, const char *port, const char *message_json);

struct rfl_message *rfl_message_flow(void);

struct rfl_message *rfl_message_boolean(int v);

struct rfl_message *rfl_message_integer(int64_t v);

struct rfl_message *rfl_message_float(double v);

/**
 * UTF-8 string; copied.
 */
struct rfl_message *rfl_message_string(const char *s);

/**
 * Binary payload; the buffer is copied into a refcounted allocation.
 */
struct rfl_message *rfl_message_bytes(const uint8_t *data, uintptr_t len);

/**
 * Object from JSON. The JSON must parse as any valid serde value.
 */
struct rfl_message *rfl_message_object_from_json(const char *json);

/**
 * Array from a JSON array string.
 */
struct rfl_message *rfl_message_array_from_json(const char *json);

struct rfl_message *rfl_message_error(const char *msg);

/**
 * Fallback: parse a fully-tagged `Message` JSON (i.e. the same shape the
 * legacy `rfl_ctx_emit`-by-JSON path consumes). Useful for tests /
 * debugging — prefer the typed constructors in production.
 */
struct rfl_message *rfl_message_from_json(const char *json);

enum rfl_message_kind rfl_message_get_kind(const struct rfl_message *m);

/**
 * If the message is a Boolean, writes its value into `*out` and returns 1.
 * Returns 0 otherwise.
 */
int rfl_message_as_boolean(const struct rfl_message *m, int *out);

int rfl_message_as_integer(const struct rfl_message *m, int64_t *out);

int rfl_message_as_float(const struct rfl_message *m, double *out);

/**
 * String access — returns a newly allocated C string on String/Error
 * variants, else NULL. Caller frees via `rfl_string_free`.
 */
char *rfl_message_as_string(const struct rfl_message *m);

/**
 * Full message serialized as JSON. Always succeeds for representable
 * variants. Caller frees via `rfl_string_free`.
 */
char *rfl_message_as_json(const struct rfl_message *m);

/**
 * Zero-copy borrow of a `Bytes` payload. Writes a pointer into the
 * Arc'd buffer and its length. The pointer is valid until the message
 * handle is freed (or ownership transferred). Returns 1 on success, 0
 * if the message is not a Bytes variant.
 */
int rfl_message_bytes_borrow(const struct rfl_message *m,
                             const uint8_t **out_data,
                             uintptr_t *out_len);

/**
 * Free a message handle. Safe on NULL.
 *
 * Do **not** call this after handing the message to `rfl_ctx_emit`
 * (which transfers ownership).
 */
void rfl_message_free(struct rfl_message *m);

/**
 * Allocate a new stream. `buffer_size == 0` creates an unbounded channel;
 * any positive value sets a bounded buffer (backpressure).
 *
 * `origin_actor` and `origin_port` are metadata attached to the
 * StreamHandle that lets consumers trace where the stream came from.
 * Either may be NULL to use empty strings.
 *
 * `content_type` is an optional MIME hint (NULL for none).
 */
struct rfl_stream *rfl_stream_new(uintptr_t buffer_size,
                                  const char *origin_actor,
                                  const char *origin_port,
                                  const char *content_type);

/**
 * Send a Data frame. The buffer is copied into a refcounted allocation.
 */
enum rfl_status rfl_stream_send_bytes(struct rfl_stream *s, const uint8_t *data, uintptr_t len);

/**
 * Send a Begin frame (stream metadata). Optional — use before the first
 * `send_bytes` if you want consumers to see `content_type` / `size_hint`
 * / `metadata_json` before any data.
 */
enum rfl_status rfl_stream_send_begin(struct rfl_stream *s,
                                      const char *content_type,
                                      uint64_t size_hint,
                                      int has_size_hint,
                                      const char *metadata_json);

/**
 * Terminate the stream with success.
 */
enum rfl_status rfl_stream_end(struct rfl_stream *s);

/**
 * Terminate the stream with an error.
 */
enum rfl_status rfl_stream_error(struct rfl_stream *s, const char *message);

/**
 * Convert this stream producer into a `Message::StreamHandle` that can be
 * emitted on an output port. The producer is **consumed** — free is not
 * necessary after this call.
 */
struct rfl_message *rfl_stream_into_message(struct rfl_stream *s);

/**
 * Free a producer handle without emitting it as a message. If the stream
 * has live consumers, they will see an `End` frame when the sender is
 * dropped.
 */
void rfl_stream_free(struct rfl_stream *s);

/**
 * Take the receiver for a `StreamHandle` message. Transfers ownership —
 * only one call succeeds per stream. Returns NULL if the message is not
 * a StreamHandle or the receiver has already been taken.
 */
struct rfl_stream_recv *rfl_message_stream_take(struct rfl_message *m);

/**
 * Block up to `timeout_ms` for the next frame.
 *
 * Writes the frame kind into `*out_kind`. On `Data` / `Error`, also
 * populates `*out_data` / `*out_len` / `*out_err` as appropriate. The
 * pointers are valid until the next call to `rfl_stream_recv_next` on
 * the same receiver.
 */
enum rfl_status rfl_stream_recv_next(struct rfl_stream_recv *r,
                                     uint32_t timeout_ms,
                                     enum rfl_stream_frame_kind *out_kind,
                                     const uint8_t **out_data,
                                     uintptr_t *out_len,
                                     char **out_err);

/**
 * Free a stream receiver. Safe on NULL.
 */
void rfl_stream_recv_free(struct rfl_stream_recv *r);

/**
 * Start a subgraph builder over a `GraphExport` JSON document. Returns
 * NULL on parse error.
 */
struct rfl_subgraph_builder *rfl_subgraph_builder_new(const char *graph_export_json);

/**
 * Register an actor under `component_name`. The builder takes ownership
 * of the actor handle — do not free it afterwards. Replacing an existing
 * registration silently overwrites it.
 */
enum rfl_status rfl_subgraph_builder_register_actor(struct rfl_subgraph_builder *b,
                                                    const char *component_name,
                                                    struct rfl_actor *actor);

/**
 * Resolve any still-unregistered components: packs first, then the
 * bundled catalog (if the `components` feature is on). Components still
 * missing after both lookups cause the call to fail.
 */
enum rfl_status rfl_subgraph_builder_fill_from_catalog(struct rfl_subgraph_builder *b);

/**
 * Build the subgraph into an actor handle. Consumes the builder.
 */
struct rfl_actor *rfl_subgraph_builder_build(struct rfl_subgraph_builder *b);

/**
 * Abandon a builder without building. Safe on NULL.
 */
void rfl_subgraph_builder_free(struct rfl_subgraph_builder *b);

/**
 * Compose N graph exports into a single `GraphExport` JSON document.
 *
 * The returned string is a heap-allocated C string owned by the caller;
 * free with `rfl_string_free`. Returns NULL on failure; read the error
 * message via `rfl_last_error_message`.
 */
char *rfl_compose_graphs(const char *composition_json);

/**
 * Load an actor pack from `path`. `path` can point at either:
 * - a `.rflpack` bundle (detected by zip magic), or
 * - a raw cdylib (`.so`, `.dylib`, `.dll`) — useful during pack
 *   development.
 *
 * Returns `rfl_status::Ok` and, on success, writes a JSON array of newly
 * registered template ids into `*out_templates_json`. Caller frees the
 * JSON via `rfl_string_free`.
 *
 * Loading the same pack twice (by manifest name, or by file stem for
 * raw dylibs) is a no-op — the existing template set is returned
 * unchanged. This makes the call safe to invoke from repeated workflow
 * boots.
 */
enum rfl_status rfl_pack_load(const char *path, char **out_templates_json);

/**
 * Return a JSON array describing every loaded pack:
 * `[{ "name": ..., "version": ..., "source_path": ..., "templates": [...] }]`.
 * Caller frees via `rfl_string_free`.
 */
char *rfl_pack_list_json(void);

/**
 * Read a `.rflpack` manifest without loading the pack. Fails for raw
 * dylibs (they have no manifest). Caller frees the returned JSON via
 * `rfl_string_free`.
 */
char *rfl_pack_inspect_json(const char *path);

/**
 * The pack ABI version this host was compiled with. Pack authors can
 * stamp the same number into their `.rflpack` manifests via
 * `reflow-pack build` (which reads the `REFLOW_PACK_ABI_VERSION` env var
 * or `[abi]` section).
 */
uint32_t rfl_pack_abi_version(void);

/**
 * Instantiate an actor from a template id.
 *
 * Lookup order:
 * 1. Templates registered by loaded `.rflpack` packs (see
 *    `rfl_pack_load`).
 * 2. The bundled `reflow_components` catalog, if this build includes the
 *    `components` feature (on by default).
 *
 * Returns an `rfl_actor*` that can be handed to
 * `rfl_network_register_actor`. Returns NULL with
 * `rfl_last_error_message` set if no loaded pack and no bundled catalog
 * owns the id.
 */
struct rfl_actor *rfl_template_actor_new(const char *template_id);

/**
 * Return a JSON array of every template id reachable through this
 * runtime — loaded packs plus (when compiled) the bundled catalog.
 * Caller frees via `rfl_string_free`.
 */
char *rfl_template_list_json(void);

/**
 * Build a SubgraphActor from a `GraphExport` JSON document. Each
 * component referenced inside the export is resolved against the pack
 * registry first, then the bundled `reflow_components` catalog.
 * Returns NULL on parse error or on unknown component references.
 *
 * The resulting `rfl_actor*` can be handed to `rfl_network_register_actor`
 * exactly like any other actor template.
 *
 * Requires the `components` feature (gives us `SubgraphActor`).
 */
struct rfl_actor *rfl_subgraph_actor_new_from_json(const char *graph_export_json);

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  /* REFLOW_RT_H */