@agent-glue/glue 0.1.8 → 0.2.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.
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- > @agent-glue/glue@0.1.7 build /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
3
+ > @agent-glue/glue@0.2.0 build /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
4
4
  > tsc
5
5
 
@@ -1,7 +1,5 @@
1
-
2
-
3
- > @agent-glue/glue@0.1.5 format /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/agent-glue
4
- > prettier --check .
5
-
6
- Checking formatting...
7
- .turbo/turbo-format.log.turbo/turbo-lint.log.turbo/turbo-typecheck.logCHANGELOG.mddist/tsconfig.tsbuildinfoeslint.config.jsnodemon.jsonpackage.jsonsrc/actor.tssrc/effects.tssrc/emitter.tssrc/message.test.tssrc/message.tssrc/server.tssrc/server/memory.tssrc/server/protocol.tssrc/server/websocket.tssrc/transformers.tssrc/types.tssrc/utils/TypedEmitter.tstsconfig.jsonAll matched files use Prettier code style!
1
+
2
+ > @agent-glue/glue@0.1.9 format /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
3
+ > prettier --check .
4
+
5
+ Checking formatting...
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- > @agent-glue/glue@0.1.7 lint /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
3
+ > @agent-glue/glue@0.2.0 lint /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
4
4
  > eslint .
5
5
 
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- > @agent-glue/glue@0.1.7 typecheck /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
3
+ > @agent-glue/glue@0.2.0 typecheck /home/gareth/Documents/Auto-Agent/repos/glue/main/packages/glue
4
4
  > tsc --noEmit
5
5
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @agent-glue/glue
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6f6c5a8: Add support for timeouts and abort signals to effects
8
+
9
+ ## 0.1.9
10
+
11
+ ### Patch Changes
12
+
13
+ - Move @types/uuid from devDependencies to dependencies for type export compatibility
14
+
3
15
  ## 0.1.8
4
16
 
5
17
  ### Patch Changes
package/dist/effects.js CHANGED
@@ -1,54 +1,152 @@
1
1
  function defaultDiscriminator(m) {
2
2
  return m === m;
3
3
  }
4
- export function take(actor, discriminator = (defaultDiscriminator)) {
5
- return new Promise((resolve) => {
4
+ export class TimeoutError extends Error {
5
+ constructor(message = "Operation timed out") {
6
+ super(message);
7
+ this.name = "TimeoutError";
8
+ }
9
+ }
10
+ export class AbortError extends Error {
11
+ constructor(message = "Operation aborted") {
12
+ super(message);
13
+ this.name = "AbortError";
14
+ }
15
+ }
16
+ function wrapAbortReason(reason) {
17
+ return typeof reason === "string" ? reason : "Operation aborted";
18
+ }
19
+ export function take(actor, discriminator = (defaultDiscriminator), options) {
20
+ return new Promise((resolve, reject) => {
21
+ let settled = false;
22
+ let timer;
23
+ const cleanup = () => {
24
+ settled = true;
25
+ actor.disconnect(handler);
26
+ if (timer)
27
+ clearTimeout(timer);
28
+ };
6
29
  const handler = (message) => {
30
+ if (settled)
31
+ return;
7
32
  if (discriminator(message)) {
8
- actor.disconnect(handler);
33
+ cleanup();
9
34
  resolve(message);
10
35
  }
11
36
  };
37
+ // AbortSignal - check before connecting
38
+ if (options?.signal) {
39
+ if (options.signal.aborted) {
40
+ reject(new AbortError(wrapAbortReason(options.signal.reason)));
41
+ return;
42
+ }
43
+ options.signal.addEventListener("abort", () => {
44
+ if (!settled) {
45
+ cleanup();
46
+ reject(new AbortError(wrapAbortReason(options.signal.reason)));
47
+ }
48
+ }, { once: true });
49
+ }
50
+ // Timeout
51
+ if (options?.timeout != null) {
52
+ timer = setTimeout(() => {
53
+ if (!settled) {
54
+ cleanup();
55
+ reject(new TimeoutError());
56
+ }
57
+ }, options.timeout);
58
+ timer.unref();
59
+ }
12
60
  actor.connect(handler);
13
61
  });
14
62
  }
15
- export async function* takeEvery(actor) {
63
+ export async function* takeEvery(actor, options) {
16
64
  const eventQueue = [];
17
65
  let resolve = null;
66
+ let reject = null;
67
+ let timer;
68
+ const clearTimer = () => {
69
+ if (timer) {
70
+ clearTimeout(timer);
71
+ timer = undefined;
72
+ }
73
+ };
74
+ const resetTimer = () => {
75
+ clearTimer();
76
+ if (options?.timeout != null) {
77
+ timer = setTimeout(() => {
78
+ if (reject) {
79
+ const rej = reject;
80
+ reject = null;
81
+ resolve = null;
82
+ rej(new TimeoutError());
83
+ }
84
+ }, options.timeout);
85
+ timer.unref();
86
+ }
87
+ };
18
88
  const disconnect = actor.connect((message) => {
19
89
  if (resolve) {
20
- resolve(message);
90
+ const res = resolve;
21
91
  resolve = null;
92
+ reject = null;
93
+ res(message);
22
94
  }
23
95
  else {
24
96
  eventQueue.push(message);
25
97
  }
26
98
  });
99
+ // AbortSignal
100
+ const onAbort = () => {
101
+ if (reject) {
102
+ const rej = reject;
103
+ reject = null;
104
+ resolve = null;
105
+ rej(new AbortError(wrapAbortReason(options?.signal?.reason)));
106
+ }
107
+ };
108
+ if (options?.signal) {
109
+ if (options.signal.aborted) {
110
+ disconnect();
111
+ return;
112
+ }
113
+ options.signal.addEventListener("abort", onAbort, { once: true });
114
+ }
27
115
  try {
28
116
  while (true) {
117
+ if (options?.signal?.aborted)
118
+ break;
29
119
  if (eventQueue.length > 0) {
30
- yield eventQueue.shift();
120
+ const event = eventQueue.shift();
121
+ resetTimer(); // reset idle timer on event
122
+ yield event;
31
123
  }
32
124
  else {
33
- yield new Promise((res) => {
125
+ resetTimer(); // start idle timer while waiting
126
+ const event = await new Promise((res, rej) => {
34
127
  resolve = res;
128
+ reject = rej;
35
129
  });
130
+ clearTimer(); // event arrived, clear timer
131
+ yield event;
36
132
  }
37
133
  }
38
134
  }
39
135
  finally {
136
+ clearTimer();
137
+ options?.signal?.removeEventListener("abort", onAbort);
40
138
  disconnect();
41
139
  }
42
140
  }
43
- export async function* takeIf(actor, discriminator) {
44
- for await (const event of takeEvery(actor)) {
141
+ export async function* takeIf(actor, discriminator, options) {
142
+ for await (const event of takeEvery(actor, options)) {
45
143
  if (discriminator(event)) {
46
144
  yield event;
47
145
  }
48
146
  }
49
147
  }
50
- export async function* takeUntil(actor, discriminator, endCondition = () => true) {
51
- for await (const event of takeEvery(actor)) {
148
+ export async function* takeUntil(actor, discriminator, endCondition = () => true, options) {
149
+ for await (const event of takeEvery(actor, options)) {
52
150
  if (endCondition(event)) {
53
151
  break;
54
152
  }
@@ -57,10 +155,19 @@ export async function* takeUntil(actor, discriminator, endCondition = () => true
57
155
  }
58
156
  }
59
157
  }
60
- export function on(actor, discriminator, handler) {
61
- return actor.connect((message) => {
158
+ export function on(actor, discriminator, handler, options) {
159
+ if (options?.signal?.aborted) {
160
+ return () => { };
161
+ }
162
+ const disconnect = actor.connect((message) => {
62
163
  if (discriminator(message)) {
63
164
  handler(message);
64
165
  }
65
166
  });
167
+ if (options?.signal) {
168
+ options.signal.addEventListener("abort", () => {
169
+ disconnect();
170
+ }, { once: true });
171
+ }
172
+ return disconnect;
66
173
  }