Repository: trpc/trpc
File: packages/client/src/links/httpSubscriptionLink.ts (TypeScript)

Code before:
              },
            });
          };
          eventSource.addEventListener('open', onStarted, { once: true });

          const iterable = sseStreamConsumer<
            Partial<{
              id?: string;
              data: unknown;
            }>
          >({
            from: eventSource,
            deserialize: transformer.output.deserialize,
            tryHandleError: async (ev) => {
              if (
                'status' in ev &&
                typeof ev.status === 'number' &&
                typeof opts.shouldReinitialize === 'function' &&
                eventSource &&
                (await opts.shouldReinitialize(ev.status, ev))
              ) {
                eventSource.restart(
                  url,
                  await resultOf(opts.eventSourceOptions),
                );

                return true;
              }

              return false;
            },
          });

          for await (const chunk of iterable) {
            if (!chunk.ok) {
              // TODO: handle in https://github.com/trpc/trpc/issues/5871
              continue;
            }
            const chunkData = chunk.data;

            // if the `tracked()`-helper is used, we always have an `id` field
            const data = 'id' in chunkData ? chunkData : chunkData.data;
            observer.next({
              result: {
                data,
              },
            });
          }

          observer.next({
            result: {

Review comment (suggestion):
we don't offer the chance to reboot when the network error itself occurs as that event doesn't come with a status code, but when it recovers and there's an issue like 401 we do call this. So it can take an extra round trip to recover but feels easier to work with

Code after:

          eventSource = new EventSourceWrapper(url, eventSourceOptions);

          const onStarted = () => {
            observer.next({
              result: {
                type: 'started',
              },
              context: {
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                eventSource: eventSource!.getEventSource(),
              },
            });
          };
          eventSource.addEventListener('open', onStarted, { once: true });

          const iterable = sseStreamConsumer<
            Partial<{
              id?: string;
              data: unknown;
            }>
          >({
            from: eventSource,
            deserialize: transformer.output.deserialize,
            tryHandleError: async (ev) => {
              if (
                typeof opts.shouldRecreateOnError !== 'function' ||
                !eventSource
              ) {
                return false;
              }

              const recreateOnErrorOpts = createRecreateOnErrorOpts(ev);

              const shouldRestart = await opts.shouldRecreateOnError(
                recreateOnErrorOpts,
              );

              if (!shouldRestart) {
                return false;
              }

              eventSource.restart(
                getUrl({
                  transformer,
                  url: await urlWithConnectionParams(opts),
                  input,
                  path,
                  type,
                  signal: null,
                }),