Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

Commit 5ca9a59

Browse files
Split TypeScript into workspace packages
- roam-core: browser + node compatible (binary, postcard, streaming) - roam-tcp: node-only TCP transport - generated: codegen output for echo and streaming services - subject: compliance test subject Updates codegen to avoid unreachable code in stub handlers.
1 parent aeb8ec2 commit 5ca9a59

37 files changed

Lines changed: 288 additions & 80 deletions

rust/roam-codegen/src/targets/typescript.rs

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ pub fn generate_service(service: &ServiceDetail) -> String {
2929
out.push_str("// @generated by roam-codegen\n");
3030
out.push_str("// DO NOT EDIT - regenerate with `cargo xtask codegen --typescript`\n\n");
3131

32-
// Import runtime primitives
33-
out.push_str("import type { MethodHandler } from \"../src/index.ts\";\n");
34-
out.push_str("import { encodeResultOk, encodeResultErr, encodeInvalidPayload } from \"../src/index.ts\";\n");
35-
out.push_str("import { encodeString, decodeString } from \"../src/index.ts\";\n");
32+
// Import runtime primitives from @bearcove/roam-core
33+
out.push_str("import type { MethodHandler } from \"@bearcove/roam-core\";\n");
34+
out.push_str("import { encodeResultOk, encodeResultErr, encodeInvalidPayload } from \"@bearcove/roam-core\";\n");
35+
out.push_str("import { encodeString, decodeString } from \"@bearcove/roam-core\";\n");
3636

3737
// Check if any method uses streaming
3838
let has_streaming = service
@@ -41,7 +41,7 @@ pub fn generate_service(service: &ServiceDetail) -> String {
4141
.any(|m| m.args.iter().any(|a| is_stream(&a.type_info)) || is_stream(&m.return_type));
4242

4343
if has_streaming {
44-
out.push_str("import type { Push, Pull, StreamId } from \"../src/index.ts\";\n");
44+
out.push_str("import type { Push, Pull, StreamId } from \"@bearcove/roam-core\";\n");
4545
}
4646
out.push('\n');
4747

@@ -185,41 +185,35 @@ fn generate_server_interface(service: &ServiceDetail) -> String {
185185
));
186186
out.push_str(" try {\n");
187187

188-
// Decode arguments
189-
if method.args.len() == 1 && matches!(method.args[0].type_info, TypeDetail::String) {
188+
// Check if we can fully implement this method
189+
let can_decode_args =
190+
method.args.len() == 1 && matches!(method.args[0].type_info, TypeDetail::String);
191+
let can_encode_return = matches!(method.return_type, TypeDetail::String);
192+
193+
if can_decode_args && can_encode_return {
190194
// Single string argument - simple case for Echo service
191195
out.push_str(" const decoded = decodeString(payload, 0);\n");
192196
out.push_str(" if (decoded.next !== payload.length) throw new Error(\"args: trailing bytes\");\n");
193197
let arg_name = method.args[0].name.to_lower_camel_case();
194198
out.push_str(&format!(" const {arg_name} = decoded.value;\n"));
195-
} else {
196-
// TODO: Handle other argument types
197-
out.push_str(" // TODO: decode arguments for complex types\n");
198-
out.push_str(
199-
" throw new Error(\"Complex argument decoding not yet implemented\");\n",
200-
);
201-
}
202199

203-
// Call handler
204-
let arg_names = method
205-
.args
206-
.iter()
207-
.map(|a| a.name.to_lower_camel_case())
208-
.collect::<Vec<_>>()
209-
.join(", ");
210-
out.push_str(&format!(
211-
" const result = await handler.{method_name}({arg_names});\n"
212-
));
200+
// Call handler
201+
let arg_names = method
202+
.args
203+
.iter()
204+
.map(|a| a.name.to_lower_camel_case())
205+
.collect::<Vec<_>>()
206+
.join(", ");
207+
out.push_str(&format!(
208+
" const result = await handler.{method_name}({arg_names});\n"
209+
));
213210

214-
// Encode response
215-
if matches!(method.return_type, TypeDetail::String) {
211+
// Encode response
216212
out.push_str(" return encodeResultOk(encodeString(result));\n");
217213
} else {
218-
// TODO: Handle other return types
219-
out.push_str(" // TODO: encode response for complex types\n");
220-
out.push_str(
221-
" throw new Error(\"Complex response encoding not yet implemented\");\n",
222-
);
214+
// Not yet implemented - return error
215+
out.push_str(" // TODO: implement encoding/decoding for complex types\n");
216+
out.push_str(" return encodeResultErr(encodeInvalidPayload());\n");
223217
}
224218

225219
out.push_str(" } catch (e) {\n");

typescript/generated/echo.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// @generated by roam-codegen
22
// DO NOT EDIT - regenerate with `cargo xtask codegen --typescript`
33

4-
import type { MethodHandler } from "../src/index.ts";
5-
import { encodeResultOk, encodeResultErr, encodeInvalidPayload } from "../src/index.ts";
6-
import { encodeString, decodeString } from "../src/index.ts";
4+
import type { MethodHandler } from "@bearcove/roam-core";
5+
import { encodeResultOk, encodeResultErr, encodeInvalidPayload } from "@bearcove/roam-core";
6+
import { encodeString, decodeString } from "@bearcove/roam-core";
77

88
export const METHOD_ID = {
99
echo: 0x3d66dd9ee36b4240n,

typescript/generated/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@bearcove/roam-generated",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"exports": {
7+
"./*.ts": "./*.ts"
8+
},
9+
"scripts": {
10+
"check": "pnpx --package @typescript/native-preview tsgo --noEmit"
11+
},
12+
"dependencies": {
13+
"@bearcove/roam-core": "workspace:*"
14+
}
15+
}

typescript/generated/streaming.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// @generated by roam-codegen
2+
// DO NOT EDIT - regenerate with `cargo xtask codegen --typescript`
3+
4+
import type { MethodHandler } from "@bearcove/roam-core";
5+
import { encodeResultOk, encodeResultErr, encodeInvalidPayload } from "@bearcove/roam-core";
6+
import { encodeString, decodeString } from "@bearcove/roam-core";
7+
import type { Push, Pull, StreamId } from "@bearcove/roam-core";
8+
9+
export const METHOD_ID = {
10+
sum: 0x09e710c9cb34ef40n,
11+
range: 0x082b800b771a1679n,
12+
pipe: 0x92cdb59bb5df3977n,
13+
stats: 0xc416b4ee044521dcn,
14+
} as const;
15+
16+
// Type definitions
17+
export type SumRequest = [/* stream */ number];
18+
export type SumResponse = bigint;
19+
20+
export type RangeRequest = [number];
21+
export type RangeResponse = /* stream */ number;
22+
23+
export type PipeRequest = [/* stream */ string];
24+
export type PipeResponse = /* stream */ string;
25+
26+
export type StatsRequest = [/* stream */ number];
27+
export type StatsResponse = [bigint, bigint, number];
28+
29+
// Client interface for Streaming
30+
export interface StreamingClient {
31+
/** Client pushes numbers, server returns their sum.
32+
33+
Tests: client-to-server streaming (`Push<T>` → scalar return).
34+
r[impl streaming.client-to-server] - Client sends stream, server returns scalar. */
35+
sum(numbers: Push<number>): Promise<bigint>;
36+
/** Client sends a count, server returns that many numbers.
37+
38+
Tests: server-to-client streaming (scalar → `Pull<T>`).
39+
r[impl streaming.server-to-client] - Client sends scalar, server returns stream. */
40+
range(count: number): Promise<Pull<number>>;
41+
/** Client pushes strings, server echoes each back.
42+
43+
Tests: bidirectional streaming (`Push<T>` ↔ `Pull<T>`).
44+
r[impl streaming.bidirectional] - Both sides stream simultaneously. */
45+
pipe(input: Push<string>): Promise<Pull<string>>;
46+
/** Client pushes numbers, server returns (sum, count, average).
47+
48+
Tests: aggregating a stream into a compound result. */
49+
stats(numbers: Push<number>): Promise<[bigint, bigint, number]>;
50+
}
51+
52+
// Server handler interface for Streaming
53+
export interface StreamingHandler {
54+
sum(numbers: Pull<number>): Promise<bigint> | bigint;
55+
range(count: number): Promise<Push<number>> | Push<number>;
56+
pipe(input: Pull<string>): Promise<Push<string>> | Push<string>;
57+
stats(numbers: Pull<number>): Promise<[bigint, bigint, number]> | [bigint, bigint, number];
58+
}
59+
60+
// Method handlers for Streaming
61+
export const streaming_methodHandlers = new Map<bigint, MethodHandler<StreamingHandler>>([
62+
[0x09e710c9cb34ef40n, async (handler, payload) => {
63+
try {
64+
// TODO: implement encoding/decoding for complex types
65+
return encodeResultErr(encodeInvalidPayload());
66+
} catch (e) {
67+
return encodeResultErr(encodeInvalidPayload());
68+
}
69+
}],
70+
[0x082b800b771a1679n, async (handler, payload) => {
71+
try {
72+
// TODO: implement encoding/decoding for complex types
73+
return encodeResultErr(encodeInvalidPayload());
74+
} catch (e) {
75+
return encodeResultErr(encodeInvalidPayload());
76+
}
77+
}],
78+
[0x92cdb59bb5df3977n, async (handler, payload) => {
79+
try {
80+
// TODO: implement encoding/decoding for complex types
81+
return encodeResultErr(encodeInvalidPayload());
82+
} catch (e) {
83+
return encodeResultErr(encodeInvalidPayload());
84+
}
85+
}],
86+
[0xc416b4ee044521dcn, async (handler, payload) => {
87+
try {
88+
// TODO: implement encoding/decoding for complex types
89+
return encodeResultErr(encodeInvalidPayload());
90+
} catch (e) {
91+
return encodeResultErr(encodeInvalidPayload());
92+
}
93+
}],
94+
]);

typescript/generated/tsconfig.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2022",
4+
"module": "ES2022",
5+
"moduleResolution": "Bundler",
6+
"lib": ["ES2022", "DOM"],
7+
"allowImportingTsExtensions": true,
8+
"strict": true,
9+
"noEmit": true
10+
},
11+
"include": ["*.ts"]
12+
}

typescript/package-lock.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

typescript/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"check": "pnpx --package @typescript/native-preview tsgo --noEmit"
7-
},
8-
"devDependencies": {
9-
"@types/node": "^22"
6+
"check": "pnpm -r run check"
107
}
118
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "@bearcove/roam-core",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"exports": {
7+
".": "./src/index.ts"
8+
},
9+
"scripts": {
10+
"check": "pnpx --package @typescript/native-preview tsgo --noEmit"
11+
}
12+
}
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)