@derivation/rpc 0.1.6 → 0.1.8

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.
Files changed (41) hide show
  1. package/dist/client-handler.d.ts +12 -11
  2. package/dist/client-handler.js +19 -13
  3. package/dist/client.d.ts +4 -3
  4. package/dist/client.js +8 -8
  5. package/dist/index.d.ts +7 -7
  6. package/dist/index.js +6 -6
  7. package/dist/iso.d.ts +1 -1
  8. package/dist/iso.js +1 -1
  9. package/dist/messageport-transport.d.ts +13 -0
  10. package/dist/messageport-transport.js +28 -0
  11. package/dist/node-web-socket-transport.d.ts +16 -0
  12. package/dist/node-web-socket-transport.js +33 -0
  13. package/dist/queue.d.ts +9 -0
  14. package/dist/queue.js +32 -0
  15. package/dist/rate-limiter.d.ts +1 -1
  16. package/dist/rate-limiter.js +13 -8
  17. package/dist/reactive-map-adapter.d.ts +4 -3
  18. package/dist/reactive-map-adapter.js +3 -2
  19. package/dist/reactive-set-adapter.d.ts +4 -3
  20. package/dist/reactive-set-adapter.js +3 -2
  21. package/dist/shared-worker-client-handler.d.ts +27 -0
  22. package/dist/shared-worker-client-handler.js +149 -0
  23. package/dist/shared-worker-client.d.ts +22 -0
  24. package/dist/shared-worker-client.js +25 -0
  25. package/dist/shared-worker-server.d.ts +28 -0
  26. package/dist/shared-worker-server.js +62 -0
  27. package/dist/stream-adapter.d.ts +2 -2
  28. package/dist/stream-adapter.js +2 -1
  29. package/dist/stream-types.d.ts +4 -4
  30. package/dist/transport.d.ts +27 -0
  31. package/dist/transport.js +1 -0
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/dist/web-socket-server.d.ts +11 -0
  34. package/dist/web-socket-server.js +59 -0
  35. package/dist/web-socket-transport.d.ts +13 -0
  36. package/dist/web-socket-transport.js +25 -0
  37. package/dist/websocket-server.d.ts +8 -2
  38. package/dist/websocket-server.js +29 -5
  39. package/dist/websocket-transport.d.ts +28 -0
  40. package/dist/websocket-transport.js +58 -0
  41. package/package.json +23 -2
@@ -0,0 +1,22 @@
1
+ import { Graph } from "derivation";
2
+ import { Client } from "./client.js";
3
+ import { StreamSinks, RPCDefinition } from "./stream-types.js";
4
+ /**
5
+ * Create a client connected to a SharedWorker.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // main.ts
10
+ * const graph = new Graph();
11
+ * const worker = new SharedWorker('/worker.js');
12
+ *
13
+ * const client = createSharedWorkerClient(worker.port, {
14
+ * streams: {
15
+ * todos: setSink(graph, todoIso),
16
+ * },
17
+ * }, graph);
18
+ *
19
+ * const todos = await client.run('todos', { filter: 'active' });
20
+ * ```
21
+ */
22
+ export declare function createSharedWorkerClient<Defs extends RPCDefinition>(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph): Client<Defs>;
@@ -0,0 +1,25 @@
1
+ import { Client } from "./client.js";
2
+ import { MessagePortTransport } from "./messageport-transport.js";
3
+ /**
4
+ * Create a client connected to a SharedWorker.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // main.ts
9
+ * const graph = new Graph();
10
+ * const worker = new SharedWorker('/worker.js');
11
+ *
12
+ * const client = createSharedWorkerClient(worker.port, {
13
+ * streams: {
14
+ * todos: setSink(graph, todoIso),
15
+ * },
16
+ * }, graph);
17
+ *
18
+ * const todos = await client.run('todos', { filter: 'active' });
19
+ * ```
20
+ */
21
+ export function createSharedWorkerClient(port, sinks, graph) {
22
+ const transport = new MessagePortTransport(port);
23
+ port.start();
24
+ return new Client(transport, sinks, graph);
25
+ }
@@ -0,0 +1,28 @@
1
+ import { Graph } from "derivation";
2
+ import { StreamEndpoints, MutationEndpoints, RPCDefinition } from "./stream-types.js";
3
+ import { PresenceHandler } from "./presence-manager.js";
4
+ export type SharedWorkerServerOptions<Defs extends RPCDefinition, Ctx = void> = {
5
+ streams: StreamEndpoints<Defs["streams"], Ctx>;
6
+ mutations: MutationEndpoints<Defs["mutations"], Ctx>;
7
+ createContext: (port: MessagePort) => Ctx | Promise<Ctx>;
8
+ presenceHandler?: PresenceHandler;
9
+ };
10
+ /**
11
+ * Set up a SharedWorker server for RPC communication.
12
+ * This creates a shared Graph that all connected tabs can interact with.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // worker.ts
17
+ * const { graph } = setupSharedWorker({
18
+ * streams: {
19
+ * todos: async (args, ctx) => new ReactiveSetSourceAdapter(source),
20
+ * },
21
+ * mutations: {
22
+ * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
23
+ * },
24
+ * createContext: (port) => ({ portId: crypto.randomUUID() }),
25
+ * });
26
+ * ```
27
+ */
28
+ export declare function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(options: SharedWorkerServerOptions<Defs, Ctx>, graph: Graph): void;
@@ -0,0 +1,62 @@
1
+ import { SharedWorkerClientHandler } from "./shared-worker-client-handler.js";
2
+ import WeakList from "./weak-list.js";
3
+ import { MessagePortTransport } from "./messageport-transport.js";
4
+ /**
5
+ * Set up a SharedWorker server for RPC communication.
6
+ * This creates a shared Graph that all connected tabs can interact with.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // worker.ts
11
+ * const { graph } = setupSharedWorker({
12
+ * streams: {
13
+ * todos: async (args, ctx) => new ReactiveSetSourceAdapter(source),
14
+ * },
15
+ * mutations: {
16
+ * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
17
+ * },
18
+ * createContext: (port) => ({ portId: crypto.randomUUID() }),
19
+ * });
20
+ * ```
21
+ */
22
+ export function setupSharedWorker(options, graph) {
23
+ const { streams, mutations, createContext, presenceHandler } = options;
24
+ const clients = new WeakList();
25
+ // After each graph step, broadcast deltas to all connected clients
26
+ graph.afterStep(() => {
27
+ for (const client of clients) {
28
+ client.handleStep();
29
+ }
30
+ });
31
+ // Handle SharedWorker connections
32
+ const globalScope = self;
33
+ globalScope.onconnect = (event) => {
34
+ const port = event.ports[0];
35
+ const messageBuffer = [];
36
+ let client = null;
37
+ // Set up temporary message handler to buffer messages
38
+ const tempMessageHandler = (e) => {
39
+ messageBuffer.push(e.data);
40
+ };
41
+ port.onmessage = tempMessageHandler;
42
+ // Create context (handle both sync and async)
43
+ Promise.resolve(createContext(port))
44
+ .then((context) => {
45
+ // Create transport and client handler
46
+ const transport = new MessagePortTransport(port);
47
+ client = new SharedWorkerClientHandler(transport, context, streams, mutations, presenceHandler);
48
+ clients.add(client);
49
+ // Process buffered messages
50
+ for (const msg of messageBuffer) {
51
+ client.handleMessage(msg);
52
+ }
53
+ messageBuffer.length = 0;
54
+ // Start the port
55
+ port.start();
56
+ })
57
+ .catch((err) => {
58
+ console.error("Error creating context:", err);
59
+ port.close();
60
+ });
61
+ };
62
+ }
@@ -1,6 +1,6 @@
1
1
  import { Graph, ReactiveValue, Input } from "derivation";
2
- import { Source, Sink } from "./stream-types";
3
- import { Iso } from "./iso";
2
+ import { Source, Sink } from "./stream-types.js";
3
+ import { Iso } from "./iso.js";
4
4
  export declare class StreamSourceAdapter<T extends object> implements Source<ReactiveValue<T>> {
5
5
  private readonly stream;
6
6
  private readonly iso;
@@ -1,3 +1,4 @@
1
+ import { inputValue } from "derivation";
1
2
  export class StreamSourceAdapter {
2
3
  constructor(stream, iso) {
3
4
  this.stream = stream;
@@ -23,7 +24,7 @@ export class StreamSinkAdapter {
23
24
  input.push(this.iso.from(change));
24
25
  }
25
26
  build() {
26
- const stream = this.graph.inputValue(this.initialValue);
27
+ const stream = inputValue(this.graph, this.initialValue);
27
28
  return { stream, input: stream };
28
29
  }
29
30
  }
@@ -17,8 +17,8 @@ export type StreamDefinition<Args extends object, ReturnType extends object, Sin
17
17
  inputType: InputType;
18
18
  };
19
19
  export type StreamDefinitions = Record<string, StreamDefinition<object, object, object, object>>;
20
- export type StreamEndpoints<Definitions extends StreamDefinitions> = {
21
- [K in keyof Definitions]: (args: Definitions[K]["args"]) => Source<Definitions[K]["returnType"]>;
20
+ export type StreamEndpoints<Definitions extends StreamDefinitions, Ctx = void> = {
21
+ [K in keyof Definitions]: (args: Definitions[K]["args"], ctx: Ctx) => Promise<Source<Definitions[K]["returnType"]>>;
22
22
  };
23
23
  export type StreamSinks<Definitions extends StreamDefinitions> = {
24
24
  [K in keyof Definitions]: (snapshot: object) => Sink<Definitions[K]["sinkType"], Definitions[K]["inputType"]>;
@@ -35,8 +35,8 @@ export type MutationDefinition<Args, Result> = {
35
35
  result: Result;
36
36
  };
37
37
  export type MutationDefinitions = Record<string, MutationDefinition<unknown, unknown>>;
38
- export type MutationEndpoints<Definitions extends MutationDefinitions> = {
39
- [K in keyof Definitions]: (args: Definitions[K]["args"]) => Promise<MutationResult<Definitions[K]["result"]>>;
38
+ export type MutationEndpoints<Definitions extends MutationDefinitions, Ctx = void> = {
39
+ [K in keyof Definitions]: (args: Definitions[K]["args"], ctx: Ctx) => Promise<MutationResult<Definitions[K]["result"]>>;
40
40
  };
41
41
  export type RPCDefinition = {
42
42
  streams: StreamDefinitions;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Transport abstraction for RPC communication.
3
+ * Allows the same RPC system to work over WebSocket or MessagePort.
4
+ */
5
+ export interface Transport {
6
+ /**
7
+ * Send a string message through the transport.
8
+ */
9
+ send(data: string): void;
10
+ /**
11
+ * Register a handler for incoming messages.
12
+ */
13
+ onMessage(handler: (data: string) => void): void;
14
+ /**
15
+ * Register a handler for transport closure/disconnection.
16
+ */
17
+ onClose(handler: () => void): void;
18
+ /**
19
+ * Close the transport connection.
20
+ */
21
+ close(): void;
22
+ /**
23
+ * Number of bytes buffered to be sent (optional, used for flow control).
24
+ * MessagePort doesn't provide this, so it's optional.
25
+ */
26
+ readonly bufferedAmount?: number;
27
+ }
@@ -0,0 +1 @@
1
+ export {};