Skip to content

Commit 96fe0d9

Browse files
authored
feat(contexts): add new context features and metadata support (#51)
- Introduce context creation with naming and renaming - Enhance error messages with span metadata - Update docs and Rust error handling for clarity
1 parent 8dc9498 commit 96fe0d9

File tree

3 files changed

+114
-218
lines changed

3 files changed

+114
-218
lines changed

docs/src/content/docs/reference/contexts.mdx

Lines changed: 51 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ specific context is specified.
1414
## System Context
1515

1616
When you first start using cross.stream, you're working in the system context.
17-
Let's see this in action:
18-
19-
<Tabs syncKey="shell">
20-
<TabItem label="nushell">
17+
The system context contains the initial `xs.start` frame and any other frames
18+
you create without specifying a different context.
2119

2220
```nushell withOutput
2321
> .cat
@@ -26,257 +24,106 @@ Let's see this in action:
2624
───┴──────────┴───────────────────────────┴──────┴──────┴─────────
2725
```
2826

29-
The `xs.start` frame above is in the system context. Let's add a note:
27+
## Creating Contexts
28+
29+
Create a new named context using the `.ctx new` command:
3030

3131
```nushell withOutput
32-
> "system note" | .append notes
33-
───────┬─────────────────────────────────────────────────────
34-
topic │ notes
35-
id │ 03d4q1qhbiv09ovtuhokw5yxv
36-
hash │ sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY=
37-
meta │
38-
ttl │ forever
39-
───────┴─────────────────────────────────────────────────────
32+
> .ctx new my-project
33+
03d4qbrxizqgav09m7hicksb0
4034
```
4135

42-
</TabItem>
43-
<TabItem label="bash">
36+
This creates a context named "my-project" and automatically switches to it.
4437

45-
```bash withOutput
46-
> xs cat ./store
47-
{"topic":"xs.start","id":"03d4qiab9g5vagrlrvxa2vjw0","hash":null,"meta":null,"ttl":null}
48-
```
38+
## Listing Contexts
4939

50-
The `xs.start` frame above is in the system context. Let's add a note:
40+
View all available contexts:
5141

52-
```bash withOutput
53-
> echo "system note" | xs append ./store notes
54-
{"topic":"notes","id":"03d4qic9vqkve1krajjtlbavd","hash":"sha256-24yYvzQ4Zd3Go/WevV9ol+KzkdTgQvlyNN2NVSGMjFE=","meta":null,"ttl":"forever"}
42+
```nushell withOutput
43+
> .ctx list
44+
─#─┬───────────────id───────────────┬───name─────┬─active──
45+
0 │ 0000000000000000000000000 │ system │ true
46+
1 │ 03d4qbrxizqgav09m7hicksb0 │ my-project │ false
47+
───┴────────────────────────────────┴────────────┴─────────
5548
```
5649

57-
</TabItem>
58-
</Tabs>
59-
60-
## Creating a New Context
50+
You can also use the `.ctx ls` alias for the same output.
6151

62-
To create a new context, we use the special `xs.context` topic:
52+
## Switching Contexts
6353

64-
<Tabs syncKey="shell">
65-
<TabItem label="nushell">
54+
Switch between contexts using either their names or IDs:
6655

6756
```nushell withOutput
68-
> "my project" | .append xs.context
69-
───────┬─────────────────────────────────────────────────────
70-
topic │ xs.context
71-
id │ 03d4qbrxizqgav09m7hicksb0
72-
meta │
73-
ttl │ forever
74-
───────┴─────────────────────────────────────────────────────
75-
76-
# Save the context ID for later use
77-
> let project_context = (ls | last).id
57+
> .ctx switch my-project
58+
03d4qbrxizqgav09m7hicksb0
59+
60+
> .ctx switch 03d4qbrxizqgav09m7hicksb0
61+
03d4qbrxizqgav09m7hicksb0
7862
```
7963

80-
</TabItem>
81-
<TabItem label="bash">
64+
You can also switch interactively by running `.ctx switch` without arguments.
65+
66+
## Renaming Contexts
8267

83-
```bash withOutput
84-
> echo "my project" | xs append ./store xs.context
85-
{"topic":"xs.context","id":"03d4qbrxizqgav09m7hicksb0","meta":null,"ttl":"forever"}
68+
You can rename contexts using the context ID:
8669

87-
# Save the context ID for later use
88-
PROJECT_CONTEXT=03d4qbrxizqgav09m7hicksb0
70+
```nushell withOutput
71+
> .ctx rename 03d4qbrxizqgav09m7hicksb0 feature-work
8972
```
9073

91-
</TabItem>
92-
</Tabs>
74+
This updates the name associated with the specified context ID.
9375

9476
## Using Contexts
9577

96-
Now we can add frames to our new context:
97-
98-
<Tabs syncKey="shell">
99-
<TabItem label="nushell">
78+
Once you've switched to a context, all operations happen in that context:
10079

10180
```nushell withOutput
102-
> "project note" | .append notes -c $project_context
103-
> .cat -c $project_context
81+
> "project note" | .append notes
82+
> .cat
10483
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬─meta─┬───ttl───
10584
0 │ notes │ 03d4qbrxizqgav09m7hicksb0 │ sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c= │ │ forever
10685
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴──────┴─────────
10786
```
10887

109-
Notice how `.cat -c $project_context` only shows frames from our project
110-
context. The system note we created earlier isn't visible.
111-
112-
The `head` command is also context-aware:
88+
You can explicitly specify a context with any command using the `-c` parameter:
11389

11490
```nushell withOutput
115-
> .head notes -c $project_context | .cas
116-
project note
117-
```
118-
119-
</TabItem>
120-
<TabItem label="bash">
121-
122-
```bash withOutput
123-
> echo "project note" | xs append ./store notes -c $PROJECT_CONTEXT
124-
> xs cat ./store -c $PROJECT_CONTEXT
125-
{"topic":"notes","id":"03d4qbrxizqgav09m7hicksb0","hash":"sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c=","meta":null,"ttl":"forever"}
91+
> "new feature idea" | .append notes -c feature-branch
92+
> .cat -c feature-branch
93+
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬─meta─┬───ttl───
94+
0 │ notes │ 03f8q6rxnzqgav09n7hicksb9 │ sha256-LMcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
95+
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴──────┴─────────
12696
```
12797

128-
Notice how `xs cat -c $PROJECT_CONTEXT` only shows frames from our project
129-
context. The system note we created earlier isn't visible.
130-
13198
The `head` command is also context-aware:
13299

133-
```bash withOutput
134-
> xs head ./store notes -c $PROJECT_CONTEXT | jq -r .hash | xargs xs cas ./store
135-
project note
100+
```nushell withOutput
101+
> .head notes -c feature-branch | .cas
102+
new feature idea
136103
```
137104

138-
</TabItem>
139-
</Tabs>
140-
141-
## Setting a Default Context
105+
## Viewing Current Context
142106

143-
Instead of specifying the context with each command, you can set a default:
144-
145-
<Tabs syncKey="shell">
146-
<TabItem label="nushell">
107+
See the ID of your current context:
147108

148109
```nushell withOutput
149-
> $env.XS_CONTEXT = $project_context
150-
> "another project note" | .append notes # Uses project context automatically
151-
> .cat # Also uses project context
152-
```
153-
154-
</TabItem>
155-
<TabItem label="bash">
156-
157-
```bash withOutput
158-
> export XS_CONTEXT=$PROJECT_CONTEXT
159-
> echo "another project note" | xs append ./store notes # Uses project context automatically
160-
> xs cat ./store # Also uses project context
110+
> .ctx
111+
03d4qbrxizqgav09m7hicksb0
161112
```
162113

163-
</TabItem>
164-
</Tabs>
165-
166114
## Viewing All Contexts
167115

168-
Sometimes you may want to see frames across all contexts:
169-
170-
<Tabs syncKey="shell">
171-
<TabItem label="nushell">
116+
View frames across all contexts with the `--all` flag:
172117

173118
```nushell withOutput
174119
> .cat --all
175120
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬─meta─┬───ttl───
176121
0 │ xs.start │ 03d4q1o70y6ek0ig8hwy9q00n │ │ │
177-
1 │ notes │ 03d4q1qhbiv09ovtuhokw5yxv │ sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
178-
2 │ xs.context│ 03d4qbrxizqgav09m7hicksb0 │ sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c= │ │ forever
179-
3 │ notes │ 03d4qkzpbiv09ovtuhokw5yxv │ sha256-LMcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
122+
1 │ notes │ 03d4qbrxizqgav09m7hicksb0 │ sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c= │ │ forever
123+
2 │ notes │ 03f8q6rxnzqgav09n7hicksb9 │ sha256-LMcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY= │ │ forever
180124
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴──────┴─────────
181125
```
182126

183-
</TabItem>
184-
<TabItem label="bash">
185-
186-
```bash withOutput
187-
> xs cat ./store --all
188-
{"topic":"xs.start","id":"03d4q1o70y6ek0ig8hwy9q00n","hash":null,"meta":null,"ttl":null}
189-
{"topic":"notes","id":"03d4q1qhbiv09ovtuhokw5yxv","hash":"sha256-wIcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY=","meta":null,"ttl":"forever"}
190-
{"topic":"xs.context","id":"03d4qbrxizqgav09m7hicksb0","hash":"sha256-KDyb7pypM+8aLiq5obfpCqbMmb6LvvPnCu2+y9eWd0c=","meta":null,"ttl":"forever"}
191-
{"topic":"notes","id":"03d4qkzpbiv09ovtuhokw5yxv","hash":"sha256-LMcRiyKpOjA1Z8O+wZvoiMXYgGEzPQOhlA8AOptOhBY=","meta":null,"ttl":"forever"}
192-
```
193-
194-
</TabItem>
195-
</Tabs>
196-
197127
<Aside type="tip">
198-
Everything in cross.stream is scoped by context - including TTLs, head tracking, and other features. This makes it easy to maintain separate streams of events while keeping them organized in the same store.
199-
</Aside>
200-
201-
## Managing Contexts with .ctx Commands
202-
203-
When using the NuShell convenience module (`xs.nu`), you get access to
204-
additional context management commands under the `.ctx` namespace. These provide
205-
a more interactive way to work with contexts.
206-
207-
### Listing Contexts
208-
209-
View all available contexts and see which one is active:
210-
211-
<Tabs syncKey="shell">
212-
<TabItem label="nushell">
213-
214-
```nushell withOutput
215-
> .ctx list
216-
─#─┬───────────────id───────────────┬─active─┐
217-
0 │ 0000000000000000000000000 │ true │
218-
1 │ 03d4qbrxizqgav09m7hicksb0 │ false │
219-
───┴──────────────────────────────────┴────────┘
220-
```
221-
222-
</TabItem>
223-
</Tabs>
224-
225-
### Switching Contexts
226-
227-
Change your active context:
228-
229-
<Tabs syncKey="shell">
230-
<TabItem label="nushell">
231-
232-
```nushell withOutput
233-
> .ctx switch 03d4qbrxizqgav09m7hicksb0
234-
03d4qbrxizqgav09m7hicksb0
235-
```
236-
237-
You can also switch interactively:
238-
239-
```nushell withOutput
240-
> .ctx switch
241-
# (shows interactive list to select from)
242-
03d4qbrxizqgav09m7hicksb0
243-
```
244-
245-
</TabItem>
246-
</Tabs>
247-
248-
### Creating a New Context
249-
250-
Create and automatically switch to a new context:
251-
252-
<Tabs syncKey="shell">
253-
<TabItem label="nushell">
254-
255-
```nushell withOutput
256-
> .ctx new
257-
03d4qbrxizqgav09m7hicksb0
258-
```
259-
260-
</TabItem>
261-
</Tabs>
262-
263-
### Viewing Current Context
264-
265-
Check your current context:
266-
267-
<Tabs syncKey="shell">
268-
<TabItem label="nushell">
269-
270-
```nushell withOutput
271-
> .ctx
272-
03d4qbrxizqgav09m7hicksb0
273-
```
274-
275-
</TabItem>
276-
</Tabs>
277-
278-
<Aside type="note">
279-
These `.ctx` commands modify the `$env.XS_CONTEXT` environment variable and
280-
provide a convenient wrapper around the basic context operations. They're only
281-
available when using NuShell with the xs.nu module loaded.
128+
Everything in cross.stream is scoped by context - including TTLs, head tracking, and other features. Using descriptive context names helps organize your event streams.
282129
</Aside>

src/main.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,20 @@ async fn cat(args: CommandCat) -> Result<(), Box<dyn std::error::Error + Send +
274274

275275
let mut receiver = xs::client::cat(&args.addr, options, args.sse).await?;
276276
let mut stdout = tokio::io::stdout();
277-
while let Some(bytes) = receiver.recv().await {
278-
stdout.write_all(&bytes).await?;
279-
stdout.flush().await?;
277+
278+
match async {
279+
while let Some(bytes) = receiver.recv().await {
280+
stdout.write_all(&bytes).await?;
281+
stdout.flush().await?;
282+
}
283+
Ok::<_, std::io::Error>(())
284+
}
285+
.await
286+
{
287+
Ok(_) => Ok(()),
288+
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => Ok(()),
289+
Err(e) => Err(e.into()),
280290
}
281-
Ok(())
282291
}
283292

284293
use std::io::IsTerminal;

0 commit comments

Comments
 (0)