Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c3fdf5e
reboot: support the `PUT` method for custom HTTP routes
rjhuijsman Jul 5, 2026
286dcfe
reboot: run library `pre_run` hooks in the test harness
rjhuijsman Jul 5, 2026
8fd6921
`reboot/std`: add a `Blob` state machine
rjhuijsman Jul 7, 2026
e2d4aec
rbt: run the filesystem blob data plane under `dev`/`serve run`
rjhuijsman Jul 7, 2026
f187aa9
reboot/std/react: add browser helpers for blob upload and download
rjhuijsman Jul 5, 2026
6f904f0
reboot/examples/chat-room: support message attachments
rjhuijsman Jul 5, 2026
2f1baee
fixup! `reboot/std`: add a `Blob` state machine
rjhuijsman Aug 3, 2026
45d2256
fixup! reboot: run library `pre_run` hooks in the test harness
rjhuijsman Aug 3, 2026
505ad23
fixup! reboot: support the `PUT` method for custom HTTP routes
rjhuijsman Aug 3, 2026
8a60e95
fixup! rbt: run the filesystem blob data plane under `dev`/`serve run`
rjhuijsman Aug 3, 2026
3c4a643
fixup! reboot/std/react: add browser helpers for blob upload and down…
rjhuijsman Aug 3, 2026
1714e03
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 3, 2026
824a54a
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 3, 2026
622e4c8
fixup! `reboot/std`: add a `Blob` state machine
rjhuijsman Aug 3, 2026
afbe90d
fixup! `reboot/std`: add a `Blob` state machine
rjhuijsman Aug 3, 2026
83434d4
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 3, 2026
adf71c8
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 3, 2026
8972b8b
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 3, 2026
5f06d89
fixup! `reboot/std`: add a `Blob` state machine
rjhuijsman Aug 4, 2026
0de2dc0
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 4, 2026
842a135
fixup! reboot/examples/chat-room: support message attachments
rjhuijsman Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions documentation/docs/learn_more/applications.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ Your entrypoint will construct an `Application` and then `run` it:
<Tabs groupId="language">
<TabItem value="python" label="Python">
<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../reboot/examples/chat-room/backend/src/main.py&lines=25-33) -->
(CODE:src=../../../reboot/examples/chat-room/backend/src/main.py&lines=26-34) -->
<!-- The below code snippet is automatically added from ../../../reboot/examples/chat-room/backend/src/main.py -->

```py
async def main():
await Application(
servicers=[ChatRoomServicer],
# Message attachments are stored as blobs; `rbt dev run` and
# `rbt serve run` provide a local filesystem data plane (see
# `REBOOT_BLOB_DATA_PLANE_URL` for using a custom one).
libraries=[blob_library()],
initialize=initialize,
).run()


if __name__ == '__main__':
asyncio.run(main())
```

<!-- MARKDOWN-AUTO-DOCS:END -->
Expand Down Expand Up @@ -59,7 +59,7 @@ instances used by your application are created.
<Tabs groupId="language">
<TabItem value="python" label="Python">
<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../reboot/examples/chat-room/backend/src/main.py&lines=13-20) -->
(CODE:src=../../../reboot/examples/chat-room/backend/src/main.py&lines=14-21) -->
<!-- The below code snippet is automatically added from ../../../reboot/examples/chat-room/backend/src/main.py -->

```py
Expand Down Expand Up @@ -133,7 +133,7 @@ implemented with [Express.js](https://expressjs.com/).

**Limitations of custom HTTP routes**

* Currently only `GET` and `POST` methods are supported.
* Currently only `GET`, `POST`, and `PUT` methods are supported.

* The `/` route is currently used by Reboot itself to
show a helpful page explaining that this is a Reboot
Expand Down
94 changes: 66 additions & 28 deletions documentation/docs/learn_more/call/from_react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,33 @@ api = API(
</TabItem>
<TabItem value="proto" label="Proto">
<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&&lines=9-41&syntax=protobuf) -->
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&&lines=9-51&syntax=protobuf) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto -->

```protobuf
// Raised when a requested attachment exceeds the chat room's
// per-attachment size limit.
message AttachmentTooLarge {
// The maximum allowed attachment size, in bytes, so the client can
// show a helpful message.
uint64 max_size_bytes = 1;
}

message Message {
string text = 1;

// IDs of `rbt.std.blob.v1.Blob`s holding this message's
// attachments. Attachments are visible to all participants from the
// moment the message is sent, while their bytes may still be
// uploading; render their progress reactively via `Blob.Info`.
repeated string attachment_blob_ids = 2;
}

message ChatRoom {
option (rbt.v1alpha1.state) = {
};
repeated string messages = 1;
reserved 1;
repeated Message messages = 2;
}

service ChatRoomMethods {
Expand All @@ -117,24 +136,17 @@ service ChatRoomMethods {
};
}

// Adds a new message to the list of recorded messages.
// Adds a new message to the list of recorded messages, creating a
// `Blob` for each requested attachment. The message is published
// immediately; the caller then uploads the attachment bytes into
// the returned blob IDs.
rpc Send(SendRequest) returns (SendResponse) {
option (rbt.v1alpha1.method).writer = {
option (rbt.v1alpha1.method) = {
transaction: {},
errors: [ "AttachmentTooLarge" ],
};
}
}

message MessagesRequest {}

message MessagesResponse {
repeated string messages = 1;
}

message SendRequest {
string message = 1; // E.g. "Hello, World".
}

message SendResponse {}
```

<!-- MARKDOWN-AUTO-DOCS:END -->
Expand Down Expand Up @@ -317,7 +329,7 @@ export const DashboardApp: FC<DashboardConfig> = ({ personalizedMessage }) => {
You can call a `reader` _reactively_ very simply:

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=33-34) -->
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=160-161) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/frontend/web/src/App.tsx -->

```tsx
Expand Down Expand Up @@ -346,7 +358,7 @@ and [`transaction`](/learn_more/define/methods#kinds) methods
are both callable from React.

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=33-33) -->
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=160-160) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/frontend/web/src/App.tsx -->

```tsx
Expand All @@ -363,11 +375,17 @@ This line calls the
in the `.proto` as `Send`, using the lower camel case name `send`:

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=37-37) -->
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=181-187) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/frontend/web/src/App.tsx -->

```tsx
const { aborted } = await send({ message: message });
const { response, aborted } = await send({
message: message,
attachments:
file !== null
? [{ contentType: file.type, sizeBytes: BigInt(file.size) }]
: [],
});
```

<!-- MARKDOWN-AUTO-DOCS:END -->
Expand All @@ -384,12 +402,17 @@ Reboot attaches all in-flight mutations to a `.pending` property of every mutato
facilitate this, for example:

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=81-83) -->
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=306-313) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/frontend/web/src/App.tsx -->

```tsx
{send.pending.map(({ request: { message }, isLoading }) => (
<PendingMessage text={message} isLoading={isLoading} key={message} />
{send.pending.map(({ request, isLoading }, index) => (
<PendingMessage
text={request.message ?? ""}
attachmentCount={request.attachments?.length ?? 0}
isLoading={isLoading}
key={index}
/>
))}
```

Expand All @@ -416,15 +439,30 @@ Every call to a mutator returns both a `response` and an `aborted`; successful c
[Learn more about Reboot errors and error types.](/learn_more/errors)

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=37-41) -->
(CODE:src=../../../../reboot/examples/chat-room/frontend/web/src/App.tsx&&lines=181-200) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/frontend/web/src/App.tsx -->

```tsx
const { aborted } = await send({ message: message });
const { response, aborted } = await send({
message: message,
attachments:
file !== null
? [{ contentType: file.type, sizeBytes: BigInt(file.size) }]
: [],
});
if (aborted !== undefined) {
console.warn(aborted.error.getType());
console.warn(aborted.message);
}
// Surface the failure to the user. The backend's
// `AttachmentTooLarge` error carries the limit, so we can say
// exactly what it is.
if (aborted.error instanceof AttachmentTooLarge) {
const maxMebibytes = Number(aborted.error.maxSizeBytes) / (1024 * 1024);
setError(
`That attachment is too large. The maximum is ${maxMebibytes} MiB.`
);
} else {
setError(`Couldn't send your message: ${aborted.message}`);
}
return;
```

<!-- MARKDOWN-AUTO-DOCS:END -->
Expand Down
13 changes: 7 additions & 6 deletions documentation/docs/learn_more/call/from_within_your_app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,15 @@ via `write()` — see
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/backend/src/chat_room_servicer.py -->

```py
self,
context: ReaderContext,
request: MessagesRequest,
) -> MessagesResponse:
return MessagesResponse(messages=self.state.messages)

async def send(
self,
context: WriterContext,
request: SendRequest,
) -> SendResponse:
message = request.message
self.state.messages.extend([message])
return SendResponse()
context: TransactionContext,
```

<!-- MARKDOWN-AUTO-DOCS:END -->
Expand Down
16 changes: 11 additions & 5 deletions documentation/docs/learn_more/define/protobuf.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ To declare a data type called `ChatRoom`, put the following in a `.proto`
file:

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&lines=9-13&syntax=protobuf) -->
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&lines=27-32&syntax=protobuf) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto -->

```protobuf
message ChatRoom {
option (rbt.v1alpha1.state) = {
};
repeated string messages = 1;
reserved 1;
repeated Message messages = 2;
}
```

Expand All @@ -32,7 +33,7 @@ In addition to defining the data type, you'll also need to define
operations for that type, for example:

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&lines=14-27&syntax=protobuf) -->
(CODE:src=../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto&lines=34-51&syntax=protobuf) -->
<!-- The below code snippet is automatically added from ../../../../reboot/examples/chat-room/api/chat_room/v1/chat_room.proto -->

```protobuf
Expand All @@ -43,9 +44,14 @@ service ChatRoomMethods {
};
}

// Adds a new message to the list of recorded messages.
// Adds a new message to the list of recorded messages, creating a
// `Blob` for each requested attachment. The message is published
// immediately; the caller then uploads the attachment bytes into
// the returned blob IDs.
rpc Send(SendRequest) returns (SendResponse) {
option (rbt.v1alpha1.method).writer = {
option (rbt.v1alpha1.method) = {
transaction: {},
errors: [ "AttachmentTooLarge" ],
};
}
}
Expand Down
9 changes: 6 additions & 3 deletions documentation/docs/learn_more/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ you to start your servicer, create a context, and call the method you want to
test.

<!-- MARKDOWN-AUTO-DOCS:START
(CODE:src=../../../reboot/examples/chat-room/backend/tests/chat_room_servicer_test.py&lines=10-40) -->
(CODE:src=../../../reboot/examples/chat-room/backend/tests/chat_room_servicer_test.py&lines=10-42) -->
<!-- The below code snippet is automatically added from ../../../reboot/examples/chat-room/backend/tests/chat_room_servicer_test.py -->

```py
Expand All @@ -33,13 +33,16 @@ async def test_chat_room(self) -> None:
await chat_room.send(context, message="Hello, World")

response: ChatRoom.MessagesResponse = await chat_room.messages(context)
self.assertEqual(response.messages, ["Hello, World"])
self.assertEqual(
[message.text for message in response.messages],
["Hello, World"],
)

await chat_room.send(context, message="Hello, Reboot!")
await chat_room.send(context, message="Hello, Peace of Mind!")
response = await chat_room.messages(context)
self.assertEqual(
response.messages,
[message.text for message in response.messages],
[
"Hello, World",
"Hello, Reboot!",
Expand Down
3 changes: 3 additions & 0 deletions rbt/std/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ ts_project(
},
visibility = ["//visibility:public"],
deps = [
"//rbt/std/blob/v1:blob_js_proto",
"//rbt/std/blob/v1:blob_js_reboot",
"//rbt/std/blob/v1:blob_js_reboot_react",
"//rbt/std/ciphertext/v1:ciphertext_js_proto",
"//rbt/std/ciphertext/v1:ciphertext_js_reboot",
"//rbt/std/collections/ordered_map/v1:ordered_map_js_proto",
Expand Down
Loading
Loading