@agent-glue/glue 0.1.0

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 (51) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-clean$colon$build.log +1 -0
  3. package/.turbo/turbo-format$colon$fix.log +46 -0
  4. package/.turbo/turbo-format.log +13 -0
  5. package/.turbo/turbo-lint$colon$fix.log +9 -0
  6. package/.turbo/turbo-lint.log +5 -0
  7. package/.turbo/turbo-test.log +27 -0
  8. package/.turbo/turbo-typecheck.log +5 -0
  9. package/CHANGELOG.md +7 -0
  10. package/LICENSE +21 -0
  11. package/dist/Actor.d.ts +51 -0
  12. package/dist/Actor.js +30 -0
  13. package/dist/actor.js +32 -0
  14. package/dist/actors/examples/timer.d.ts +1 -0
  15. package/dist/actors/examples/timer.js +1 -0
  16. package/dist/actors/langchain/llm.d.ts +40 -0
  17. package/dist/actors/langchain/llm.js +52 -0
  18. package/dist/constructors.js +1 -0
  19. package/dist/effects.js +66 -0
  20. package/dist/emitter.js +19 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/message.js +18 -0
  24. package/dist/message.test.js +37 -0
  25. package/dist/server/memory.js +46 -0
  26. package/dist/server/protocol.js +4 -0
  27. package/dist/server/websocket.js +72 -0
  28. package/dist/server.js +3 -0
  29. package/dist/transformers.d.ts +41 -0
  30. package/dist/transformers.js +17 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -0
  32. package/dist/types.js +1 -0
  33. package/dist/utils/TypedEmitter.d.ts +15 -0
  34. package/dist/utils/TypedEmitter.js +16 -0
  35. package/eslint.config.js +4 -0
  36. package/nodemon.json +7 -0
  37. package/package.json +75 -0
  38. package/src/actor.ts +69 -0
  39. package/src/effects.ts +88 -0
  40. package/src/emitter.ts +22 -0
  41. package/src/index.ts +1 -0
  42. package/src/message.test.ts +52 -0
  43. package/src/message.ts +54 -0
  44. package/src/server/memory.ts +77 -0
  45. package/src/server/protocol.ts +36 -0
  46. package/src/server/websocket.ts +137 -0
  47. package/src/server.ts +3 -0
  48. package/src/transformers.ts +66 -0
  49. package/src/types.ts +7 -0
  50. package/src/utils/TypedEmitter.ts +30 -0
  51. package/tsconfig.json +8 -0
@@ -0,0 +1,5 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 build /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > tsc
5
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,46 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 format:fix /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > prettier --write .
5
+
6
+ CHANGELOG.mdCHANGELOG.md 44ms
7
+ dist/Actor.d.tsdist/Actor.d.ts 233ms
8
+ dist/actor.jsdist/actor.js 66ms
9
+ dist/Actor.jsdist/Actor.js 9ms
10
+ dist/actors/examples/timer.d.tsdist/actors/examples/timer.d.ts 4ms
11
+ dist/actors/examples/timer.jsdist/actors/examples/timer.js 2ms
12
+ dist/actors/langchain/llm.d.tsdist/actors/langchain/llm.d.ts 19ms
13
+ dist/actors/langchain/llm.jsdist/actors/langchain/llm.js 24ms
14
+ dist/constructors.jsdist/constructors.js 4ms
15
+ dist/effects.jsdist/effects.js 18ms
16
+ dist/emitter.jsdist/emitter.js 7ms
17
+ dist/index.d.tsdist/index.d.ts 4ms
18
+ dist/index.jsdist/index.js 2ms
19
+ dist/message.jsdist/message.js 5ms
20
+ dist/message.test.jsdist/message.test.js 10ms
21
+ dist/server.jsdist/server.js 2ms
22
+ dist/server/memory.jsdist/server/memory.js 10ms
23
+ dist/server/protocol.jsdist/server/protocol.js 4ms
24
+ dist/server/websocket.jsdist/server/websocket.js 14ms
25
+ dist/transformers.d.tsdist/transformers.d.ts 14ms
26
+ dist/transformers.jsdist/transformers.js 4ms
27
+ dist/types.jsdist/types.js 2ms
28
+ dist/utils/TypedEmitter.d.tsdist/utils/TypedEmitter.d.ts 6ms
29
+ dist/utils/TypedEmitter.jsdist/utils/TypedEmitter.js 2ms
30
+ eslint.config.jseslint.config.js 3ms
31
+ nodemon.jsonnodemon.json 3ms
32
+ package.jsonpackage.json 3ms
33
+ src/actor.tssrc/actor.ts 22ms
34
+ src/effects.tssrc/effects.ts 23ms
35
+ src/emitter.tssrc/emitter.ts 10ms
36
+ src/index.tssrc/index.ts 2ms
37
+ src/message.test.tssrc/message.test.ts 16ms
38
+ src/message.tssrc/message.ts 14ms
39
+ src/server.tssrc/server.ts 2ms
40
+ src/server/memory.tssrc/server/memory.ts 18ms
41
+ src/server/protocol.tssrc/server/protocol.ts 7ms
42
+ src/server/websocket.tssrc/server/websocket.ts 23ms
43
+ src/transformers.tssrc/transformers.ts 10ms
44
+ src/types.tssrc/types.ts 3ms
45
+ src/utils/TypedEmitter.tssrc/utils/TypedEmitter.ts 5ms
46
+ tsconfig.jsontsconfig.json 2ms
@@ -0,0 +1,13 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 format /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > prettier --check .
5
+
6
+ Checking formatting...
7
+ CHANGELOG.mddist/Actor.d.tsdist/actor.js[warn] dist/actor.js
8
+ dist/Actor.js[warn] dist/Actor.js
9
+ dist/actors/examples/timer.d.tsdist/actors/examples/timer.jsdist/actors/langchain/llm.d.tsdist/actors/langchain/llm.jsdist/constructors.jsdist/effects.js[warn] dist/effects.js
10
+ dist/emitter.js[warn] dist/emitter.js
11
+ dist/index.d.tsdist/index.jsdist/message.js[warn] dist/message.js
12
+ dist/message.test.js[warn] dist/message.test.js
13
+ dist/server.jsdist/server/memory.js
@@ -0,0 +1,9 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 lint:fix /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > pnpm lint --fix
5
+
6
+
7
+ > @agent-glue/glue@0.1.0 lint /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
8
+ > eslint . "--fix"
9
+
@@ -0,0 +1,5 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 lint /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > eslint .
5
+
@@ -0,0 +1,27 @@
1
+
2
+
3
+ > @agent-glue/glue@0.0.1 test /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > vitest
5
+
6
+ [?25l
7
+  DEV  v3.0.4 /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
8
+
9
+ [?2026h
10
+  ❯ src/message.test.ts [queued]
11
+
12
+  Test Files 0 passed (1)
13
+  Tests 0 passed (0)
14
+  Start at 03:32:17
15
+  Duration 200ms
16
+ [?2026l ✓ src/message.test.ts (3 tests) 5ms
17
+ ✓ defineMessage > should create a message definition and type guard
18
+ ✓ defineMessage > is > should allow checking if a message is of the defined type
19
+ ✓ defineMessage > message > should provide a message builder function
20
+
21
+  Test Files  1 passed (1)
22
+  Tests  3 passed (3)
23
+  Start at  03:32:17
24
+  Duration  401ms (transform 64ms, setup 0ms, collect 64ms, tests 5ms, environment 0ms, prepare 98ms)
25
+
26
+  PASS  Waiting for file changes...
27
+ press h to show help, press q to quit
@@ -0,0 +1,5 @@
1
+
2
+
3
+ > @agent-glue/glue@0.1.0 typecheck /home/gareth/Documents/Personal/2025/agent-glue/packages/agent-glue
4
+ > tsc --noEmit
5
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @agent-glue/glue
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial release
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gareth Andrew
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,51 @@
1
+ export interface Message {
2
+ id: string;
3
+ type: string;
4
+ }
5
+ export declare function isMessageType<T extends Message>(
6
+ type: T["type"]
7
+ ): (message: Message) => message is T;
8
+ export declare function message<T extends Message>(
9
+ type: T["type"]
10
+ ): (
11
+ message: Omit<T, "id" | "type"> & {
12
+ id?: string;
13
+ type?: string;
14
+ }
15
+ ) => T;
16
+ export interface ActorInterface<
17
+ Commands extends Message,
18
+ Events extends Message
19
+ > {
20
+ send(command: Commands): void;
21
+ connect(handler: (event: Events) => void): void;
22
+ disconnect(handler: (event: Events) => void): void;
23
+ }
24
+ export declare abstract class Actor<
25
+ Commands extends Message = never,
26
+ Events extends Message = never
27
+ > implements ActorInterface<Commands, Events>
28
+ {
29
+ private readonly emitter;
30
+ protected emit(event: Events): void;
31
+ send(_command: Commands): void;
32
+ connect(handler: (event: Events) => void): void;
33
+ disconnect(handler: (event: Events) => void): void;
34
+ }
35
+ export type CommandsType<T extends ActorInterface<Message, Message>> =
36
+ T extends ActorInterface<infer C, Message> ? C : never;
37
+ export type ActorFunction<
38
+ Commands extends Message = never,
39
+ Events extends Message = never
40
+ > = (emit: (event: Events) => void) => (command: Commands) => void;
41
+ export declare class FunctionActor<
42
+ Commands extends Message = never,
43
+ Events extends Message = never
44
+ > extends Actor<Commands, Events> {
45
+ private readonly fn;
46
+ constructor(fn: ActorFunction<Commands, Events>);
47
+ send(command: Commands): void;
48
+ }
49
+ export declare function actor<Commands extends Message, Events extends Message>(
50
+ fn: ActorFunction<Commands, Events>
51
+ ): ActorInterface<Commands, Events>;
package/dist/Actor.js ADDED
@@ -0,0 +1,30 @@
1
+ import { TypedEmitter } from "./utils/TypedEmitter.js";
2
+ export class Actor {
3
+ emitter = new TypedEmitter();
4
+ emit(event) {
5
+ this.emitter.emit("event", event);
6
+ }
7
+ send(_command) {
8
+ return;
9
+ }
10
+ connect(handler) {
11
+ this.emitter.on("event", handler);
12
+ }
13
+ disconnect(handler) {
14
+ this.emitter.off("event", handler);
15
+ }
16
+ }
17
+ export class FunctionActor extends Actor {
18
+ fn;
19
+ constructor(fn) {
20
+ super();
21
+ this.fn = fn;
22
+ }
23
+ send(command) {
24
+ const emit = (event) => this.emit(event);
25
+ this.fn(emit)(command);
26
+ }
27
+ }
28
+ export function actor(fn) {
29
+ return new FunctionActor(fn);
30
+ }
package/dist/actor.js ADDED
@@ -0,0 +1,32 @@
1
+ import { Emitter } from "./emitter.js";
2
+ export class Actor {
3
+ emitter = new Emitter();
4
+ emit(event) {
5
+ this.emitter.emit(event);
6
+ }
7
+ send(_command) {
8
+ return;
9
+ }
10
+ connect(handler) {
11
+ return this.emitter.connect(handler);
12
+ }
13
+ disconnect(handler) {
14
+ this.emitter.disconnect(handler);
15
+ }
16
+ }
17
+ export class FunctionActor extends Actor {
18
+ constructor(fn) {
19
+ super();
20
+ this.send = fn(this.emit.bind(this));
21
+ }
22
+ }
23
+ export function actor(fn) {
24
+ return new FunctionActor(fn);
25
+ }
26
+ export function actorClass(handler) {
27
+ return class extends FunctionActor {
28
+ constructor() {
29
+ super(handler);
30
+ }
31
+ };
32
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
2
+ import { AIMessage, BaseMessage } from "@langchain/core/messages";
3
+ import { Actor, Message } from "../../Actor.js";
4
+ export declare const GENERATE_COMMAND_TYPE = "langchain.llm.generate";
5
+ export interface GenerateCommand extends Message {
6
+ type: typeof GENERATE_COMMAND_TYPE;
7
+ model: BaseChatModel;
8
+ messages: BaseMessage[];
9
+ }
10
+ export declare const generateCommand: (
11
+ message: Omit<GenerateCommand, "type" | "id"> & {
12
+ id?: string;
13
+ type?: string;
14
+ }
15
+ ) => GenerateCommand;
16
+ export declare const isGenerateCommand: (
17
+ message: Message
18
+ ) => message is GenerateCommand;
19
+ export declare const RESPONSE_EVENT_TYPE = "langchain.llm.response";
20
+ export interface ResponseEvent extends Message {
21
+ type: typeof RESPONSE_EVENT_TYPE;
22
+ requestId: string;
23
+ response: AIMessage;
24
+ }
25
+ export declare const responseEvent: (
26
+ message: Omit<ResponseEvent, "type" | "id"> & {
27
+ id?: string;
28
+ type?: string;
29
+ }
30
+ ) => ResponseEvent;
31
+ export declare const isResponseEvent: (
32
+ message: Message
33
+ ) => message is ResponseEvent;
34
+ export type LLMCommands = GenerateCommand;
35
+ export type LLMEvents = ResponseEvent;
36
+ export declare class LLMActor extends Actor<LLMCommands, LLMEvents> {
37
+ send(cmd: LLMCommands): Promise<void>;
38
+ }
39
+ export declare const withPromptCaching: any;
40
+ export declare const wihMessageTruncation: any;
@@ -0,0 +1,52 @@
1
+ import { AIMessage } from "@langchain/core/messages";
2
+ import { Actor, isMessageType, message } from "../../Actor.js";
3
+ import { applyCachingToMessages } from "../../llm/messageTools.js";
4
+ import {
5
+ commandTransformer,
6
+ eventTransformer
7
+ } from "../../glue/transformers.js";
8
+ export const GENERATE_COMMAND_TYPE = "langchain.llm.generate";
9
+ export const generateCommand = message(GENERATE_COMMAND_TYPE);
10
+ export const isGenerateCommand = isMessageType(GENERATE_COMMAND_TYPE);
11
+ export const RESPONSE_EVENT_TYPE = "langchain.llm.response";
12
+ export const responseEvent = message(RESPONSE_EVENT_TYPE);
13
+ export const isResponseEvent = isMessageType(RESPONSE_EVENT_TYPE);
14
+ export class LLMActor extends Actor {
15
+ async send(cmd) {
16
+ const msg = await cmd.model.invoke(cmd.messages);
17
+ this.emit({
18
+ type: "langchain.llm.response",
19
+ requestId: cmd.id,
20
+ response: msg
21
+ });
22
+ }
23
+ }
24
+ export const withPromptCaching = commandTransformer((cmd) => {
25
+ if (!isGenerateCommand(cmd)) {
26
+ return cmd;
27
+ }
28
+ return generateCommand({
29
+ ...cmd,
30
+ messages: applyCachingToMessages(cmd.messages)
31
+ });
32
+ });
33
+ const truncateMaxTokens = (message) => {
34
+ if (!isResponseEvent(message)) {
35
+ return message;
36
+ }
37
+ let response = message.response;
38
+ const stopReason = response.response_metadata["stop_reason"];
39
+ if (stopReason === "max_tokens") {
40
+ // In all cases so far, when we hit max_tokens there are multiple tool calls so we can just skip the last one and assume
41
+ // the agent will try again in the next message
42
+ response = new AIMessage({
43
+ content: response.content && response.content.slice(0, -1),
44
+ tool_calls: response.tool_calls && response.tool_calls.slice(0, -1)
45
+ });
46
+ }
47
+ return responseEvent({
48
+ ...message,
49
+ response
50
+ });
51
+ };
52
+ export const wihMessageTruncation = eventTransformer(truncateMaxTokens);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ function defaultDiscriminator(m) {
2
+ return m === m;
3
+ }
4
+ export function take(actor, discriminator = defaultDiscriminator) {
5
+ return new Promise((resolve) => {
6
+ const handler = (message) => {
7
+ if (discriminator(message)) {
8
+ actor.disconnect(handler);
9
+ resolve(message);
10
+ }
11
+ };
12
+ actor.connect(handler);
13
+ });
14
+ }
15
+ export async function* takeEvery(actor) {
16
+ const eventQueue = [];
17
+ let resolve = null;
18
+ const disconnect = actor.connect((message) => {
19
+ if (resolve) {
20
+ resolve(message);
21
+ resolve = null;
22
+ }
23
+ else {
24
+ eventQueue.push(message);
25
+ }
26
+ });
27
+ try {
28
+ while (true) {
29
+ if (eventQueue.length > 0) {
30
+ yield eventQueue.shift();
31
+ }
32
+ else {
33
+ yield new Promise((res) => {
34
+ resolve = res;
35
+ });
36
+ }
37
+ }
38
+ }
39
+ finally {
40
+ disconnect();
41
+ }
42
+ }
43
+ export async function* takeIf(actor, discriminator) {
44
+ for await (const event of takeEvery(actor)) {
45
+ if (discriminator(event)) {
46
+ yield event;
47
+ }
48
+ }
49
+ }
50
+ export async function* takeUntil(actor, discriminator, endCondition = () => true) {
51
+ for await (const event of takeEvery(actor)) {
52
+ if (endCondition(event)) {
53
+ break;
54
+ }
55
+ if (discriminator(event)) {
56
+ yield event;
57
+ }
58
+ }
59
+ }
60
+ export function on(actor, discriminator, handler) {
61
+ return actor.connect((message) => {
62
+ if (discriminator(message)) {
63
+ handler(message);
64
+ }
65
+ });
66
+ }
@@ -0,0 +1,19 @@
1
+ import { TypedEmitter } from "./utils/TypedEmitter.js";
2
+ export class Emitter {
3
+ emitter = new TypedEmitter();
4
+ emit(event) {
5
+ process.nextTick(() => this.emitter.emit("event", event));
6
+ }
7
+ connect(handler) {
8
+ this.emitter.on("event", handler);
9
+ return () => this.emitter.off("event", handler);
10
+ }
11
+ disconnect(handler) {
12
+ if (!handler) {
13
+ this.emitter.removeAllListeners();
14
+ }
15
+ else {
16
+ this.emitter.off("event", handler);
17
+ }
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ export declare const foo = "foo";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export const foo = "foo";
@@ -0,0 +1,18 @@
1
+ import { v7 as uuid } from "uuid";
2
+ export function isMessageType(type) {
3
+ return (message) => message.type === type;
4
+ }
5
+ export function message(type) {
6
+ return (message) => {
7
+ return { ...message, type, id: uuid() };
8
+ };
9
+ }
10
+ export function defineMessage(type) {
11
+ const factory = message(type);
12
+ const isMessage = isMessageType(type);
13
+ factory.is = isMessage;
14
+ factory.isMessage = isMessage;
15
+ factory.type = type;
16
+ factory.message = factory;
17
+ return factory;
18
+ }
@@ -0,0 +1,37 @@
1
+ import { describe, expect, expectTypeOf, it } from "vitest";
2
+ import { defineMessage } from "./message.js";
3
+ describe("defineMessage", () => {
4
+ it("should create a message definition and type guard", () => {
5
+ const TestMessage = defineMessage("test.type");
6
+ const msg = TestMessage({ data: "test" });
7
+ expect(msg.type).toBe("test.type");
8
+ expect(TestMessage.type).toBe("test.type");
9
+ expect(TestMessage.is(msg)).toBe(true);
10
+ });
11
+ describe("is", () => {
12
+ it("should allow checking if a message is of the defined type", () => {
13
+ const TestMessage = defineMessage("test.type");
14
+ const OtherMessage = defineMessage("other.type");
15
+ const msg = TestMessage({ data: "test" });
16
+ expect(TestMessage.is(msg)).toBe(true);
17
+ expect(OtherMessage.is(msg)).toBe(false);
18
+ const unknownMsg = msg;
19
+ if (TestMessage.is(unknownMsg)) {
20
+ expectTypeOf(unknownMsg).toEqualTypeOf();
21
+ }
22
+ else {
23
+ expectTypeOf(unknownMsg).toEqualTypeOf();
24
+ }
25
+ });
26
+ });
27
+ describe("message", () => {
28
+ it("should provide a message builder function", () => {
29
+ const TestMessage = defineMessage("test.type");
30
+ const msg = TestMessage.message({ data: "test" });
31
+ expectTypeOf(msg).toEqualTypeOf();
32
+ expect(msg.type).toBe("test.type");
33
+ expect(msg.data).toBe("test");
34
+ expect(TestMessage.is(msg)).toBe(true);
35
+ });
36
+ });
37
+ });
@@ -0,0 +1,46 @@
1
+ import { Actor } from "../actor.js";
2
+ import { defineMessage } from "../message.js";
3
+ import { event, isConnect, isSend } from "./protocol.js";
4
+ export const { message: localConnect, isMessage: isLocalConnect, type: LocalConnectType } = defineMessage("local-connect");
5
+ export const { message: localRegister, isMessage: isLocalRegister, type: LocalRegisterType } = defineMessage("local-register");
6
+ export class LocalServer extends Actor {
7
+ store = new Map();
8
+ send(command) {
9
+ if (isSend(command)) {
10
+ const { destination, message } = command;
11
+ const actor = this.store.get(destination);
12
+ if (actor) {
13
+ actor.send(message);
14
+ }
15
+ }
16
+ else if (isLocalConnect(command)) {
17
+ const { destination, callback } = command;
18
+ const actor = this.store.get(destination);
19
+ if (actor) {
20
+ actor.connect(callback);
21
+ }
22
+ }
23
+ else if (isLocalRegister(command)) {
24
+ const { name, actor } = command;
25
+ this.store.set(name, actor);
26
+ }
27
+ }
28
+ }
29
+ export class MemoryClient extends Actor {
30
+ server;
31
+ constructor(server) {
32
+ super();
33
+ this.server = server;
34
+ }
35
+ send(command) {
36
+ if (isSend(command)) {
37
+ this.server.send(command);
38
+ }
39
+ else if (isConnect(command)) {
40
+ this.server.send(localConnect({
41
+ destination: command.destination,
42
+ callback: (msg) => this.emit(event({ origin: command.destination, message: msg }))
43
+ }));
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,4 @@
1
+ import { defineMessage } from "../message.js";
2
+ export const { message: send, isMessage: isSend, type: SendType } = defineMessage("send");
3
+ export const { message: connect, isMessage: isConnect, type: ConnectType } = defineMessage("connect");
4
+ export const { message: event, isMessage: isEvent, type: EventType } = defineMessage("event");
@@ -0,0 +1,72 @@
1
+ import { Actor } from "../actor.js";
2
+ import { defineMessage } from "../message.js";
3
+ export const { message: sendCommand, isMessage: isSendCommand, type: SendCommandType } = defineMessage("send-command");
4
+ export const { message: openEvent, isMessage: isOpenEvent, type: OpenEventType } = defineMessage("open-event");
5
+ export const { message: closeEvent, isMessage: isCloseEvent, type: CloseEventType } = defineMessage("close-event");
6
+ export const { message: errorEvent, isMessage: isErrorEvent, type: ErrorEventType } = defineMessage("error-event");
7
+ export const { message: messageEvent, isMessage: isMessageEvent, type: MessageEventType } = defineMessage("message-event");
8
+ export class WebsocketClient extends Actor {
9
+ ws;
10
+ constructor(ws) {
11
+ super();
12
+ this.ws = ws;
13
+ ws.addEventListener("open", () => {
14
+ this.emit(openEvent({}));
15
+ });
16
+ ws.addEventListener("message", (event) => {
17
+ this.emit(messageEvent({ message: event.data }));
18
+ });
19
+ ws.addEventListener("close", () => {
20
+ this.emit(closeEvent({}));
21
+ });
22
+ ws.addEventListener("error", (event) => {
23
+ this.emit(errorEvent({ error: event }));
24
+ });
25
+ }
26
+ send(command) {
27
+ if (isSendCommand(command)) {
28
+ this.ws.send(command.message);
29
+ }
30
+ }
31
+ }
32
+ export class WebsocketClientWrapper extends Actor {
33
+ ws;
34
+ client;
35
+ constructor(ws) {
36
+ super();
37
+ this.ws = ws;
38
+ this.client = new WebsocketClient(ws);
39
+ this.client.connect((event) => {
40
+ if (isMessageEvent(event)) {
41
+ const message = JSON.parse(event.message);
42
+ this.emit(message);
43
+ }
44
+ });
45
+ }
46
+ send(command) {
47
+ this.client.send(sendCommand({ message: JSON.stringify(command) }));
48
+ }
49
+ }
50
+ export const { message: connectionEvent, isMessage: isConnectionEvent, type: ConnectionEventType } = defineMessage("connection-event");
51
+ export class WebsocketServer extends Actor {
52
+ wss;
53
+ constructor(wss) {
54
+ super();
55
+ this.wss = wss;
56
+ this.wss.on("connection", (ws) => {
57
+ this.emit(connectionEvent({ ws }));
58
+ });
59
+ }
60
+ }
61
+ export class WebsocketServerWrapper {
62
+ constructor(ws, actor) {
63
+ //const client = new WebsocketClient(ws);
64
+ const wrapper = new WebsocketClientWrapper(ws);
65
+ wrapper.connect((command) => {
66
+ actor.send(command);
67
+ });
68
+ actor.connect((event) => {
69
+ wrapper.send(event);
70
+ });
71
+ }
72
+ }
package/dist/server.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./server/protocol.js";
2
+ export * from "./server/memory.js";
3
+ export * from "./server/websocket.js";