@pellux/goodvibes-transport-http 0.18.3 → 0.30.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.
- package/README.md +14 -7
- package/dist/auth.d.ts +25 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +55 -0
- package/dist/backoff.d.ts +7 -0
- package/dist/backoff.d.ts.map +1 -1
- package/dist/backoff.js +10 -2
- package/dist/client-plumbing.d.ts +32 -0
- package/dist/client-plumbing.d.ts.map +1 -0
- package/dist/client-plumbing.js +243 -0
- package/dist/contract-client.d.ts +11 -1
- package/dist/contract-client.d.ts.map +1 -1
- package/dist/contract-client.js +20 -5
- package/dist/http-core.d.ts +42 -1
- package/dist/http-core.d.ts.map +1 -1
- package/dist/http-core.js +240 -76
- package/dist/http.d.ts +3 -3
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +46 -5
- package/dist/index.d.ts +11 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +3 -2
- package/dist/reconnect.d.ts +2 -0
- package/dist/reconnect.d.ts.map +1 -1
- package/dist/reconnect.js +4 -3
- package/dist/retry.d.ts +15 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +21 -2
- package/dist/sse-stream.d.ts +9 -2
- package/dist/sse-stream.d.ts.map +1 -1
- package/dist/sse-stream.js +44 -25
- package/dist/sse.d.ts +1 -1
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +6 -12
- package/package.json +53 -4
package/dist/reconnect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../src/reconnect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../src/reconnect.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,KAAK,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE3H,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,gGAAgG;AAChG,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C,eAAO,MAAM,+BAA+B,EAAE,6BAM7C,CAAC;AAEF,wBAAgB,8BAA8B,CAC5C,MAAM,CAAC,EAAE,qBAAqB,GAC7B,6BAA6B,CAM/B;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,6BAA6B,GACpC,MAAM,CAER"}
|
package/dist/reconnect.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
// Synced from goodvibes-tui/src/runtime/transports/stream-reconnect.ts
|
|
2
1
|
import { computeBackoffDelay, normalizeBackoffPolicy } from './backoff.js';
|
|
2
|
+
/** Maximum reconnect attempts when reconnect is enabled and the caller does not set a limit. */
|
|
3
|
+
export const DEFAULT_STREAM_MAX_ATTEMPTS = 10;
|
|
3
4
|
export const DEFAULT_STREAM_RECONNECT_POLICY = {
|
|
4
5
|
enabled: false,
|
|
5
|
-
maxAttempts:
|
|
6
|
+
maxAttempts: DEFAULT_STREAM_MAX_ATTEMPTS,
|
|
6
7
|
baseDelayMs: 500,
|
|
7
|
-
maxDelayMs:
|
|
8
|
+
maxDelayMs: 30_000,
|
|
8
9
|
backoffFactor: 2,
|
|
9
10
|
};
|
|
10
11
|
export function normalizeStreamReconnectPolicy(policy) {
|
package/dist/retry.d.ts
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { type BackoffPolicy, type ResolvedBackoffPolicy } from './backoff.js';
|
|
2
|
+
export interface PerMethodRetryPolicy {
|
|
3
|
+
readonly maxAttempts?: number;
|
|
4
|
+
readonly baseDelayMs?: number;
|
|
5
|
+
readonly maxDelayMs?: number;
|
|
6
|
+
readonly backoffFactor?: number;
|
|
7
|
+
}
|
|
2
8
|
export interface HttpRetryPolicy extends BackoffPolicy {
|
|
3
9
|
readonly retryOnStatuses?: readonly number[];
|
|
4
10
|
readonly retryOnMethods?: readonly string[];
|
|
5
11
|
readonly retryOnNetworkError?: boolean;
|
|
12
|
+
/** Per-method retry policy overrides keyed by method ID. */
|
|
13
|
+
readonly perMethodPolicy?: Readonly<Record<string, PerMethodRetryPolicy>>;
|
|
6
14
|
}
|
|
7
15
|
export interface ResolvedHttpRetryPolicy extends ResolvedBackoffPolicy {
|
|
8
16
|
readonly retryOnStatuses: readonly number[];
|
|
9
17
|
readonly retryOnMethods: readonly string[];
|
|
10
18
|
readonly retryOnNetworkError: boolean;
|
|
19
|
+
/** Per-method retry policy overrides keyed by method ID. */
|
|
20
|
+
readonly perMethodPolicy: Readonly<Record<string, PerMethodRetryPolicy>>;
|
|
11
21
|
}
|
|
12
22
|
export declare const DEFAULT_HTTP_RETRY_POLICY: ResolvedHttpRetryPolicy;
|
|
13
23
|
export declare function normalizeHttpRetryPolicy(policy?: HttpRetryPolicy): ResolvedHttpRetryPolicy;
|
|
14
24
|
export declare function resolveHttpRetryPolicy(defaultPolicy?: HttpRetryPolicy, override?: false | HttpRetryPolicy): ResolvedHttpRetryPolicy;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a per-method retry policy override by method ID.
|
|
27
|
+
* Returns the base policy with overrides applied, or the base policy unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyPerMethodPolicy(base: ResolvedHttpRetryPolicy, methodId: string): ResolvedHttpRetryPolicy;
|
|
15
30
|
export declare function getHttpRetryDelay(attempt: number, policy: ResolvedHttpRetryPolicy): number;
|
|
16
31
|
export declare function isRetryableHttpStatus(method: string, status: number, policy: ResolvedHttpRetryPolicy): boolean;
|
|
17
32
|
export declare function isRetryableNetworkError(method: string, policy: ResolvedHttpRetryPolicy): boolean;
|
package/dist/retry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AACA,OAAO,EAA+C,KAAK,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE3H,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AACA,OAAO,EAA+C,KAAK,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE3H,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAC1E;AAED,eAAO,MAAM,yBAAyB,EAAE,uBASvC,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,MAAM,CAAC,EAAE,eAAe,GACvB,uBAAuB,CASzB;AAED,wBAAgB,sBAAsB,CACpC,aAAa,CAAC,EAAE,eAAe,EAC/B,QAAQ,CAAC,EAAE,KAAK,GAAG,eAAe,GACjC,uBAAuB,CAczB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,EAAE,MAAM,GACf,uBAAuB,CAUzB;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,uBAAuB,GAC9B,MAAM,CAER;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAGT;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAET"}
|
package/dist/retry.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { RETRYABLE_STATUS_CODES } from '@pellux/goodvibes-errors';
|
|
2
2
|
import { computeBackoffDelay, normalizeBackoffPolicy } from './backoff.js';
|
|
3
3
|
export const DEFAULT_HTTP_RETRY_POLICY = {
|
|
4
4
|
maxAttempts: 1,
|
|
5
5
|
baseDelayMs: 250,
|
|
6
6
|
maxDelayMs: 2_000,
|
|
7
7
|
backoffFactor: 2,
|
|
8
|
-
retryOnStatuses:
|
|
8
|
+
retryOnStatuses: RETRYABLE_STATUS_CODES,
|
|
9
9
|
retryOnMethods: ['GET', 'HEAD', 'OPTIONS'],
|
|
10
10
|
retryOnNetworkError: true,
|
|
11
|
+
perMethodPolicy: {},
|
|
11
12
|
};
|
|
12
13
|
export function normalizeHttpRetryPolicy(policy) {
|
|
13
14
|
const normalized = normalizeBackoffPolicy(policy, DEFAULT_HTTP_RETRY_POLICY);
|
|
@@ -16,6 +17,7 @@ export function normalizeHttpRetryPolicy(policy) {
|
|
|
16
17
|
retryOnStatuses: [...(policy?.retryOnStatuses ?? DEFAULT_HTTP_RETRY_POLICY.retryOnStatuses)],
|
|
17
18
|
retryOnMethods: [...(policy?.retryOnMethods ?? DEFAULT_HTTP_RETRY_POLICY.retryOnMethods)].map((method) => method.toUpperCase()),
|
|
18
19
|
retryOnNetworkError: policy?.retryOnNetworkError ?? DEFAULT_HTTP_RETRY_POLICY.retryOnNetworkError,
|
|
20
|
+
perMethodPolicy: policy?.perMethodPolicy ?? DEFAULT_HTTP_RETRY_POLICY.perMethodPolicy,
|
|
19
21
|
};
|
|
20
22
|
}
|
|
21
23
|
export function resolveHttpRetryPolicy(defaultPolicy, override) {
|
|
@@ -31,6 +33,23 @@ export function resolveHttpRetryPolicy(defaultPolicy, override) {
|
|
|
31
33
|
retryOnStatuses: override.retryOnStatuses ? [...override.retryOnStatuses] : base.retryOnStatuses,
|
|
32
34
|
retryOnMethods: override.retryOnMethods ? override.retryOnMethods.map((method) => method.toUpperCase()) : base.retryOnMethods,
|
|
33
35
|
retryOnNetworkError: override.retryOnNetworkError ?? base.retryOnNetworkError,
|
|
36
|
+
perMethodPolicy: override.perMethodPolicy ?? base.perMethodPolicy,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a per-method retry policy override by method ID.
|
|
41
|
+
* Returns the base policy with overrides applied, or the base policy unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export function applyPerMethodPolicy(base, methodId) {
|
|
44
|
+
const override = base.perMethodPolicy[methodId];
|
|
45
|
+
if (!override)
|
|
46
|
+
return base;
|
|
47
|
+
return {
|
|
48
|
+
...base,
|
|
49
|
+
maxAttempts: override.maxAttempts ?? base.maxAttempts,
|
|
50
|
+
baseDelayMs: override.baseDelayMs ?? base.baseDelayMs,
|
|
51
|
+
maxDelayMs: override.maxDelayMs ?? base.maxDelayMs,
|
|
52
|
+
backoffFactor: override.backoffFactor ?? base.backoffFactor,
|
|
34
53
|
};
|
|
35
54
|
}
|
|
36
55
|
export function getHttpRetryDelay(attempt, policy) {
|
package/dist/sse-stream.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AuthTokenResolver } from './auth.js';
|
|
2
2
|
import { type StreamReconnectPolicy } from './reconnect.js';
|
|
3
|
+
import { isAbortError } from '@pellux/goodvibes-transport-core';
|
|
3
4
|
export interface ServerSentEventHandlers {
|
|
4
5
|
readonly onEvent?: (eventName: string, payload: unknown) => void;
|
|
5
6
|
readonly onReady?: (payload: unknown) => void;
|
|
@@ -8,6 +9,11 @@ export interface ServerSentEventHandlers {
|
|
|
8
9
|
readonly attempt: number;
|
|
9
10
|
readonly delayMs: number;
|
|
10
11
|
}) => void;
|
|
12
|
+
readonly onClose?: () => void;
|
|
13
|
+
readonly onTerminate?: (input: {
|
|
14
|
+
readonly error: unknown;
|
|
15
|
+
readonly reconnectAttempts: number;
|
|
16
|
+
}) => void;
|
|
11
17
|
}
|
|
12
18
|
export interface ServerSentEventOptions {
|
|
13
19
|
readonly signal?: AbortSignal;
|
|
@@ -17,6 +23,7 @@ export interface ServerSentEventOptions {
|
|
|
17
23
|
readonly lastEventId?: string | null;
|
|
18
24
|
readonly reconnect?: StreamReconnectPolicy;
|
|
19
25
|
}
|
|
20
|
-
export
|
|
21
|
-
export
|
|
26
|
+
export { isAbortError };
|
|
27
|
+
export { openRawServerSentEventStream as openServerSentEventStream };
|
|
28
|
+
export declare function openRawServerSentEventStream(fetchImpl: typeof fetch, url: string, handlers: ServerSentEventHandlers, options?: ServerSentEventOptions): Promise<() => void>;
|
|
22
29
|
//# sourceMappingURL=sse-stream.d.ts.map
|
package/dist/sse-stream.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-stream.d.ts","sourceRoot":"","sources":["../src/sse-stream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sse-stream.d.ts","sourceRoot":"","sources":["../src/sse-stream.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGhE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACzG;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAC;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,qBAAqB,CAAC;CAC5C;AAYD,OAAO,EAAE,YAAY,EAAE,CAAC;AAwCxB,OAAO,EAAE,4BAA4B,IAAI,yBAAyB,EAAE,CAAC;AAMrE,wBAAsB,4BAA4B,CAChD,SAAS,EAAE,OAAO,KAAK,EACvB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,uBAAuB,EACjC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,IAAI,CAAC,CAyLrB"}
|
package/dist/sse-stream.js
CHANGED
|
@@ -1,46 +1,58 @@
|
|
|
1
|
-
// Synced from goodvibes-tui/src/runtime/transports/sse-stream.ts
|
|
2
1
|
import { sleepWithSignal } from './backoff.js';
|
|
3
2
|
import { mergeHeaders, resolveAuthToken } from './auth.js';
|
|
4
3
|
import { getStreamReconnectDelay, normalizeStreamReconnectPolicy, } from './reconnect.js';
|
|
4
|
+
import { createHttpStatusError, HttpStatusError } from '@pellux/goodvibes-errors';
|
|
5
|
+
import { isAbortError } from '@pellux/goodvibes-transport-core';
|
|
5
6
|
function readEventPayload(data) {
|
|
6
7
|
if (!data.trim())
|
|
7
8
|
return null;
|
|
8
9
|
try {
|
|
9
10
|
return JSON.parse(data);
|
|
10
11
|
}
|
|
11
|
-
catch {
|
|
12
|
+
catch (error) {
|
|
13
|
+
void error;
|
|
12
14
|
return data;
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
|
-
export
|
|
16
|
-
return (error instanceof DOMException && error.name === 'AbortError') || (typeof error === 'object'
|
|
17
|
-
&& error !== null
|
|
18
|
-
&& 'name' in error
|
|
19
|
-
&& error.name === 'AbortError');
|
|
20
|
-
}
|
|
17
|
+
export { isAbortError };
|
|
21
18
|
function createStreamError(status, url, body) {
|
|
22
19
|
const message = body.trim()
|
|
23
20
|
? `Unable to open SSE stream: ${status} ${body}`.trim()
|
|
24
21
|
: `Unable to open SSE stream: ${status}`;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const error = status > 0
|
|
23
|
+
? status >= 500
|
|
24
|
+
? new HttpStatusError(message, {
|
|
25
|
+
status,
|
|
26
|
+
category: 'network',
|
|
27
|
+
source: 'transport',
|
|
28
|
+
recoverable: true,
|
|
29
|
+
url,
|
|
30
|
+
method: 'GET',
|
|
31
|
+
body,
|
|
32
|
+
})
|
|
33
|
+
: createHttpStatusError(status, url, 'GET', body)
|
|
34
|
+
: new HttpStatusError(message, {
|
|
35
|
+
status: undefined,
|
|
36
|
+
category: 'network',
|
|
37
|
+
source: 'transport',
|
|
38
|
+
recoverable: true,
|
|
29
39
|
url,
|
|
30
40
|
method: 'GET',
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
body,
|
|
42
|
+
});
|
|
43
|
+
const transportPayload = {
|
|
44
|
+
status,
|
|
45
|
+
body,
|
|
46
|
+
url,
|
|
47
|
+
method: 'GET',
|
|
48
|
+
};
|
|
49
|
+
return Object.assign(error, { transport: transportPayload });
|
|
33
50
|
}
|
|
51
|
+
export { openRawServerSentEventStream as openServerSentEventStream };
|
|
34
52
|
function reportStreamError(error, handlers) {
|
|
35
|
-
|
|
36
|
-
handlers.onError(error);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
queueMicrotask(() => {
|
|
40
|
-
throw error;
|
|
41
|
-
});
|
|
53
|
+
handlers.onError?.(error);
|
|
42
54
|
}
|
|
43
|
-
export async function
|
|
55
|
+
export async function openRawServerSentEventStream(fetchImpl, url, handlers, options = {}) {
|
|
44
56
|
const outerController = new AbortController();
|
|
45
57
|
const reconnectPolicy = normalizeStreamReconnectPolicy(options.reconnect);
|
|
46
58
|
let lastEventId = options.lastEventId ?? null;
|
|
@@ -173,6 +185,7 @@ export async function openServerSentEventStream(fetchImpl, url, handlers, option
|
|
|
173
185
|
try {
|
|
174
186
|
await runConnection();
|
|
175
187
|
reconnectAttempts = 0;
|
|
188
|
+
handlers.onClose?.();
|
|
176
189
|
return;
|
|
177
190
|
}
|
|
178
191
|
catch (error) {
|
|
@@ -180,13 +193,15 @@ export async function openServerSentEventStream(fetchImpl, url, handlers, option
|
|
|
180
193
|
return;
|
|
181
194
|
}
|
|
182
195
|
const nextAttempt = reconnectAttempts + 1;
|
|
183
|
-
const shouldReconnect = reconnectPolicy.enabled && nextAttempt
|
|
196
|
+
const shouldReconnect = reconnectPolicy.enabled && nextAttempt <= reconnectPolicy.maxAttempts;
|
|
184
197
|
if (!shouldReconnect) {
|
|
198
|
+
handlers.onTerminate?.({ error, reconnectAttempts: nextAttempt });
|
|
185
199
|
reportStreamError(error, handlers);
|
|
186
200
|
return;
|
|
187
201
|
}
|
|
188
202
|
reconnectAttempts = nextAttempt;
|
|
189
|
-
|
|
203
|
+
// Use the same 1-based attempt counter as the WS connector for a symmetric schedule.
|
|
204
|
+
const delayMs = getStreamReconnectDelay(nextAttempt, reconnectPolicy);
|
|
190
205
|
handlers.onReconnect?.({ attempt: nextAttempt, delayMs });
|
|
191
206
|
handlers.onError?.(error);
|
|
192
207
|
try {
|
|
@@ -201,7 +216,11 @@ export async function openServerSentEventStream(fetchImpl, url, handlers, option
|
|
|
201
216
|
}
|
|
202
217
|
}
|
|
203
218
|
};
|
|
204
|
-
void loop()
|
|
219
|
+
void loop().catch((error) => {
|
|
220
|
+
if (!isAbortError(error)) {
|
|
221
|
+
reportStreamError(error, handlers);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
205
224
|
});
|
|
206
225
|
await readyPromise;
|
|
207
226
|
return () => {
|
package/dist/sse.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ServerSentEventHandlers, type ServerSentEventOptions as CoreServerSentEventOptions } from './sse-stream.js';
|
|
2
|
-
import {
|
|
2
|
+
import type { HttpTransport } from './http.js';
|
|
3
3
|
export type { ServerSentEventHandlers };
|
|
4
4
|
export interface ServerSentEventOptions extends Omit<CoreServerSentEventOptions, 'authToken'> {
|
|
5
5
|
}
|
package/dist/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,IAAI,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AACxJ,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,YAAY,EAAE,uBAAuB,EAAE,CAAC;AACxC,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,0BAA0B,EAAE,WAAW,CAAC;CAAG;AAEhG,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,uBAAuB,EACjC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,IAAI,CAAC,CASrB"}
|
package/dist/sse.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { normalizeTransportError } from './http.js';
|
|
1
|
+
import { openRawServerSentEventStream } from './sse-stream.js';
|
|
3
2
|
export async function openServerSentEventStream(transport, pathOrUrl, handlers, options = {}) {
|
|
4
3
|
const url = pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')
|
|
5
4
|
? pathOrUrl
|
|
6
5
|
: transport.buildUrl(pathOrUrl);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
catch (error) {
|
|
15
|
-
throw normalizeTransportError(error);
|
|
16
|
-
}
|
|
6
|
+
return await openRawServerSentEventStream(transport.fetchImpl, url, handlers, {
|
|
7
|
+
...options,
|
|
8
|
+
authToken: transport.authToken,
|
|
9
|
+
getAuthToken: transport.getAuthToken.bind(transport),
|
|
10
|
+
});
|
|
17
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-transport-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=20.0.0"
|
|
6
|
+
},
|
|
4
7
|
"description": "HTTP, JSON, path, and SSE transport primitives for GoodVibes client integrations.",
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "./dist/index.js",
|
|
@@ -10,6 +13,50 @@
|
|
|
10
13
|
"types": "./dist/index.d.ts",
|
|
11
14
|
"import": "./dist/index.js"
|
|
12
15
|
},
|
|
16
|
+
"./auth": {
|
|
17
|
+
"types": "./dist/auth.d.ts",
|
|
18
|
+
"import": "./dist/auth.js"
|
|
19
|
+
},
|
|
20
|
+
"./backoff": {
|
|
21
|
+
"types": "./dist/backoff.d.ts",
|
|
22
|
+
"import": "./dist/backoff.js"
|
|
23
|
+
},
|
|
24
|
+
"./contract-client": {
|
|
25
|
+
"types": "./dist/contract-client.d.ts",
|
|
26
|
+
"import": "./dist/contract-client.js"
|
|
27
|
+
},
|
|
28
|
+
"./client-plumbing": {
|
|
29
|
+
"types": "./dist/client-plumbing.d.ts",
|
|
30
|
+
"import": "./dist/client-plumbing.js"
|
|
31
|
+
},
|
|
32
|
+
"./http-core": {
|
|
33
|
+
"types": "./dist/http-core.d.ts",
|
|
34
|
+
"import": "./dist/http-core.js"
|
|
35
|
+
},
|
|
36
|
+
"./http": {
|
|
37
|
+
"types": "./dist/http.d.ts",
|
|
38
|
+
"import": "./dist/http.js"
|
|
39
|
+
},
|
|
40
|
+
"./paths": {
|
|
41
|
+
"types": "./dist/paths.d.ts",
|
|
42
|
+
"import": "./dist/paths.js"
|
|
43
|
+
},
|
|
44
|
+
"./reconnect": {
|
|
45
|
+
"types": "./dist/reconnect.d.ts",
|
|
46
|
+
"import": "./dist/reconnect.js"
|
|
47
|
+
},
|
|
48
|
+
"./retry": {
|
|
49
|
+
"types": "./dist/retry.d.ts",
|
|
50
|
+
"import": "./dist/retry.js"
|
|
51
|
+
},
|
|
52
|
+
"./sse-stream": {
|
|
53
|
+
"types": "./dist/sse-stream.d.ts",
|
|
54
|
+
"import": "./dist/sse-stream.js"
|
|
55
|
+
},
|
|
56
|
+
"./sse": {
|
|
57
|
+
"types": "./dist/sse.d.ts",
|
|
58
|
+
"import": "./dist/sse.js"
|
|
59
|
+
},
|
|
13
60
|
"./package.json": "./package.json"
|
|
14
61
|
},
|
|
15
62
|
"files": [
|
|
@@ -32,10 +79,12 @@
|
|
|
32
79
|
"sse",
|
|
33
80
|
"transport"
|
|
34
81
|
],
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"@pellux/goodvibes-errors": "0.30.0",
|
|
84
|
+
"@pellux/goodvibes-transport-core": "0.30.0",
|
|
85
|
+
"zod": "^4.3.6"
|
|
86
|
+
},
|
|
35
87
|
"publishConfig": {
|
|
36
88
|
"access": "public"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@pellux/goodvibes-errors": "0.18.3"
|
|
40
89
|
}
|
|
41
90
|
}
|