@aurelo_npm/sdk 0.1.3 → 0.1.4

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.
package/dist/index.d.ts CHANGED
@@ -157,6 +157,9 @@ export declare class AureloSDK {
157
157
  private clientIdValue;
158
158
  private sessionValue;
159
159
  private reconnectCursors;
160
+ private readonly observedStreamResponses;
161
+ private readonly observedSseComments;
162
+ private observedSseCommentOrder;
160
163
  constructor(options: AureloSDKOptions);
161
164
  getClientId(): Promise<string>;
162
165
  getFullClientId(): Promise<string>;
@@ -169,6 +172,7 @@ export declare class AureloSDK {
169
172
  private setReconnectCursor;
170
173
  private clearReconnectCursor;
171
174
  observeSseComment(comment: string): Promise<void>;
175
+ private rememberSseComment;
172
176
  queueMessage(request: string | AureloQueueMessageRequest): Promise<unknown>;
173
177
  createResponse(request: AureloResponseRequest, options?: {
174
178
  signal?: AbortSignal;
@@ -186,6 +190,9 @@ export declare class AureloSDK {
186
190
  reconnect(request?: AureloReconnectRequest): Promise<Response>;
187
191
  submitToolResult(request: AureloToolResultRequest): Promise<Response | unknown>;
188
192
  streamToolResult(request: AureloToolResultRequest): AsyncGenerator<AureloStreamEvent>;
193
+ private observeResponseStream;
194
+ private observeSseTextFragment;
195
+ private observeSseCommentLine;
189
196
  private handleSseLine;
190
197
  private readErrorPayload;
191
198
  private readResponsePayload;
package/dist/index.js CHANGED
@@ -291,6 +291,9 @@ export class AureloSDK {
291
291
  clientIdValue = null;
292
292
  sessionValue = null;
293
293
  reconnectCursors = new Map();
294
+ observedStreamResponses = new WeakSet();
295
+ observedSseComments = new Set();
296
+ observedSseCommentOrder = [];
294
297
  constructor(options) {
295
298
  if (!options.apiKey || !String(options.apiKey).trim()) {
296
299
  throw new Error('AureloSDK requires apiKey.');
@@ -423,6 +426,9 @@ export class AureloSDK {
423
426
  if (!normalizedComment) {
424
427
  return;
425
428
  }
429
+ if (this.rememberSseComment(normalizedComment)) {
430
+ return;
431
+ }
426
432
  const reconnectCursor = parseReconnectCursorComment(normalizedComment);
427
433
  if (reconnectCursor) {
428
434
  await this.setReconnectCursor(reconnectCursor.sessionId, reconnectCursor.cursor);
@@ -432,6 +438,20 @@ export class AureloSDK {
432
438
  await this.rotateSession(reason);
433
439
  }
434
440
  }
441
+ rememberSseComment(comment) {
442
+ if (this.observedSseComments.has(comment)) {
443
+ return true;
444
+ }
445
+ this.observedSseComments.add(comment);
446
+ this.observedSseCommentOrder.push(comment);
447
+ while (this.observedSseCommentOrder.length > 500) {
448
+ const oldest = this.observedSseCommentOrder.shift();
449
+ if (oldest) {
450
+ this.observedSseComments.delete(oldest);
451
+ }
452
+ }
453
+ return false;
454
+ }
435
455
  async queueMessage(request) {
436
456
  const session = await this.getSession();
437
457
  const queueRequest = typeof request === 'string'
@@ -522,7 +542,7 @@ export class AureloSDK {
522
542
  };
523
543
  await this.storage.set(SESSION_KEY, JSON.stringify(this.sessionValue));
524
544
  }
525
- return response;
545
+ return this.observeResponseStream(response);
526
546
  }
527
547
  async createResponseWithRotationRetry(request, options = {}) {
528
548
  try {
@@ -614,6 +634,7 @@ export class AureloSDK {
614
634
  await this.closeSession('request_closed');
615
635
  return;
616
636
  }
637
+ const observeComments = !this.observedStreamResponses.has(response);
617
638
  const reader = response.body.getReader();
618
639
  const decoder = new TextDecoder();
619
640
  let buffer = '';
@@ -627,7 +648,7 @@ export class AureloSDK {
627
648
  const lines = buffer.split('\n');
628
649
  buffer = lines.pop() || '';
629
650
  for (const line of lines) {
630
- const event = await this.handleSseLine(line);
651
+ const event = await this.handleSseLine(line, { observeComments });
631
652
  if (event) {
632
653
  yield event;
633
654
  }
@@ -635,7 +656,7 @@ export class AureloSDK {
635
656
  }
636
657
  buffer += decoder.decode();
637
658
  if (buffer.trim()) {
638
- const event = await this.handleSseLine(buffer);
659
+ const event = await this.handleSseLine(buffer, { observeComments });
639
660
  if (event) {
640
661
  yield event;
641
662
  }
@@ -700,7 +721,7 @@ export class AureloSDK {
700
721
  payload,
701
722
  });
702
723
  }
703
- return response;
724
+ return this.observeResponseStream(response);
704
725
  }
705
726
  async submitToolResult(request) {
706
727
  const session = request.sessionId
@@ -762,7 +783,7 @@ export class AureloSDK {
762
783
  }
763
784
  const contentType = response.headers.get('content-type') || '';
764
785
  if (contentType.includes('text/event-stream')) {
765
- return response;
786
+ return this.observeResponseStream(response);
766
787
  }
767
788
  return this.readResponsePayload(response);
768
789
  }
@@ -774,14 +795,88 @@ export class AureloSDK {
774
795
  }
775
796
  yield { type: 'event', raw: '', data: result };
776
797
  }
777
- async handleSseLine(line) {
798
+ observeResponseStream(response) {
799
+ const contentType = response.headers.get('content-type') || '';
800
+ if (!response.body || !contentType.includes('text/event-stream') || typeof ReadableStream === 'undefined') {
801
+ return response;
802
+ }
803
+ const reader = response.body.getReader();
804
+ const decoder = new TextDecoder();
805
+ let buffer = '';
806
+ const body = new ReadableStream({
807
+ start: async (controller) => {
808
+ try {
809
+ while (true) {
810
+ const { done, value } = await reader.read();
811
+ if (done) {
812
+ break;
813
+ }
814
+ if (value) {
815
+ buffer = await this.observeSseTextFragment(decoder.decode(value, { stream: true }), buffer);
816
+ controller.enqueue(value);
817
+ }
818
+ }
819
+ const trailing = decoder.decode();
820
+ if (trailing) {
821
+ buffer = await this.observeSseTextFragment(trailing, buffer);
822
+ }
823
+ if (buffer.trim()) {
824
+ await this.observeSseCommentLine(buffer);
825
+ }
826
+ controller.close();
827
+ }
828
+ catch (error) {
829
+ controller.error(error);
830
+ }
831
+ finally {
832
+ reader.releaseLock();
833
+ }
834
+ },
835
+ cancel: async (reason) => {
836
+ try {
837
+ await reader.cancel(reason);
838
+ }
839
+ finally {
840
+ reader.releaseLock();
841
+ }
842
+ },
843
+ });
844
+ const observedResponse = new Response(body, {
845
+ status: response.status,
846
+ statusText: response.statusText,
847
+ headers: response.headers,
848
+ });
849
+ this.observedStreamResponses.add(observedResponse);
850
+ return observedResponse;
851
+ }
852
+ async observeSseTextFragment(fragment, previousBuffer) {
853
+ if (!fragment) {
854
+ return previousBuffer;
855
+ }
856
+ const lines = `${previousBuffer}${fragment}`.split(/\r?\n/);
857
+ const buffer = lines.pop() || '';
858
+ for (const line of lines) {
859
+ await this.observeSseCommentLine(line);
860
+ }
861
+ return buffer;
862
+ }
863
+ async observeSseCommentLine(line) {
864
+ const trimmed = String(line || '').trim();
865
+ if (!trimmed.startsWith(':')) {
866
+ return;
867
+ }
868
+ await this.observeSseComment(trimmed.slice(1).trim());
869
+ }
870
+ async handleSseLine(line, options = {}) {
778
871
  const trimmed = line.trim();
779
872
  if (!trimmed) {
780
873
  return null;
781
874
  }
782
875
  if (trimmed.startsWith(':')) {
783
876
  const comment = trimmed.slice(1).trim();
784
- await this.observeSseComment(comment);
877
+ if (options.observeComments !== false) {
878
+ await this.observeSseComment(comment);
879
+ }
785
880
  return { type: 'comment', raw: line, comment };
786
881
  }
787
882
  if (trimmed === 'data: [DONE]') {
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@aurelo_npm/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Aurelo API-key SDK with stable client identity and backend-driven session rotation.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "files": [
9
9
  "dist/index.js",
10
- "dist/index.d.ts"
10
+ "dist/index.d.ts",
11
+ "!README.md"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "tsc -p tsconfig.json",