@streamlayer/sdk-web-api 0.18.0 → 0.19.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,13 +1,13 @@
1
1
  import { ReadableAtom } from 'nanostores';
2
- import type { BypassAuthRequest, BypassAuthResponse } from '@streamlayer/sl-eslib/users/users_pb';
2
+ import type { BypassAuthRequest } from '@streamlayer/sl-eslib/users/users_pb';
3
3
  import { PlainMessage } from '@bufbuild/protobuf';
4
4
  import { Transport } from '../transport';
5
5
  export declare const $user: ($userToken: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/users/users_pb").MeResponse, any>;
6
- export declare const $bypassLogin: (transport: Transport) => import("@nanostores/query").MutatorStore<PlainMessage<BypassAuthRequest>, PlainMessage<BypassAuthResponse>, any>;
6
+ export declare const bypassLogin: (transport: Transport) => ({ userKey, schema, init }: PlainMessage<BypassAuthRequest>) => Promise<import("@streamlayer/sl-eslib/users/users_pb").BypassAuthResponse>;
7
7
  export declare const bypassAuth: (transport: Transport, params: {
8
8
  userKey?: string;
9
9
  schema?: string;
10
10
  init?: boolean;
11
- }) => Promise<BypassAuthResponse>;
11
+ }) => Promise<import("@streamlayer/sl-eslib/users/users_pb").BypassAuthResponse>;
12
12
  export declare const $userSettings: ($userToken: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/sdkSettings/client/client_pb").ClientSettings | undefined, any>;
13
13
  export declare const register: (transport: Transport, phone: string) => Promise<import("@streamlayer/sl-eslib/users/users_pb").RegisterResponse>;
@@ -12,14 +12,9 @@ export const $user = ($userToken, transport) => {
12
12
  fetcher: () => client.me({}),
13
13
  });
14
14
  };
15
- export const $bypassLogin = (transport) => {
16
- const { client, queryKeyStr } = transport.createPromiseClient(Users, { method: 'bypassAuth' });
17
- return transport.nanoquery.createMutatorStore(async ({ data: { userKey, schema, init }, getCacheUpdater }) => {
18
- const [updateCache] = getCacheUpdater(queryKeyStr);
19
- const user = await client.bypassAuth({ userKey, schema, init });
20
- updateCache(user);
21
- return user;
22
- });
15
+ export const bypassLogin = (transport) => {
16
+ const { client } = transport.createPromiseClient(Users, { method: 'bypassAuth' });
17
+ return ({ userKey, schema, init }) => client.bypassAuth({ userKey, schema, init });
23
18
  };
24
19
  export const bypassAuth = (transport, params) => {
25
20
  const { client } = transport.createPromiseClient(Users, { method: 'bypassAuth' });
@@ -1,11 +1,14 @@
1
- import { CallbackClient } from '@connectrpc/connect';
1
+ import { PromiseClient } from '@connectrpc/connect';
2
2
  import { Atom } from 'nanostores';
3
3
  import type { ServiceType, Message, PlainMessage, MethodInfoServerStreaming } from '@bufbuild/protobuf';
4
4
  import { Transport } from './transport';
5
+ type StreamPromiseClient<T extends ServiceType> = {
6
+ [P in keyof PromiseClient<T> as T['methods'][P] extends MethodInfoServerStreaming<any, any> ? P : never]: T['methods'][P] extends MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never;
7
+ };
5
8
  type StreamMethods<T extends ServiceType> = {
6
- [P in keyof CallbackClient<T> as T['methods'][P] extends MethodInfoServerStreaming<any, any> ? P : never]: P;
9
+ [P in keyof StreamPromiseClient<T>]: P;
7
10
  };
8
- export type StreamMethod<T extends ServiceType> = StreamMethods<T>[keyof StreamMethods<T>] extends keyof CallbackClient<T> ? StreamMethods<T>[keyof StreamMethods<T>] : never;
11
+ export type StreamMethod<T extends ServiceType> = StreamMethods<T>[keyof StreamMethods<T>] extends keyof StreamPromiseClient<T> ? StreamMethods<T>[keyof StreamMethods<T>] : never;
9
12
  declare enum ServerStreamSubscriptionStatus {
10
13
  Init = "init",
11
14
  Ready = "ready",
@@ -13,21 +16,28 @@ declare enum ServerStreamSubscriptionStatus {
13
16
  Connected = "connected",
14
17
  Disconnected = "disconnected",
15
18
  Failed = "failed",
19
+ Reconnect = "reconnect",
16
20
  Reconnecting = "reconnecting"
17
21
  }
18
22
  export type ServerStreamSubscriptionOptions = {
19
23
  name: string;
20
24
  withStore?: boolean;
25
+ reconnectDelay?: number;
26
+ reconnectMaxDelay?: number;
27
+ reconnectMaxAttempts?: number;
21
28
  };
22
- export declare class ServerStreamSubscription<T extends ServiceType, Request extends Message<Request>, Response extends Message<Response>, M extends StreamMethod<T> = StreamMethod<T>, Method extends CallbackClient<T>[M] = CallbackClient<T>[M]> {
29
+ export declare class ServerStreamSubscription<T extends ServiceType, Request extends Message<Request>, Response extends Message<Response>, M extends keyof StreamMethods<T> = keyof StreamMethods<T>, Method extends StreamPromiseClient<T>[M] = StreamPromiseClient<T>[M]> {
23
30
  params: Atom<PlainMessage<Request>> | PlainMessage<Request>;
24
- private stream?;
31
+ private streamCancel?;
25
32
  private method;
26
- private name;
33
+ private options;
27
34
  private headers;
28
35
  private listeners;
29
36
  private state;
30
37
  private store?;
38
+ private paramsListener?;
39
+ private reconnectTimeout?;
40
+ private attempt;
31
41
  constructor(headers: Transport['$headers'], method: Method, params: Atom<PlainMessage<Request>> | PlainMessage<Request>, options: ServerStreamSubscriptionOptions);
32
42
  updateState: (status: ServerStreamSubscriptionStatus) => void;
33
43
  addStateLog: (msg: string) => void;
@@ -35,9 +45,17 @@ export declare class ServerStreamSubscription<T extends ServiceType, Request ext
35
45
  removeListener: (name: string) => void;
36
46
  connect: () => void;
37
47
  disconnect: () => void;
48
+ /**
49
+ * Reconnect after delay, if not already reconnecting, otherwise do nothing
50
+ */
38
51
  reconnect: () => void;
39
52
  getStore: () => import("nanostores").WritableAtom<Response | null | undefined> | undefined;
40
53
  private onData;
54
+ /**
55
+ * Disconnect if error is not instance of ConnectError or stream is Canceled,
56
+ * Reconnect in other cases
57
+ * Do nothing if error is undefined
58
+ */
41
59
  private onStreamError;
42
60
  }
43
61
  export {};
@@ -1,5 +1,5 @@
1
1
  import { MapStore, SingleStore, createMapStore, createSingleStore } from '@streamlayer/sdk-web-interfaces';
2
- import { Code } from '@connectrpc/connect';
2
+ import { ConnectError, Code } from '@connectrpc/connect';
3
3
  var ServerStreamSubscriptionStatus;
4
4
  (function (ServerStreamSubscriptionStatus) {
5
5
  ServerStreamSubscriptionStatus["Init"] = "init";
@@ -8,17 +8,21 @@ var ServerStreamSubscriptionStatus;
8
8
  ServerStreamSubscriptionStatus["Connected"] = "connected";
9
9
  ServerStreamSubscriptionStatus["Disconnected"] = "disconnected";
10
10
  ServerStreamSubscriptionStatus["Failed"] = "failed";
11
+ ServerStreamSubscriptionStatus["Reconnect"] = "reconnect";
11
12
  ServerStreamSubscriptionStatus["Reconnecting"] = "reconnecting";
12
13
  })(ServerStreamSubscriptionStatus || (ServerStreamSubscriptionStatus = {}));
13
14
  export class ServerStreamSubscription {
14
15
  params;
15
- stream;
16
+ streamCancel;
16
17
  method;
17
- name;
18
+ options;
18
19
  headers;
19
20
  listeners;
20
21
  state;
21
22
  store;
23
+ paramsListener;
24
+ reconnectTimeout;
25
+ attempt = 0;
22
26
  constructor(headers, method, params, options) {
23
27
  const initState = {
24
28
  status: ServerStreamSubscriptionStatus.Init,
@@ -26,7 +30,13 @@ export class ServerStreamSubscription {
26
30
  log: [],
27
31
  };
28
32
  this.state = new MapStore(createMapStore(initState), `subscription:${options.name}:state`);
29
- this.name = options.name;
33
+ this.options = {
34
+ ...options,
35
+ reconnectDelay: options.reconnectDelay ?? 1000,
36
+ reconnectMaxDelay: options.reconnectMaxDelay ?? 30000,
37
+ reconnectMaxAttempts: options.reconnectMaxAttempts ?? 10,
38
+ withStore: options.withStore ?? false,
39
+ };
30
40
  this.headers = headers;
31
41
  this.listeners = new Map();
32
42
  this.params = params;
@@ -35,8 +45,11 @@ export class ServerStreamSubscription {
35
45
  this.store = new SingleStore(createSingleStore(null), `subscription:${options.name}:store`);
36
46
  }
37
47
  if ('subscribe' in params && typeof params.subscribe === 'function') {
38
- params.subscribe(() => {
39
- this.reconnect();
48
+ this.paramsListener = params.subscribe((newParams) => {
49
+ if (this.state.getValue('status') === ServerStreamSubscriptionStatus.Connected) {
50
+ this.addStateLog(`params updated, reconnect => ${JSON.stringify(newParams)}`);
51
+ this.reconnect();
52
+ }
40
53
  });
41
54
  }
42
55
  this.updateState(ServerStreamSubscriptionStatus.Ready);
@@ -52,7 +65,7 @@ export class ServerStreamSubscription {
52
65
  };
53
66
  addListener = (name, listener) => {
54
67
  if (this.listeners.has(name)) {
55
- this.addStateLog(`listener '${name}' not added`);
68
+ this.addStateLog(`listener '${name}' not added, already exists`);
56
69
  return false;
57
70
  }
58
71
  this.listeners.set(name, listener);
@@ -65,50 +78,103 @@ export class ServerStreamSubscription {
65
78
  };
66
79
  connect = () => {
67
80
  this.updateState(ServerStreamSubscriptionStatus.Connecting);
68
- if (this.stream) {
81
+ if (this.streamCancel) {
69
82
  this.addStateLog(`disconnect prev connection`);
70
- this.stream();
83
+ this.streamCancel.abort();
84
+ this.streamCancel = undefined;
71
85
  }
72
- const params = 'get' in this.params && typeof this.params.get === 'function' ? this.params.get() : this.params;
73
- this.stream = this.method(params,
74
- // ToDo: fix types
75
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
76
- // @ts-ignore
77
- this.onData, this.onStreamError, { headers: this.headers.getValues() });
86
+ const params = ('get' in this.params && typeof this.params.get === 'function' ? this.params.get() : this.params);
87
+ const fn = async () => {
88
+ this.streamCancel = new AbortController();
89
+ try {
90
+ const options = {
91
+ headers: this.headers.getValues(),
92
+ signal: this.streamCancel.signal,
93
+ };
94
+ const stream = this.method(params, options);
95
+ for await (const res of stream) {
96
+ this.attempt = 0;
97
+ this.onData(res);
98
+ }
99
+ }
100
+ catch (err) {
101
+ if (err instanceof ConnectError && err.code != Code.Canceled) {
102
+ void this.onStreamError(err);
103
+ }
104
+ }
105
+ };
106
+ void fn();
78
107
  this.updateState(ServerStreamSubscriptionStatus.Connected);
79
108
  };
80
109
  disconnect = () => {
81
- if (this.stream) {
82
- this.stream();
110
+ if (this.streamCancel) {
111
+ this.streamCancel.abort();
83
112
  }
84
113
  this.listeners.clear();
114
+ this.paramsListener?.();
115
+ clearTimeout(this.reconnectTimeout);
116
+ this.reconnectTimeout = undefined;
85
117
  this.updateState(ServerStreamSubscriptionStatus.Disconnected);
86
118
  };
119
+ /**
120
+ * Reconnect after delay, if not already reconnecting, otherwise do nothing
121
+ */
87
122
  reconnect = () => {
88
- this.updateState(ServerStreamSubscriptionStatus.Reconnecting);
89
- this.connect();
123
+ if (!this.reconnectTimeout) {
124
+ if (this.attempt < this.options.reconnectMaxAttempts) {
125
+ this.updateState(ServerStreamSubscriptionStatus.Reconnect);
126
+ // https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter/
127
+ const backoff = Math.min(this.options.reconnectMaxDelay, Math.pow(2, this.attempt) * this.options.reconnectDelay);
128
+ const delayMs = Math.round((backoff * (1 + Math.random())) / 2);
129
+ this.reconnectTimeout = setTimeout(() => {
130
+ this.attempt++;
131
+ this.updateState(ServerStreamSubscriptionStatus.Reconnecting);
132
+ this.addStateLog(`reconnect attempt ${this.attempt} after ${delayMs}ms`);
133
+ this.connect();
134
+ this.reconnectTimeout = undefined;
135
+ }, delayMs);
136
+ }
137
+ else {
138
+ this.addStateLog(`max reconnect attempts reached`);
139
+ this.disconnect();
140
+ }
141
+ }
142
+ else {
143
+ this.addStateLog(`already reconnecting`);
144
+ }
90
145
  };
91
146
  getStore = () => this.store?.getStore();
92
147
  onData = (response) => {
93
- this.addStateLog(`received data => ${JSON.stringify(response)}`);
94
- if (this.store) {
95
- this.store.setValue(response);
148
+ try {
149
+ this.addStateLog(`received data => ${JSON.stringify(response)}`);
150
+ if (this.store) {
151
+ this.store.setValue(response);
152
+ }
153
+ for (const [, listener] of this.listeners) {
154
+ listener(response);
155
+ }
156
+ this.addStateLog(`data routed to ${this.listeners.size} listeners`);
96
157
  }
97
- for (const [, listener] of this.listeners) {
98
- listener(response);
158
+ catch (err) {
159
+ this.addStateLog(`error process data => ${err}`);
99
160
  }
100
- this.addStateLog(`data routed to ${this.listeners.size} listeners`);
101
161
  };
162
+ /**
163
+ * Disconnect if error is not instance of ConnectError or stream is Canceled,
164
+ * Reconnect in other cases
165
+ * Do nothing if error is undefined
166
+ */
102
167
  onStreamError = (error) => {
168
+ this.addStateLog(`error => ${error ? JSON.stringify(error) : 'undefined'}}`);
103
169
  if (error === undefined) {
104
170
  return;
105
171
  }
106
- if (error.code !== Code.Canceled && error.rawMessage !== '[canceled] BodyStreamBuffer was aborted') {
172
+ if (error instanceof ConnectError && error.code !== Code.Canceled) {
107
173
  this.updateState(ServerStreamSubscriptionStatus.Failed);
108
174
  this.state.setValue('error', error);
175
+ this.reconnect();
176
+ return;
109
177
  }
110
- else {
111
- this.disconnect();
112
- }
178
+ this.disconnect();
113
179
  };
114
180
  }
@@ -1,4 +1,4 @@
1
- import { createRouterTransport, ConnectRouter, Interceptor, PromiseClient, CallbackClient, UnaryRequest, StreamRequest } from '@connectrpc/connect';
1
+ import { createRouterTransport, ConnectRouter, Interceptor, PromiseClient, UnaryRequest, StreamRequest } from '@connectrpc/connect';
2
2
  import type { ServiceType, Message, PlainMessage } from '@bufbuild/protobuf';
3
3
  import { createGrpcWebTransport } from '@connectrpc/connect-web';
4
4
  import type { KeyInput } from '@nanostores/query';
@@ -9,6 +9,7 @@ type KnownHeaders = {
9
9
  authorization?: string;
10
10
  sdk?: string;
11
11
  'sl-device-id': string;
12
+ 'sl-user-id'?: string;
12
13
  } & Record<string, string>;
13
14
  export type GrpcTransport = Transport['transport'];
14
15
  type ReservedHeaders = 'sdk' | 'authorization';
@@ -42,13 +43,12 @@ export declare class Transport {
42
43
  private callbackClients;
43
44
  private subscriptions;
44
45
  constructor(host: string);
45
- addSubscription: <T extends ServiceType, Req extends Message<Req>, Res extends Message<Res>>(method: CallbackClient<T>[import("./subscription").StreamMethod<T>], params: PlainMessage<Req> | Atom<PlainMessage<Req>>, options: ServerStreamSubscriptionOptions) => ServerStreamSubscription<ServiceType, Message<import("@bufbuild/protobuf").AnyMessage>, Message<import("@bufbuild/protobuf").AnyMessage>, never, never> | ServerStreamSubscription<T, Req, Res, import("./subscription").StreamMethod<T>, CallbackClient<T>[import("./subscription").StreamMethod<T>]>;
46
+ addSubscription: <T extends ServiceType, Req extends Message<Req>, Res extends Message<Res>>(method: { [P in keyof PromiseClient<T> as T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? P : never]: T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never; }[keyof { [P in keyof PromiseClient<T> as T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? P : never]: T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never; }], params: PlainMessage<Req> | Atom<PlainMessage<Req>>, options: ServerStreamSubscriptionOptions) => ServerStreamSubscription<ServiceType, Message<import("@bufbuild/protobuf").AnyMessage>, Message<import("@bufbuild/protobuf").AnyMessage>, never, never> | ServerStreamSubscription<T, Req, Res, keyof { [P in keyof PromiseClient<T> as T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? P : never]: T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never; }, { [P in keyof PromiseClient<T> as T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? P : never]: T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never; }[keyof { [P in keyof PromiseClient<T> as T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? P : never]: T["methods"][P] extends import("@bufbuild/protobuf").MethodInfoServerStreaming<any, any> ? PromiseClient<T>[P] : never; }]>;
46
47
  removeSubscription: (subscription: ServerStreamSubscription<ServiceType, Message, Message>) => void;
47
48
  disconnect: () => void;
48
49
  registerInterceptor: (interceptor: Interceptor) => void;
49
50
  removeInterceptor: (interceptor: Interceptor) => void;
50
51
  getClient: <T extends ServiceType>(service: T) => PromiseClient<T>;
51
- getCallbackClient: <T extends ServiceType>(service: T) => CallbackClient<T>;
52
52
  createPromiseClient: <T extends ServiceType>(service: T, { params, method }: {
53
53
  params?: KeyInput | undefined;
54
54
  method: keyof T["methods"];
@@ -57,11 +57,11 @@ export declare class Transport {
57
57
  queryKey: ((string | number | true) | import("nanostores").ReadableAtom<(string | number | true) | (false | void | null | undefined)> | import("@nanostores/query").FetcherStore<any, any>)[];
58
58
  queryKeyStr: string;
59
59
  };
60
- createCallbackClient: <T extends ServiceType>(service: T) => {
61
- client: CallbackClient<T>;
60
+ createStreamClient: <T extends ServiceType>(service: T) => {
61
+ client: PromiseClient<T>;
62
62
  };
63
63
  setSdkKey: (sdkKey: string) => void;
64
- setAuth: (token?: string) => void;
64
+ setAuth: (token: string, userId: string) => void;
65
65
  setHeader: <T extends string = string>(name: ExcludeReservedHeaders<T>, value: string) => void;
66
66
  getHeader: (name: keyof KnownHeaders) => string;
67
67
  getHeaders: () => KnownHeaders;
@@ -1,5 +1,5 @@
1
1
  import { MapStore, createMapStore } from '@streamlayer/sdk-web-interfaces';
2
- import { createRouterTransport, createPromiseClient, createCallbackClient, } from '@connectrpc/connect';
2
+ import { createRouterTransport, createPromiseClient, } from '@connectrpc/connect';
3
3
  import { createGrpcWebTransport } from '@connectrpc/connect-web';
4
4
  import { nanoquery } from '@nanostores/query';
5
5
  import { __GRPC_DEVTOOLS_EXTENSION__ } from '../utils/devtools';
@@ -61,9 +61,9 @@ export class Transport {
61
61
  };
62
62
  // cleanup subscriptions
63
63
  disconnect = () => {
64
- for (const [name, subscription] of this.subscriptions) {
64
+ for (const [params, subscription] of this.subscriptions) {
65
65
  subscription.disconnect();
66
- this.subscriptions.delete(name);
66
+ this.subscriptions.delete(params);
67
67
  }
68
68
  };
69
69
  registerInterceptor = (interceptor) => {
@@ -81,15 +81,6 @@ export class Transport {
81
81
  this.clients.set(serviceName, client);
82
82
  return client;
83
83
  };
84
- getCallbackClient = (service) => {
85
- const serviceName = service.typeName;
86
- if (this.callbackClients.has(serviceName)) {
87
- return this.callbackClients.get(serviceName);
88
- }
89
- const client = createCallbackClient(service, this.transport);
90
- this.callbackClients.set(serviceName, client);
91
- return client;
92
- };
93
84
  // create unary client, used for query request
94
85
  createPromiseClient = (service, { params = [], method }) => {
95
86
  const client = this.getClient(service);
@@ -102,16 +93,17 @@ export class Transport {
102
93
  const queryKeyWithoutParams = [service.typeName, methodName.charAt(0).toLowerCase() + methodName.slice(1)];
103
94
  return { client, queryKey, queryKeyStr: queryKeyWithoutParams.join('') };
104
95
  };
105
- // create callback client, used for server stream subscriptions
106
- createCallbackClient = (service) => {
107
- const client = this.getCallbackClient(service);
96
+ // create promise client, used for server stream subscriptions
97
+ createStreamClient = (service) => {
98
+ const client = this.getClient(service);
108
99
  return { client };
109
100
  };
110
101
  setSdkKey = (sdkKey) => {
111
102
  this.$headers.setValue('sdk', sdkKey);
112
103
  };
113
- setAuth = (token) => {
104
+ setAuth = (token, userId) => {
114
105
  this.$headers.setValue('authorization', token);
106
+ this.$headers.setValue('sl-user-id', userId);
115
107
  };
116
108
  setHeader = (name, value) => this.$headers.setValue(name, value);
117
109
  getHeader = (name) => this.$headers.getValue(name);
@@ -145,7 +137,7 @@ export class Transport {
145
137
  export class MockTransport extends Transport {
146
138
  calls;
147
139
  constructor(transport) {
148
- super(process.env.NX_GRPC_HOST || 'https://grpc-web.next.streamlayer.io:443');
140
+ super(process.env.NX_GRPC_HOST || 'https://grpc-sdk.next.streamlayer.io:443');
149
141
  this.calls = [];
150
142
  this.interceptors.push((next) => (req) => {
151
143
  this.calls.push(req);
package/lib/index.d.ts CHANGED
@@ -17,4 +17,5 @@ declare module '@streamlayer/sdk-web-interfaces' {
17
17
  export declare const transport: (instance: StreamLayerContext, opts: {
18
18
  sdkKey: string;
19
19
  host: string;
20
+ version?: string;
20
21
  }, done: () => void) => void;
package/lib/index.js CHANGED
@@ -5,5 +5,6 @@ export const transport = (instance, opts, done) => {
5
5
  instance.transport = new Transport(opts.host);
6
6
  instance.sdk.host = instance.transport.host;
7
7
  instance.transport.setSdkKey(opts.sdkKey);
8
+ instance.transport.setHeader('sl-sdk-version', opts.version || '-');
8
9
  done();
9
10
  };
@@ -16,18 +16,20 @@ async function* logEach(store, stream) {
16
16
  export const __GRPC_DEVTOOLS_EXTENSION__ = () => (next) => async (request) => {
17
17
  const store = {
18
18
  name: request.url,
19
- request: {},
19
+ stream: request.stream,
20
+ sent_at: Date.now(),
21
+ request: {
22
+ // clone headers to avoid mutating
23
+ header: Object.fromEntries(request.header.entries()),
24
+ },
20
25
  response: {},
21
26
  };
22
- store.request.header = Object.fromEntries(request.header.entries());
23
- store.sent_at = Date.now();
24
27
  try {
25
28
  const response = await next(request);
26
29
  store.received_at = Date.now();
27
- store.stream = response.stream;
28
30
  store.response.header = Object.fromEntries(response.header.entries());
29
31
  store.response.trailer = Object.fromEntries(response.trailer.entries());
30
- if (!response.stream) {
32
+ if (!request.stream) {
31
33
  store.request.message = request.message;
32
34
  store.response.message = response.message;
33
35
  store.latency = store.received_at - store.sent_at;
@@ -38,6 +40,15 @@ export const __GRPC_DEVTOOLS_EXTENSION__ = () => (next) => async (request) => {
38
40
  window.postMessage(msg);
39
41
  }
40
42
  else {
43
+ store.request.message = request.message;
44
+ const msg = {
45
+ type: '__GRPC_DEVTOOLS_EXTENSION__',
46
+ data: {
47
+ ...store,
48
+ stream: false,
49
+ },
50
+ };
51
+ window.postMessage(msg);
41
52
  return {
42
53
  ...response,
43
54
  message: logEach(store, response.message),
@@ -3,7 +3,7 @@ export class GrpcStub {
3
3
  transport;
4
4
  stubs;
5
5
  constructor() {
6
- this.transport = new Transport(process.env.NX_GRPC_HOST || 'https://grpc-web.next.streamlayer.io:443');
6
+ this.transport = new Transport(process.env.NX_GRPC_HOST || 'https://grpc-sdk.next.streamlayer.io:443');
7
7
  this.stubs = new Map();
8
8
  const stubbedUnary = (service, method, signal, timeoutMs, header, input) => {
9
9
  const key = `${service.typeName}${method.name}`.toLowerCase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamlayer/sdk-web-api",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "type": "module",
5
5
  "main": "./lib/index.js",
6
6
  "typings": "./lib/index.d.ts",
@@ -21,16 +21,16 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@streamlayer/sdk-web-interfaces": "^0.1.0"
24
+ "@streamlayer/sdk-web-interfaces": "^0.19.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@swc/helpers": "*",
28
- "@bufbuild/protobuf": "*",
29
- "@connectrpc/connect": "*",
30
- "@connectrpc/connect-web": "*",
31
- "@nanostores/query": "*",
32
- "@streamlayer/sl-eslib": "*",
33
- "nanostores": "*",
34
- "tslib": "*"
27
+ "@bufbuild/protobuf": "^1.6.0",
28
+ "@connectrpc/connect": "^1.3.0",
29
+ "@connectrpc/connect-web": "^1.3.0",
30
+ "@nanostores/query": "^0.2.8",
31
+ "@streamlayer/sl-eslib": "^5.63.3",
32
+ "@swc/helpers": "^0.5.3",
33
+ "nanostores": "^0.9.5",
34
+ "tslib": "^2.6.2"
35
35
  }
36
36
  }