vovk 3.0.0-draft.272 → 3.0.0-draft.273

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.
@@ -6,10 +6,15 @@ export declare class JSONLinesResponse<T> extends Response {
6
6
  controller?: ReadableStreamDefaultController;
7
7
  readonly encoder: TextEncoder;
8
8
  readonly readableStream: ReadableStream;
9
+ private iteratorQueue;
10
+ private iteratorResolvers;
9
11
  constructor(requestHeaders: Awaited<ReturnType<typeof headers>>, init?: ResponseInit);
10
12
  send: (data: T | StreamAbortMessage) => void;
11
13
  close: () => void;
12
14
  throw: (e: KnownAny) => void;
13
15
  [Symbol.dispose]: () => void;
14
16
  [Symbol.asyncDispose]: () => void;
17
+ [Symbol.asyncIterator]: () => {
18
+ next: () => Promise<IteratorResult<T | StreamAbortMessage>>;
19
+ };
15
20
  }
@@ -7,6 +7,9 @@ class JSONLinesResponse extends Response {
7
7
  controller;
8
8
  encoder;
9
9
  readableStream;
10
+ // Add these private fields for async iteration
11
+ iteratorQueue = [];
12
+ iteratorResolvers = [];
10
13
  constructor(requestHeaders, init) {
11
14
  const encoder = new TextEncoder();
12
15
  let readableController;
@@ -39,7 +42,18 @@ class JSONLinesResponse extends Response {
39
42
  const { controller, encoder } = this;
40
43
  if (this.isClosed)
41
44
  return;
42
- return controller?.enqueue(encoder.encode(JSON.stringify(data) + '\n'));
45
+ // Enqueue to the ReadableStream
46
+ controller?.enqueue(encoder.encode(JSON.stringify(data) + '\n'));
47
+ // Handle async iterator consumers
48
+ if (this.iteratorResolvers.length > 0) {
49
+ // If there's a pending next() call, resolve it immediately
50
+ const resolve = this.iteratorResolvers.shift();
51
+ resolve({ value: data, done: false });
52
+ }
53
+ else {
54
+ // Otherwise, queue the value for later consumption
55
+ this.iteratorQueue.push(data);
56
+ }
43
57
  };
44
58
  close = () => {
45
59
  const { controller } = this;
@@ -47,16 +61,36 @@ class JSONLinesResponse extends Response {
47
61
  return;
48
62
  this.isClosed = true;
49
63
  controller?.close();
64
+ // Resolve all pending iterator next() calls with done: true
65
+ while (this.iteratorResolvers.length > 0) {
66
+ const resolve = this.iteratorResolvers.shift();
67
+ resolve({ done: true, value: undefined });
68
+ }
50
69
  };
51
70
  throw = (e) => {
52
71
  this.send({ isError: true, reason: e instanceof Error ? e.message : e });
53
72
  return this.close();
54
73
  };
55
- [Symbol.dispose] = () => {
56
- this.close();
57
- };
58
- [Symbol.asyncDispose] = () => {
59
- this.close();
74
+ [Symbol.dispose] = () => this.close();
75
+ [Symbol.asyncDispose] = () => this.close();
76
+ [Symbol.asyncIterator] = () => {
77
+ return {
78
+ next: async () => {
79
+ // If we have queued values, return them immediately
80
+ if (this.iteratorQueue.length > 0) {
81
+ const value = this.iteratorQueue.shift();
82
+ return { value, done: false };
83
+ }
84
+ // If the stream is closed and no more values, we're done
85
+ if (this.isClosed) {
86
+ return { done: true, value: undefined };
87
+ }
88
+ // Otherwise, wait for the next value or close
89
+ return new Promise((resolve) => {
90
+ this.iteratorResolvers.push(resolve);
91
+ });
92
+ },
93
+ };
60
94
  };
61
95
  }
62
96
  exports.JSONLinesResponse = JSONLinesResponse;
package/cjs/VovkApp.js CHANGED
@@ -152,6 +152,7 @@ class VovkApp {
152
152
  const result = await staticMethod.call(controller, req, methodParams);
153
153
  const isIterator = typeof result === 'object' &&
154
154
  !!result &&
155
+ !(result instanceof Response) && // don't invoke asyncIterable for JSONLinesResponse
155
156
  ((Reflect.has(result, Symbol.iterator) &&
156
157
  typeof result[Symbol.iterator] === 'function') ||
157
158
  (Reflect.has(result, Symbol.asyncIterator) &&
@@ -6,10 +6,15 @@ export declare class JSONLinesResponse<T> extends Response {
6
6
  controller?: ReadableStreamDefaultController;
7
7
  readonly encoder: TextEncoder;
8
8
  readonly readableStream: ReadableStream;
9
+ private iteratorQueue;
10
+ private iteratorResolvers;
9
11
  constructor(requestHeaders: Awaited<ReturnType<typeof headers>>, init?: ResponseInit);
10
12
  send: (data: T | StreamAbortMessage) => void;
11
13
  close: () => void;
12
14
  throw: (e: KnownAny) => void;
13
15
  [Symbol.dispose]: () => void;
14
16
  [Symbol.asyncDispose]: () => void;
17
+ [Symbol.asyncIterator]: () => {
18
+ next: () => Promise<IteratorResult<T | StreamAbortMessage>>;
19
+ };
15
20
  }
@@ -7,6 +7,9 @@ class JSONLinesResponse extends Response {
7
7
  controller;
8
8
  encoder;
9
9
  readableStream;
10
+ // Add these private fields for async iteration
11
+ iteratorQueue = [];
12
+ iteratorResolvers = [];
10
13
  constructor(requestHeaders, init) {
11
14
  const encoder = new TextEncoder();
12
15
  let readableController;
@@ -39,7 +42,18 @@ class JSONLinesResponse extends Response {
39
42
  const { controller, encoder } = this;
40
43
  if (this.isClosed)
41
44
  return;
42
- return controller?.enqueue(encoder.encode(JSON.stringify(data) + '\n'));
45
+ // Enqueue to the ReadableStream
46
+ controller?.enqueue(encoder.encode(JSON.stringify(data) + '\n'));
47
+ // Handle async iterator consumers
48
+ if (this.iteratorResolvers.length > 0) {
49
+ // If there's a pending next() call, resolve it immediately
50
+ const resolve = this.iteratorResolvers.shift();
51
+ resolve({ value: data, done: false });
52
+ }
53
+ else {
54
+ // Otherwise, queue the value for later consumption
55
+ this.iteratorQueue.push(data);
56
+ }
43
57
  };
44
58
  close = () => {
45
59
  const { controller } = this;
@@ -47,16 +61,36 @@ class JSONLinesResponse extends Response {
47
61
  return;
48
62
  this.isClosed = true;
49
63
  controller?.close();
64
+ // Resolve all pending iterator next() calls with done: true
65
+ while (this.iteratorResolvers.length > 0) {
66
+ const resolve = this.iteratorResolvers.shift();
67
+ resolve({ done: true, value: undefined });
68
+ }
50
69
  };
51
70
  throw = (e) => {
52
71
  this.send({ isError: true, reason: e instanceof Error ? e.message : e });
53
72
  return this.close();
54
73
  };
55
- [Symbol.dispose] = () => {
56
- this.close();
57
- };
58
- [Symbol.asyncDispose] = () => {
59
- this.close();
74
+ [Symbol.dispose] = () => this.close();
75
+ [Symbol.asyncDispose] = () => this.close();
76
+ [Symbol.asyncIterator] = () => {
77
+ return {
78
+ next: async () => {
79
+ // If we have queued values, return them immediately
80
+ if (this.iteratorQueue.length > 0) {
81
+ const value = this.iteratorQueue.shift();
82
+ return { value, done: false };
83
+ }
84
+ // If the stream is closed and no more values, we're done
85
+ if (this.isClosed) {
86
+ return { done: true, value: undefined };
87
+ }
88
+ // Otherwise, wait for the next value or close
89
+ return new Promise((resolve) => {
90
+ this.iteratorResolvers.push(resolve);
91
+ });
92
+ },
93
+ };
60
94
  };
61
95
  }
62
96
  exports.JSONLinesResponse = JSONLinesResponse;
package/mjs/VovkApp.js CHANGED
@@ -152,6 +152,7 @@ class VovkApp {
152
152
  const result = await staticMethod.call(controller, req, methodParams);
153
153
  const isIterator = typeof result === 'object' &&
154
154
  !!result &&
155
+ !(result instanceof Response) && // don't invoke asyncIterable for JSONLinesResponse
155
156
  ((Reflect.has(result, Symbol.iterator) &&
156
157
  typeof result[Symbol.iterator] === 'function') ||
157
158
  (Reflect.has(result, Symbol.asyncIterator) &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk",
3
- "version": "3.0.0-draft.272",
3
+ "version": "3.0.0-draft.273",
4
4
  "main": "./cjs/index.js",
5
5
  "module": "./mjs/index.js",
6
6
  "types": "./mjs/index.d.ts",