@pellux/goodvibes-sdk 0.19.6 → 0.19.9
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/_internal/contracts/index.d.ts +1 -0
- package/dist/_internal/contracts/index.d.ts.map +1 -1
- package/dist/_internal/contracts/index.js +2 -0
- package/dist/_internal/contracts/types.d.ts +4 -0
- package/dist/_internal/contracts/types.d.ts.map +1 -1
- package/dist/_internal/contracts/zod-schemas/accounts.d.ts +81 -0
- package/dist/_internal/contracts/zod-schemas/accounts.d.ts.map +1 -0
- package/dist/_internal/contracts/zod-schemas/accounts.js +47 -0
- package/dist/_internal/contracts/zod-schemas/auth.d.ts +42 -0
- package/dist/_internal/contracts/zod-schemas/auth.d.ts.map +1 -0
- package/dist/_internal/contracts/zod-schemas/auth.js +29 -0
- package/dist/_internal/contracts/zod-schemas/events.d.ts +37 -0
- package/dist/_internal/contracts/zod-schemas/events.d.ts.map +1 -0
- package/dist/_internal/contracts/zod-schemas/events.js +26 -0
- package/dist/_internal/contracts/zod-schemas/index.d.ts +9 -0
- package/dist/_internal/contracts/zod-schemas/index.d.ts.map +1 -0
- package/dist/_internal/contracts/zod-schemas/index.js +4 -0
- package/dist/_internal/contracts/zod-schemas/session.d.ts +22 -0
- package/dist/_internal/contracts/zod-schemas/session.d.ts.map +1 -0
- package/dist/_internal/contracts/zod-schemas/session.js +19 -0
- package/dist/_internal/daemon/api-router.d.ts.map +1 -1
- package/dist/_internal/daemon/api-router.js +0 -1
- package/dist/_internal/daemon/automation.d.ts.map +1 -1
- package/dist/_internal/daemon/channel-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/channel-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/context.d.ts.map +1 -1
- package/dist/_internal/daemon/control-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/http-policy.d.ts.map +1 -1
- package/dist/_internal/daemon/http-policy.js +0 -1
- package/dist/_internal/daemon/integration-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/integration-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-routes.js +5 -4
- package/dist/_internal/daemon/media-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/media-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/operator.d.ts.map +1 -1
- package/dist/_internal/daemon/remote-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/remote.d.ts.map +1 -1
- package/dist/_internal/daemon/route-helpers.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-automation-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-route-types.d.ts +14 -1
- package/dist/_internal/daemon/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-session-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-session-routes.js +0 -2
- package/dist/_internal/daemon/sessions.d.ts.map +1 -1
- package/dist/_internal/daemon/system-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/system-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/tasks.d.ts.map +1 -1
- package/dist/_internal/daemon/telemetry-routes.d.ts.map +1 -1
- package/dist/_internal/errors/daemon-error-contract.d.ts.map +1 -1
- package/dist/_internal/errors/index.d.ts +2 -2
- package/dist/_internal/errors/index.js +2 -2
- package/dist/_internal/operator/client-core.d.ts.map +1 -1
- package/dist/_internal/operator/client-core.js +8 -2
- package/dist/_internal/operator/client.d.ts +7 -0
- package/dist/_internal/operator/client.d.ts.map +1 -1
- package/dist/_internal/operator/client.js +32 -1
- package/dist/_internal/peer/client-core.d.ts.map +1 -1
- package/dist/_internal/platform/agents/orchestrator.d.ts +7 -0
- package/dist/_internal/platform/agents/orchestrator.d.ts.map +1 -1
- package/dist/_internal/platform/agents/orchestrator.js +8 -0
- package/dist/_internal/platform/auth/android-keystore-token-store.d.ts +110 -0
- package/dist/_internal/platform/auth/android-keystore-token-store.d.ts.map +1 -0
- package/dist/_internal/platform/auth/android-keystore-token-store.js +164 -0
- package/dist/_internal/platform/auth/auto-refresh-middleware.d.ts +46 -0
- package/dist/_internal/platform/auth/auto-refresh-middleware.d.ts.map +1 -0
- package/dist/_internal/platform/auth/auto-refresh-middleware.js +155 -0
- package/dist/_internal/platform/auth/auto-refresh.d.ts +123 -0
- package/dist/_internal/platform/auth/auto-refresh.d.ts.map +1 -0
- package/dist/_internal/platform/auth/auto-refresh.js +236 -0
- package/dist/_internal/platform/auth/expo-secure-token-store.d.ts +82 -0
- package/dist/_internal/platform/auth/expo-secure-token-store.d.ts.map +1 -0
- package/dist/_internal/platform/auth/expo-secure-token-store.js +135 -0
- package/dist/_internal/platform/auth/index.d.ts +3 -0
- package/dist/_internal/platform/auth/index.d.ts.map +1 -1
- package/dist/_internal/platform/auth/index.js +2 -0
- package/dist/_internal/platform/auth/ios-keychain-token-store.d.ts +88 -0
- package/dist/_internal/platform/auth/ios-keychain-token-store.d.ts.map +1 -0
- package/dist/_internal/platform/auth/ios-keychain-token-store.js +147 -0
- package/dist/_internal/platform/auth/session-manager.d.ts +2 -0
- package/dist/_internal/platform/auth/session-manager.d.ts.map +1 -1
- package/dist/_internal/platform/auth/session-manager.js +9 -1
- package/dist/_internal/platform/auth/token-store.d.ts +13 -0
- package/dist/_internal/platform/auth/token-store.d.ts.map +1 -1
- package/dist/_internal/platform/auth/token-store.js +23 -0
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts +64 -11
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -1
- package/dist/_internal/platform/companion/companion-chat-manager.js +158 -12
- package/dist/_internal/platform/companion/companion-chat-persistence.d.ts +33 -0
- package/dist/_internal/platform/companion/companion-chat-persistence.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-persistence.js +115 -0
- package/dist/_internal/platform/companion/companion-chat-rate-limiter.d.ts +47 -0
- package/dist/_internal/platform/companion/companion-chat-rate-limiter.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-rate-limiter.js +117 -0
- package/dist/_internal/platform/companion/companion-chat-types.d.ts +2 -4
- package/dist/_internal/platform/companion/companion-chat-types.d.ts.map +1 -1
- package/dist/_internal/platform/companion/companion-chat-types.js +2 -4
- package/dist/_internal/platform/companion/index.d.ts +4 -0
- package/dist/_internal/platform/companion/index.d.ts.map +1 -1
- package/dist/_internal/platform/companion/index.js +2 -0
- package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.js +5 -0
- package/dist/_internal/platform/daemon/facade.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade.js +3 -0
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts +0 -7
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/platform/state/db.d.ts.map +1 -1
- package/dist/_internal/platform/state/db.js +0 -1
- package/dist/_internal/platform/state/sqlite-store.d.ts.map +1 -1
- package/dist/_internal/platform/state/sqlite-store.js +0 -1
- package/dist/_internal/platform/version.js +1 -1
- package/dist/_internal/transport-core/client-transport.d.ts.map +1 -1
- package/dist/_internal/transport-core/event-envelope.d.ts.map +1 -1
- package/dist/_internal/transport-core/event-feeds.d.ts.map +1 -1
- package/dist/_internal/transport-core/index.d.ts +5 -0
- package/dist/_internal/transport-core/index.d.ts.map +1 -1
- package/dist/_internal/transport-core/index.js +3 -0
- package/dist/_internal/transport-core/middleware.d.ts +76 -0
- package/dist/_internal/transport-core/middleware.d.ts.map +1 -0
- package/dist/_internal/transport-core/middleware.js +67 -0
- package/dist/_internal/transport-core/observer.d.ts +53 -0
- package/dist/_internal/transport-core/observer.d.ts.map +1 -0
- package/dist/_internal/transport-core/observer.js +26 -0
- package/dist/_internal/transport-core/otel.d.ts +64 -0
- package/dist/_internal/transport-core/otel.d.ts.map +1 -0
- package/dist/_internal/transport-core/otel.js +149 -0
- package/dist/_internal/transport-direct/index.d.ts.map +1 -1
- package/dist/_internal/transport-direct/index.js +0 -1
- package/dist/_internal/transport-http/contract-client.d.ts +11 -1
- package/dist/_internal/transport-http/contract-client.d.ts.map +1 -1
- package/dist/_internal/transport-http/contract-client.js +18 -4
- package/dist/_internal/transport-http/http-core.d.ts +27 -1
- package/dist/_internal/transport-http/http-core.d.ts.map +1 -1
- package/dist/_internal/transport-http/http-core.js +180 -12
- package/dist/_internal/transport-http/http.d.ts +3 -3
- package/dist/_internal/transport-http/http.d.ts.map +1 -1
- package/dist/_internal/transport-http/http.js +2 -2
- package/dist/_internal/transport-http/index.d.ts +4 -2
- package/dist/_internal/transport-http/index.d.ts.map +1 -1
- package/dist/_internal/transport-http/index.js +2 -1
- package/dist/_internal/transport-http/paths.js +1 -1
- package/dist/_internal/transport-http/reconnect.d.ts +2 -0
- package/dist/_internal/transport-http/reconnect.d.ts.map +1 -1
- package/dist/_internal/transport-http/reconnect.js +4 -2
- package/dist/_internal/transport-http/retry.d.ts +15 -0
- package/dist/_internal/transport-http/retry.d.ts.map +1 -1
- package/dist/_internal/transport-http/retry.js +19 -0
- package/dist/_internal/transport-realtime/domain-events.d.ts.map +1 -1
- package/dist/_internal/transport-realtime/runtime-events.d.ts +10 -3
- package/dist/_internal/transport-realtime/runtime-events.d.ts.map +1 -1
- package/dist/_internal/transport-realtime/runtime-events.js +73 -8
- package/dist/auth.d.ts +38 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +68 -3
- package/dist/client.d.ts +61 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +64 -3
- package/dist/expo.d.ts +1 -0
- package/dist/expo.d.ts.map +1 -1
- package/dist/expo.js +1 -0
- package/dist/observer/index.d.ts +16 -25
- package/dist/observer/index.d.ts.map +1 -1
- package/dist/platform/runtime/transports/http.js +1 -1
- package/dist/react-native.d.ts +2 -0
- package/dist/react-native.d.ts.map +1 -1
- package/dist/react-native.js +2 -0
- package/package.json +16 -3
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Synced from packages/transport-realtime/src/runtime-events.ts
|
|
2
|
-
// Extracted from legacy source: src/runtime/transports/runtime-events-client.ts
|
|
3
2
|
import { RUNTIME_EVENT_DOMAINS } from '../contracts/index.js';
|
|
4
3
|
import { normalizeAuthToken, openRawServerSentEventStream as openServerSentEventStream, normalizeStreamReconnectPolicy, getStreamReconnectDelay, } from '../transport-http/index.js';
|
|
5
4
|
import { buildUrl, normalizeBaseUrl } from '../transport-http/index.js';
|
|
5
|
+
import { injectTraceparentAsync, invokeTransportObserver } from '../transport-core/index.js';
|
|
6
6
|
import { createRemoteDomainEvents, } from './domain-events.js';
|
|
7
7
|
/**
|
|
8
8
|
* Returns a filtered view of a {@link RemoteRuntimeEvents} object where every
|
|
@@ -33,8 +33,8 @@ import { createRemoteDomainEvents, } from './domain-events.js';
|
|
|
33
33
|
export { forSession as forSessionRuntime } from './domain-events.js';
|
|
34
34
|
/** Default max reconnect attempts for WebSocket connections (finite to prevent infinite auth loops). */
|
|
35
35
|
export const DEFAULT_WS_MAX_ATTEMPTS = 10;
|
|
36
|
-
/** Maximum number of messages that may be queued in
|
|
37
|
-
const MAX_OUTBOUND_QUEUE =
|
|
36
|
+
/** Maximum number of messages that may be queued in the outbound queue before the oldest entry is dropped. */
|
|
37
|
+
const MAX_OUTBOUND_QUEUE = 1024;
|
|
38
38
|
export function createRemoteRuntimeEvents(connect) {
|
|
39
39
|
return createRemoteDomainEvents(RUNTIME_EVENT_DOMAINS, connect);
|
|
40
40
|
}
|
|
@@ -53,26 +53,45 @@ export function buildWebSocketUrl(baseUrl, domains) {
|
|
|
53
53
|
return url.toString();
|
|
54
54
|
}
|
|
55
55
|
export function createEventSourceConnector(baseUrl, token, fetchImpl, options = {}) {
|
|
56
|
+
const { observer } = options;
|
|
56
57
|
const handleError = options.onError ?? (options.reconnect?.enabled ? (() => { }) : undefined);
|
|
57
58
|
return async (domain, onEnvelope) => {
|
|
58
59
|
const url = buildEventSourceUrl(baseUrl, domain);
|
|
59
60
|
const getAuthToken = normalizeAuthToken(token ?? undefined);
|
|
61
|
+
// Inject W3C traceparent if OTel is active (async probe for SSE cold-start).
|
|
62
|
+
const sseHeaders = {};
|
|
63
|
+
await injectTraceparentAsync(sseHeaders);
|
|
64
|
+
// Notify observer of outbound SSE connection attempt.
|
|
65
|
+
invokeTransportObserver(() => observer?.onTransportActivity?.({ direction: 'send', url, kind: 'sse' }));
|
|
60
66
|
return await openServerSentEventStream(fetchImpl, url, {
|
|
61
67
|
onEvent: (eventName, payload) => {
|
|
62
68
|
if (eventName !== domain)
|
|
63
69
|
return;
|
|
64
70
|
if (!payload || typeof payload !== 'object')
|
|
65
71
|
return;
|
|
66
|
-
|
|
72
|
+
const envelope = payload;
|
|
73
|
+
onEnvelope(envelope);
|
|
74
|
+
// Notify observer of inbound event.
|
|
75
|
+
invokeTransportObserver(() => {
|
|
76
|
+
observer?.onTransportActivity?.({ direction: 'recv', url, kind: 'sse' });
|
|
77
|
+
if (envelope.payload) {
|
|
78
|
+
observer?.onEvent?.(envelope.payload);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
onError: (err) => {
|
|
83
|
+
invokeTransportObserver(() => observer?.onError?.(err instanceof Error ? err : new Error(String(err))));
|
|
84
|
+
handleError?.(err);
|
|
67
85
|
},
|
|
68
|
-
onError: handleError,
|
|
69
86
|
}, {
|
|
70
87
|
reconnect: options.reconnect,
|
|
71
88
|
getAuthToken,
|
|
89
|
+
headers: Object.keys(sseHeaders).length > 0 ? sseHeaders : undefined,
|
|
72
90
|
});
|
|
73
91
|
};
|
|
74
92
|
}
|
|
75
93
|
export function createWebSocketConnector(baseUrl, token, WebSocketImpl, options = {}) {
|
|
94
|
+
const { observer } = options;
|
|
76
95
|
return async (domain, onEnvelope) => {
|
|
77
96
|
const url = buildWebSocketUrl(baseUrl, [domain]);
|
|
78
97
|
const reconnect = options.reconnect;
|
|
@@ -88,9 +107,39 @@ export function createWebSocketConnector(baseUrl, token, WebSocketImpl, options
|
|
|
88
107
|
let hasReceivedMessage = false;
|
|
89
108
|
let socket = null;
|
|
90
109
|
let reconnectTimer = null;
|
|
91
|
-
//
|
|
92
|
-
//
|
|
110
|
+
// Bounded outbound message queue — max MAX_OUTBOUND_QUEUE entries, drop-oldest policy.
|
|
111
|
+
// Messages pushed while the socket is not yet open or is reconnecting are buffered here
|
|
112
|
+
// and flushed on the next successful open event.
|
|
93
113
|
const outboundQueue = [];
|
|
114
|
+
let droppedOutboundCount = 0;
|
|
115
|
+
/**
|
|
116
|
+
* Enqueue a message for delivery over this WebSocket connection.
|
|
117
|
+
*
|
|
118
|
+
* If the socket is currently open the message is sent immediately.
|
|
119
|
+
* If the socket is not yet open (or is reconnecting), the message is
|
|
120
|
+
* buffered and will be flushed once the connection is re-established.
|
|
121
|
+
*
|
|
122
|
+
* When the buffer is full (> MAX_OUTBOUND_QUEUE), the oldest pending
|
|
123
|
+
* message is silently dropped and a counter is incremented. Callers that
|
|
124
|
+
* need back-pressure should check `socket?.readyState` before calling.
|
|
125
|
+
*
|
|
126
|
+
* @param data - Serialised message string to send.
|
|
127
|
+
*/
|
|
128
|
+
const emitLocal = (data) => {
|
|
129
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
130
|
+
socket.send(data);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (outboundQueue.length >= MAX_OUTBOUND_QUEUE) {
|
|
134
|
+
// Drop oldest message to make room (drop-oldest policy).
|
|
135
|
+
outboundQueue.shift();
|
|
136
|
+
droppedOutboundCount += 1;
|
|
137
|
+
options.onError?.(new Error(`WebSocket outbound queue full (limit ${MAX_OUTBOUND_QUEUE}). Oldest message dropped; total dropped: ${droppedOutboundCount}.`));
|
|
138
|
+
}
|
|
139
|
+
outboundQueue.push(data);
|
|
140
|
+
};
|
|
141
|
+
// Notify caller of the emitter handle (for test/shim use cases).
|
|
142
|
+
options.onEmitter?.(emitLocal);
|
|
94
143
|
const closeSocket = () => {
|
|
95
144
|
if (!socket)
|
|
96
145
|
return;
|
|
@@ -124,11 +173,18 @@ export function createWebSocketConnector(baseUrl, token, WebSocketImpl, options
|
|
|
124
173
|
const authToken = (await normalizeAuthToken(token ?? undefined)()) ?? null;
|
|
125
174
|
if (!authToken || !socket)
|
|
126
175
|
return;
|
|
176
|
+
// Notify observer of outbound WS connection.
|
|
177
|
+
invokeTransportObserver(() => observer?.onTransportActivity?.({ direction: 'send', url, kind: 'ws' }));
|
|
127
178
|
// Send auth frame first, then drain any messages buffered during resolution.
|
|
179
|
+
// Inject traceparent into the auth frame for W3C Trace Context propagation over WebSocket.
|
|
180
|
+
const wsTraceHeaders = {};
|
|
181
|
+
await injectTraceparentAsync(wsTraceHeaders);
|
|
128
182
|
socket.send(JSON.stringify({
|
|
129
183
|
type: 'auth',
|
|
130
184
|
token: authToken,
|
|
131
185
|
domains: [domain],
|
|
186
|
+
...(wsTraceHeaders['traceparent'] ? { traceparent: wsTraceHeaders['traceparent'] } : {}),
|
|
187
|
+
...(wsTraceHeaders['tracestate'] ? { tracestate: wsTraceHeaders['tracestate'] } : {}),
|
|
132
188
|
}));
|
|
133
189
|
flushOutboundQueue(socket);
|
|
134
190
|
};
|
|
@@ -142,7 +198,15 @@ export function createWebSocketConnector(baseUrl, token, WebSocketImpl, options
|
|
|
142
198
|
hasReceivedMessage = true;
|
|
143
199
|
reconnectAttempt = 0;
|
|
144
200
|
}
|
|
145
|
-
|
|
201
|
+
const wsPayload = frame.payload;
|
|
202
|
+
onEnvelope(wsPayload);
|
|
203
|
+
// Notify observer of inbound WS event.
|
|
204
|
+
invokeTransportObserver(() => {
|
|
205
|
+
observer?.onTransportActivity?.({ direction: 'recv', url, kind: 'ws' });
|
|
206
|
+
if (wsPayload.payload) {
|
|
207
|
+
observer?.onEvent?.(wsPayload.payload);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
146
210
|
}
|
|
147
211
|
}
|
|
148
212
|
catch {
|
|
@@ -155,6 +219,7 @@ export function createWebSocketConnector(baseUrl, token, WebSocketImpl, options
|
|
|
155
219
|
scheduleReconnect();
|
|
156
220
|
};
|
|
157
221
|
const onError = (event) => {
|
|
222
|
+
invokeTransportObserver(() => observer?.onError?.(event instanceof Error ? event : new Error(String(event))));
|
|
158
223
|
options.onError?.(event);
|
|
159
224
|
};
|
|
160
225
|
const connect = async () => {
|
package/dist/auth.d.ts
CHANGED
|
@@ -2,16 +2,38 @@ import type { SDKObserver } from './observer/index.js';
|
|
|
2
2
|
import type { OperatorMethodInput, OperatorMethodOutput } from './_internal/contracts/index.js';
|
|
3
3
|
import type { AuthTokenResolver } from './_internal/transport-http/index.js';
|
|
4
4
|
import type { OperatorSdk } from './_internal/operator/index.js';
|
|
5
|
-
import { PermissionResolver, SessionManager, TokenStore } from './_internal/platform/auth/index.js';
|
|
5
|
+
import { AutoRefreshCoordinator, PermissionResolver, SessionManager, TokenStore } from './_internal/platform/auth/index.js';
|
|
6
|
+
import type { AutoRefreshOptions } from './_internal/platform/auth/index.js';
|
|
6
7
|
export { PermissionResolver, SessionManager, TokenStore } from './_internal/platform/auth/index.js';
|
|
7
8
|
export type { OAuthStartState, OAuthTokenPayload } from './_internal/platform/auth/oauth-types.js';
|
|
8
9
|
export type GoodVibesCurrentAuth = OperatorMethodOutput<'control.auth.current'>;
|
|
9
10
|
export type GoodVibesLoginInput = OperatorMethodInput<'control.auth.login'>;
|
|
10
11
|
export type GoodVibesLoginOutput = OperatorMethodOutput<'control.auth.login'>;
|
|
12
|
+
/**
|
|
13
|
+
* Token storage interface for the GoodVibes SDK.
|
|
14
|
+
*
|
|
15
|
+
* Implement all three core methods. The optional `getTokenEntry` / `setTokenEntry`
|
|
16
|
+
* methods are used by auto-refresh to track token expiry without requiring
|
|
17
|
+
* consumers to change their existing `GoodVibesTokenStore` implementations.
|
|
18
|
+
*/
|
|
11
19
|
export interface GoodVibesTokenStore {
|
|
12
20
|
getToken(): Promise<string | null>;
|
|
13
21
|
setToken(token: string | null): Promise<void>;
|
|
14
22
|
clearToken(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Return the current token and its expiry timestamp (unix ms).
|
|
25
|
+
* Optional: when absent, auto-refresh falls back to `getToken()` with no
|
|
26
|
+
* expiry tracking (leeway-based pre-flight checks are disabled).
|
|
27
|
+
*/
|
|
28
|
+
getTokenEntry?(): Promise<{
|
|
29
|
+
token: string | null;
|
|
30
|
+
expiresAt?: number;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Persist a token alongside its expiry timestamp (unix ms).
|
|
34
|
+
* Optional: when absent, auto-refresh falls back to `setToken()`.
|
|
35
|
+
*/
|
|
36
|
+
setTokenEntry?(token: string | null, expiresAt?: number): Promise<void>;
|
|
15
37
|
}
|
|
16
38
|
export interface BrowserTokenStoreOptions {
|
|
17
39
|
readonly key?: string;
|
|
@@ -57,6 +79,12 @@ export interface GoodVibesAuthClient {
|
|
|
57
79
|
/** Clear the stored token. Delegates to `TokenStore.clearToken()`. */
|
|
58
80
|
clearToken(): Promise<void>;
|
|
59
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Options for the auto-refresh feature on the auth client.
|
|
84
|
+
*
|
|
85
|
+
* @see AutoRefreshOptions
|
|
86
|
+
*/
|
|
87
|
+
export type { AutoRefreshOptions };
|
|
60
88
|
/**
|
|
61
89
|
* Create a simple in-memory token store.
|
|
62
90
|
*
|
|
@@ -70,7 +98,7 @@ export interface GoodVibesAuthClient {
|
|
|
70
98
|
* const sdk = createGoodVibesSdk({ baseUrl: '...', tokenStore: store });
|
|
71
99
|
* await sdk.auth.clearToken(); // clears only in-memory
|
|
72
100
|
*/
|
|
73
|
-
export declare function createMemoryTokenStore(initialToken?: string | null): GoodVibesTokenStore;
|
|
101
|
+
export declare function createMemoryTokenStore(initialToken?: string | null, initialExpiresAt?: number): GoodVibesTokenStore;
|
|
74
102
|
/**
|
|
75
103
|
* Create a token store backed by `localStorage` (or a custom `Storage`).
|
|
76
104
|
*
|
|
@@ -108,5 +136,12 @@ export declare function createBrowserTokenStore(options?: BrowserTokenStoreOptio
|
|
|
108
136
|
* // Later: clear the session
|
|
109
137
|
* await sdk.auth.clearToken();
|
|
110
138
|
*/
|
|
111
|
-
export declare function createGoodVibesAuthClient(operator: OperatorSdk, tokenStore: GoodVibesTokenStore | null, getAuthToken?: AuthTokenResolver, observer?: SDKObserver
|
|
139
|
+
export declare function createGoodVibesAuthClient(operator: OperatorSdk, tokenStore: GoodVibesTokenStore | null, getAuthToken?: AuthTokenResolver, observer?: SDKObserver, autoRefreshOptions?: AutoRefreshOptions,
|
|
140
|
+
/**
|
|
141
|
+
* Optional pre-built `AutoRefreshCoordinator`. When provided, it is reused
|
|
142
|
+
* directly (no new coordinator is constructed). This allows `createGoodVibesSdk`
|
|
143
|
+
* to share a single coordinator instance between the transport middleware and
|
|
144
|
+
* the auth client, avoiding duplicate refresh calls.
|
|
145
|
+
*/
|
|
146
|
+
existingCoordinator?: AutoRefreshCoordinator | null): GoodVibesAuthClient;
|
|
112
147
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,UAAU,EACX,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConfigurationError } from './_internal/errors/index.js';
|
|
2
2
|
import { invokeObserver } from './observer/index.js';
|
|
3
|
-
import { PermissionResolver, SessionManager, TokenStore, } from './_internal/platform/auth/index.js';
|
|
3
|
+
import { AutoRefreshCoordinator, PermissionResolver, SessionManager, TokenStore, } from './_internal/platform/auth/index.js';
|
|
4
4
|
// Re-export focused responsibility classes for consumers who prefer
|
|
5
5
|
// narrower, single-concern APIs over the combined GoodVibesAuthClient facade.
|
|
6
6
|
// NOTE: OAuthClient is intentionally NOT re-exported here. It depends on
|
|
@@ -30,17 +30,29 @@ function requireStorage(storage) {
|
|
|
30
30
|
* const sdk = createGoodVibesSdk({ baseUrl: '...', tokenStore: store });
|
|
31
31
|
* await sdk.auth.clearToken(); // clears only in-memory
|
|
32
32
|
*/
|
|
33
|
-
export function createMemoryTokenStore(initialToken = null) {
|
|
33
|
+
export function createMemoryTokenStore(initialToken = null, initialExpiresAt) {
|
|
34
34
|
let token = initialToken;
|
|
35
|
+
let expiresAt = initialExpiresAt;
|
|
35
36
|
return {
|
|
36
37
|
async getToken() {
|
|
37
38
|
return token;
|
|
38
39
|
},
|
|
39
40
|
async setToken(nextToken) {
|
|
40
41
|
token = nextToken;
|
|
42
|
+
// When setToken is called directly (not via setTokenEntry), clear expiry
|
|
43
|
+
// to avoid stale expiry data attached to a manually-set token.
|
|
44
|
+
expiresAt = undefined;
|
|
41
45
|
},
|
|
42
46
|
async clearToken() {
|
|
43
47
|
token = null;
|
|
48
|
+
expiresAt = undefined;
|
|
49
|
+
},
|
|
50
|
+
async getTokenEntry() {
|
|
51
|
+
return { token, expiresAt };
|
|
52
|
+
},
|
|
53
|
+
async setTokenEntry(nextToken, nextExpiresAt) {
|
|
54
|
+
token = nextToken;
|
|
55
|
+
expiresAt = nextExpiresAt;
|
|
44
56
|
},
|
|
45
57
|
};
|
|
46
58
|
}
|
|
@@ -62,6 +74,7 @@ export function createMemoryTokenStore(initialToken = null) {
|
|
|
62
74
|
export function createBrowserTokenStore(options = {}) {
|
|
63
75
|
const storage = requireStorage(options.storage);
|
|
64
76
|
const key = options.key?.trim() || 'goodvibes.token';
|
|
77
|
+
const expiresAtKey = `${key}.expiresAt`;
|
|
65
78
|
return {
|
|
66
79
|
async getToken() {
|
|
67
80
|
const value = storage.getItem(key);
|
|
@@ -70,12 +83,37 @@ export function createBrowserTokenStore(options = {}) {
|
|
|
70
83
|
async setToken(token) {
|
|
71
84
|
if (!token) {
|
|
72
85
|
storage.removeItem(key);
|
|
86
|
+
storage.removeItem(expiresAtKey);
|
|
73
87
|
return;
|
|
74
88
|
}
|
|
75
89
|
storage.setItem(key, token);
|
|
90
|
+
// Clear expiry when set via setToken (no expiry info provided).
|
|
91
|
+
storage.removeItem(expiresAtKey);
|
|
76
92
|
},
|
|
77
93
|
async clearToken() {
|
|
78
94
|
storage.removeItem(key);
|
|
95
|
+
storage.removeItem(expiresAtKey);
|
|
96
|
+
},
|
|
97
|
+
async getTokenEntry() {
|
|
98
|
+
const value = storage.getItem(key);
|
|
99
|
+
const token = value && value.trim() ? value : null;
|
|
100
|
+
const expiresAtStr = storage.getItem(expiresAtKey);
|
|
101
|
+
const expiresAt = expiresAtStr ? parseInt(expiresAtStr, 10) : undefined;
|
|
102
|
+
return { token, expiresAt: Number.isFinite(expiresAt) ? expiresAt : undefined };
|
|
103
|
+
},
|
|
104
|
+
async setTokenEntry(token, expiresAt) {
|
|
105
|
+
if (!token) {
|
|
106
|
+
storage.removeItem(key);
|
|
107
|
+
storage.removeItem(expiresAtKey);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
storage.setItem(key, token);
|
|
111
|
+
if (expiresAt !== undefined) {
|
|
112
|
+
storage.setItem(expiresAtKey, String(expiresAt));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
storage.removeItem(expiresAtKey);
|
|
116
|
+
}
|
|
79
117
|
},
|
|
80
118
|
};
|
|
81
119
|
}
|
|
@@ -115,11 +153,34 @@ function assertWritableTokenStore(tokenStore) {
|
|
|
115
153
|
* // Later: clear the session
|
|
116
154
|
* await sdk.auth.clearToken();
|
|
117
155
|
*/
|
|
118
|
-
export function createGoodVibesAuthClient(operator, tokenStore, getAuthToken, observer
|
|
156
|
+
export function createGoodVibesAuthClient(operator, tokenStore, getAuthToken, observer, autoRefreshOptions,
|
|
157
|
+
/**
|
|
158
|
+
* Optional pre-built `AutoRefreshCoordinator`. When provided, it is reused
|
|
159
|
+
* directly (no new coordinator is constructed). This allows `createGoodVibesSdk`
|
|
160
|
+
* to share a single coordinator instance between the transport middleware and
|
|
161
|
+
* the auth client, avoiding duplicate refresh calls.
|
|
162
|
+
*/
|
|
163
|
+
existingCoordinator) {
|
|
119
164
|
// Construct the split-class instances that own each concern.
|
|
120
165
|
// The facade delegates to these rather than duplicating logic.
|
|
121
166
|
const ts = tokenStore ? new TokenStore(tokenStore) : null;
|
|
122
167
|
const sm = new SessionManager(operator, ts);
|
|
168
|
+
// Use the provided coordinator if available; otherwise build one.
|
|
169
|
+
const coordinator = existingCoordinator !== undefined
|
|
170
|
+
? existingCoordinator
|
|
171
|
+
: (() => {
|
|
172
|
+
const autoRefresh = autoRefreshOptions?.autoRefresh ?? true;
|
|
173
|
+
const refreshLeewayMs = autoRefreshOptions?.refreshLeewayMs ?? 60_000;
|
|
174
|
+
return tokenStore && autoRefresh
|
|
175
|
+
? new AutoRefreshCoordinator({
|
|
176
|
+
tokenStore,
|
|
177
|
+
autoRefresh,
|
|
178
|
+
refreshLeewayMs,
|
|
179
|
+
refresh: autoRefreshOptions?.refresh,
|
|
180
|
+
observer,
|
|
181
|
+
})
|
|
182
|
+
: null;
|
|
183
|
+
})();
|
|
123
184
|
return {
|
|
124
185
|
get writable() {
|
|
125
186
|
return sm.writable;
|
|
@@ -134,6 +195,10 @@ export function createGoodVibesAuthClient(operator, tokenStore, getAuthToken, ob
|
|
|
134
195
|
return new PermissionResolver(snapshot);
|
|
135
196
|
},
|
|
136
197
|
async current() {
|
|
198
|
+
if (coordinator) {
|
|
199
|
+
await coordinator.ensureFreshToken();
|
|
200
|
+
return coordinator.withRetryOn401(() => sm.current());
|
|
201
|
+
}
|
|
137
202
|
return sm.current();
|
|
138
203
|
},
|
|
139
204
|
async login(input, options = {}) {
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type OperatorSdk } from './_internal/operator/index.js';
|
|
2
2
|
import { type PeerSdk } from './_internal/peer/index.js';
|
|
3
|
-
import type { AuthTokenResolver, HeaderResolver, HttpRetryPolicy, StreamReconnectPolicy } from './_internal/transport-http/index.js';
|
|
3
|
+
import type { AuthTokenResolver, HeaderResolver, HttpRetryPolicy, StreamReconnectPolicy, TransportMiddleware } from './_internal/transport-http/index.js';
|
|
4
4
|
import { type RemoteRuntimeEvents } from './_internal/transport-realtime/index.js';
|
|
5
5
|
import type { AnyRuntimeEvent } from './_internal/platform/runtime/events/index.js';
|
|
6
|
-
import { type GoodVibesAuthClient, type GoodVibesTokenStore } from './auth.js';
|
|
6
|
+
import { type AutoRefreshOptions, type GoodVibesAuthClient, type GoodVibesTokenStore } from './auth.js';
|
|
7
|
+
import type { SDKObserver } from './observer/index.js';
|
|
7
8
|
/**
|
|
8
9
|
* Discriminated union of all runtime events emitted by the GoodVibes daemon.
|
|
9
10
|
*
|
|
@@ -108,6 +109,50 @@ export interface GoodVibesSdkOptions {
|
|
|
108
109
|
* reconnect policies, error callback).
|
|
109
110
|
*/
|
|
110
111
|
readonly realtime?: GoodVibesRealtimeOptions;
|
|
112
|
+
/**
|
|
113
|
+
* Optional observer for SDK-level observability hooks.
|
|
114
|
+
*
|
|
115
|
+
* Pass a `SDKObserver` implementation (or one of the built-in adapters
|
|
116
|
+
* like `createConsoleObserver` / `createOpenTelemetryObserver`) to receive
|
|
117
|
+
* callbacks for auth transitions, transport activity, events, and errors.
|
|
118
|
+
*
|
|
119
|
+
* All observer methods are wrapped in a silent try/catch — observer
|
|
120
|
+
* exceptions never propagate into SDK logic.
|
|
121
|
+
*/
|
|
122
|
+
readonly observer?: SDKObserver;
|
|
123
|
+
/**
|
|
124
|
+
* Initial middleware chain applied to every HTTP request/response cycle.
|
|
125
|
+
*
|
|
126
|
+
* Middleware functions receive a mutable `TransportContext` and a `next()`
|
|
127
|
+
* callback. They run in the order provided (outer-first, onion model).
|
|
128
|
+
*
|
|
129
|
+
* Additional middleware can be appended at any time via `sdk.use(mw)`.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* const sdk = createGoodVibesSdk({
|
|
133
|
+
* baseUrl: 'https://daemon.example.com',
|
|
134
|
+
* middleware: [
|
|
135
|
+
* async (ctx, next) => {
|
|
136
|
+
* ctx.headers['X-Request-Id'] = crypto.randomUUID();
|
|
137
|
+
* await next();
|
|
138
|
+
* },
|
|
139
|
+
* ],
|
|
140
|
+
* });
|
|
141
|
+
*/
|
|
142
|
+
readonly middleware?: TransportMiddleware[];
|
|
143
|
+
/**
|
|
144
|
+
* Options for silent token auto-refresh.
|
|
145
|
+
*
|
|
146
|
+
* - `autoRefresh` — when `false`, disables silent refresh entirely and lets
|
|
147
|
+
* 401 responses propagate to the caller immediately. Default: `true`.
|
|
148
|
+
* - `refreshLeewayMs` — milliseconds before token expiry to trigger a
|
|
149
|
+
* pre-flight refresh. Default: 60_000 (1 minute).
|
|
150
|
+
* - `refresh` — optional callback invoked to obtain a new token on pre-flight
|
|
151
|
+
* leeway trigger or reactive 401. When absent, pre-flight is a no-op and
|
|
152
|
+
* 401 retry re-reads the token store (useful when an external party updates
|
|
153
|
+
* it). See `AutoRefreshOptions.refresh` for a full example.
|
|
154
|
+
*/
|
|
155
|
+
readonly autoRefresh?: AutoRefreshOptions;
|
|
111
156
|
}
|
|
112
157
|
/**
|
|
113
158
|
* Options controlling realtime transport behaviour.
|
|
@@ -184,6 +229,20 @@ export interface GoodVibesSdk {
|
|
|
184
229
|
* @see https://github.com/mgd34msu/goodvibes-sdk/blob/main/docs/realtime-and-telemetry.md
|
|
185
230
|
*/
|
|
186
231
|
readonly realtime: GoodVibesRealtime;
|
|
232
|
+
/**
|
|
233
|
+
* Append a middleware to the SDK's HTTP transport chain.
|
|
234
|
+
*
|
|
235
|
+
* Multiple `use()` calls compose in order (outer-first). The method is
|
|
236
|
+
* idempotent in the sense that each call simply appends — call it once per
|
|
237
|
+
* middleware to avoid double-registration.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* sdk.use(async (ctx, next) => {
|
|
241
|
+
* ctx.headers['X-Tenant-Id'] = 'acme';
|
|
242
|
+
* await next();
|
|
243
|
+
* });
|
|
244
|
+
*/
|
|
245
|
+
use(middleware: TransportMiddleware): void;
|
|
187
246
|
}
|
|
188
247
|
/**
|
|
189
248
|
* Create a GoodVibes SDK instance.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,qBAAqB,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -4,10 +4,11 @@ import { createPeerSdk, } from './_internal/peer/index.js';
|
|
|
4
4
|
import { normalizeAuthToken } from './_internal/transport-http/index.js';
|
|
5
5
|
import { createEventSourceConnector, createRemoteRuntimeEvents, createWebSocketConnector, } from './_internal/transport-realtime/index.js';
|
|
6
6
|
import { createGoodVibesAuthClient, createMemoryTokenStore, } from './auth.js';
|
|
7
|
+
import { AutoRefreshCoordinator, createAutoRefreshMiddleware, } from './_internal/platform/auth/index.js';
|
|
7
8
|
function requireBaseUrl(baseUrl) {
|
|
8
9
|
const normalized = baseUrl.trim();
|
|
9
10
|
if (!normalized) {
|
|
10
|
-
throw new ConfigurationError('GoodVibes baseUrl is required');
|
|
11
|
+
throw new ConfigurationError('GoodVibes baseUrl is required. Pass a non-empty baseUrl in your createGoodVibesSdk options (e.g. "https://my-daemon.example.com").');
|
|
11
12
|
}
|
|
12
13
|
return normalized;
|
|
13
14
|
}
|
|
@@ -37,6 +38,7 @@ function createClientOptions(options) {
|
|
|
37
38
|
...(options.headers ? { headers: options.headers } : {}),
|
|
38
39
|
...(options.getHeaders ? { getHeaders: options.getHeaders } : {}),
|
|
39
40
|
...(options.retry ? { retry: options.retry } : {}),
|
|
41
|
+
...(options.middleware ? { middleware: options.middleware } : {}),
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
@@ -63,36 +65,95 @@ function createClientOptions(options) {
|
|
|
63
65
|
export function createGoodVibesSdk(options) {
|
|
64
66
|
const baseUrl = requireBaseUrl(options.baseUrl);
|
|
65
67
|
const tokenStore = options.tokenStore ?? (options.getAuthToken ? null : createMemoryTokenStore(options.authToken ?? null));
|
|
66
|
-
const authToken = options.authToken ?? null;
|
|
67
68
|
const getAuthToken = tokenStore
|
|
68
69
|
? () => tokenStore.getToken()
|
|
69
70
|
: options.getAuthToken;
|
|
70
71
|
// Single normalized resolver used by realtime connectors.
|
|
71
72
|
const tokenResolver = normalizeAuthToken(getAuthToken ?? options.authToken ?? undefined);
|
|
72
73
|
const fetchImpl = () => requireFetchImplementation(options.fetch);
|
|
74
|
+
const { observer } = options;
|
|
75
|
+
// Build the auto-refresh coordinator when a writable token store is present
|
|
76
|
+
// and autoRefresh is not explicitly disabled.
|
|
77
|
+
const autoRefreshEnabled = (options.autoRefresh?.autoRefresh ?? true) && tokenStore !== null;
|
|
78
|
+
const coordinator = autoRefreshEnabled && tokenStore
|
|
79
|
+
? new AutoRefreshCoordinator({
|
|
80
|
+
tokenStore,
|
|
81
|
+
autoRefresh: true,
|
|
82
|
+
refreshLeewayMs: options.autoRefresh?.refreshLeewayMs ?? 60_000,
|
|
83
|
+
refresh: options.autoRefresh?.refresh,
|
|
84
|
+
observer,
|
|
85
|
+
})
|
|
86
|
+
: null;
|
|
87
|
+
// Build the merged middleware list: auto-refresh first (if enabled), then
|
|
88
|
+
// consumer-provided middleware. This ensures the auto-refresh pre-flight runs
|
|
89
|
+
// before any consumer middleware sees ctx.headers.Authorization, and that the
|
|
90
|
+
// reactive 401 retry is transparent to consumer middleware.
|
|
91
|
+
//
|
|
92
|
+
// The transport reference for the retry callback is resolved lazily: we pass
|
|
93
|
+
// a proxy object whose `requestJson` property is populated immediately after
|
|
94
|
+
// createOperatorSdk / createPeerSdk returns. Because the middleware only calls
|
|
95
|
+
// `transport.requestJson` on a reactive 401 (not at construction time), the
|
|
96
|
+
// holder is always populated before it is accessed.
|
|
97
|
+
// Lazy transport proxy: populated after createOperatorSdk / createPeerSdk.
|
|
98
|
+
// The middleware only invokes requestJson on a reactive 401 — never at
|
|
99
|
+
// construction time — so the proxy is always populated before first use.
|
|
100
|
+
let operatorRequestJson = null;
|
|
101
|
+
let peerRequestJson = null;
|
|
102
|
+
const buildMiddleware = (getRequestJson) => {
|
|
103
|
+
const mws = [];
|
|
104
|
+
if (coordinator) {
|
|
105
|
+
// Wrap the coordinator + lazy transport reference into a minimal proxy
|
|
106
|
+
// that satisfies createAutoRefreshMiddleware's Pick<HttpJsonTransport, 'requestJson'>.
|
|
107
|
+
const transportProxy = {
|
|
108
|
+
requestJson(url, opts) {
|
|
109
|
+
const rj = getRequestJson();
|
|
110
|
+
if (!rj)
|
|
111
|
+
throw new Error('Auto-refresh: transport not yet initialised');
|
|
112
|
+
return rj(url, opts);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
mws.push(createAutoRefreshMiddleware(coordinator, transportProxy, tokenStore));
|
|
116
|
+
}
|
|
117
|
+
if (options.middleware) {
|
|
118
|
+
mws.push(...options.middleware);
|
|
119
|
+
}
|
|
120
|
+
return mws;
|
|
121
|
+
};
|
|
73
122
|
const operator = createOperatorSdk(createClientOptions({
|
|
74
123
|
...options,
|
|
75
124
|
tokenStore: tokenStore ?? undefined,
|
|
125
|
+
middleware: buildMiddleware(() => operatorRequestJson),
|
|
76
126
|
}));
|
|
127
|
+
// Populate the lazy reference now that the transport is fully constructed.
|
|
128
|
+
operatorRequestJson = (url, opts) => operator.transport.requestJson(url, opts);
|
|
77
129
|
const peer = createPeerSdk(createClientOptions({
|
|
78
130
|
...options,
|
|
79
131
|
tokenStore: tokenStore ?? undefined,
|
|
132
|
+
middleware: buildMiddleware(() => peerRequestJson),
|
|
80
133
|
}));
|
|
134
|
+
// Populate the lazy reference now that the transport is fully constructed.
|
|
135
|
+
peerRequestJson = (url, opts) => peer.transport.requestJson(url, opts);
|
|
81
136
|
return {
|
|
82
137
|
operator,
|
|
83
138
|
peer,
|
|
84
|
-
auth: createGoodVibesAuthClient(operator, tokenStore, getAuthToken),
|
|
139
|
+
auth: createGoodVibesAuthClient(operator, tokenStore, getAuthToken, observer, options.autoRefresh, coordinator),
|
|
140
|
+
use(middleware) {
|
|
141
|
+
operator.transport.use(middleware);
|
|
142
|
+
peer.transport.use(middleware);
|
|
143
|
+
},
|
|
85
144
|
realtime: {
|
|
86
145
|
viaSse() {
|
|
87
146
|
return createRemoteRuntimeEvents(createEventSourceConnector(baseUrl, tokenResolver, fetchImpl(), {
|
|
88
147
|
reconnect: options.realtime?.sseReconnect,
|
|
89
148
|
onError: options.realtime?.onError,
|
|
149
|
+
observer,
|
|
90
150
|
}));
|
|
91
151
|
},
|
|
92
152
|
viaWebSocket(webSocketImpl) {
|
|
93
153
|
return createRemoteRuntimeEvents(createWebSocketConnector(baseUrl, tokenResolver, requireWebSocketImplementation(webSocketImpl ?? options.WebSocketImpl), {
|
|
94
154
|
reconnect: options.realtime?.webSocketReconnect,
|
|
95
155
|
onError: options.realtime?.onError,
|
|
156
|
+
observer,
|
|
96
157
|
}));
|
|
97
158
|
},
|
|
98
159
|
},
|
package/dist/expo.d.ts
CHANGED
|
@@ -17,4 +17,5 @@ export interface ExpoGoodVibesSdkOptions extends ReactNativeGoodVibesSdkOptions
|
|
|
17
17
|
*/
|
|
18
18
|
export { forSession } from './transport-realtime.js';
|
|
19
19
|
export declare function createExpoGoodVibesSdk(options: ExpoGoodVibesSdkOptions): ReactNativeGoodVibesSdk;
|
|
20
|
+
export { createExpoSecureTokenStore, type ExpoSecureTokenStore, type ExpoSecureTokenStoreOptions, type ExpoSecureStoreAccessible, } from './_internal/platform/auth/expo-secure-token-store.js';
|
|
20
21
|
//# sourceMappingURL=expo.d.ts.map
|
package/dist/expo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expo.d.ts","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACpC,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;CAAG;AAElF;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAEhG"}
|
|
1
|
+
{"version":3,"file":"expo.d.ts","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACpC,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;CAAG;AAElF;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAEhG;AAED,OAAO,EACL,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,sDAAsD,CAAC"}
|
package/dist/expo.js
CHANGED