@trpc/client 10.0.0-alpha.10 → 10.0.0-alpha.13

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.
Files changed (150) hide show
  1. package/dist/{httpUtils-1f9e4e3c.js → httpUtils-27640b42.js} +0 -0
  2. package/dist/{httpUtils-c09d7b79.mjs → httpUtils-b92552af.mjs} +0 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +215 -18
  6. package/dist/index.mjs +198 -13
  7. package/dist/internals/TRPCClient.d.ts +4 -2
  8. package/dist/internals/TRPCClient.d.ts.map +1 -1
  9. package/dist/links/dedupeLink.d.ts.map +1 -1
  10. package/dist/links/httpBatchLink.d.ts +1 -1
  11. package/dist/links/httpBatchLink.d.ts.map +1 -1
  12. package/dist/links/httpBatchLink.js +3 -3
  13. package/dist/links/httpBatchLink.mjs +3 -3
  14. package/dist/links/httpLink.d.ts +1 -1
  15. package/dist/links/httpLink.d.ts.map +1 -1
  16. package/dist/links/httpLink.js +3 -3
  17. package/dist/links/httpLink.mjs +3 -3
  18. package/dist/links/index.d.ts +11 -0
  19. package/dist/links/index.d.ts.map +1 -0
  20. package/dist/links/{httpUtils.d.ts → internals/httpUtils.d.ts} +1 -1
  21. package/dist/links/internals/httpUtils.d.ts.map +1 -0
  22. package/dist/links/loggerLink.d.ts.map +1 -1
  23. package/dist/links/loggerLink.js +4 -3
  24. package/dist/links/loggerLink.mjs +3 -2
  25. package/dist/links/retryLink.d.ts.map +1 -1
  26. package/dist/links/splitLink.js +3 -25
  27. package/dist/links/splitLink.mjs +2 -28
  28. package/dist/links/transformerLink.js +2 -2
  29. package/dist/links/transformerLink.mjs +2 -2
  30. package/dist/links/types.d.ts +4 -3
  31. package/dist/links/types.d.ts.map +1 -1
  32. package/dist/links/wsLink.d.ts +1 -2
  33. package/dist/links/wsLink.d.ts.map +1 -1
  34. package/dist/links/wsLink.js +11 -377
  35. package/dist/links/wsLink.mjs +9 -369
  36. package/dist/observable/index.d.ts +4 -0
  37. package/dist/observable/index.d.ts.map +1 -0
  38. package/dist/observable/index.js +40 -0
  39. package/dist/observable/index.mjs +33 -0
  40. package/dist/{rx.ts.js → observable/index.ts.js} +0 -0
  41. package/dist/observable/observable.d.ts +4 -0
  42. package/dist/observable/observable.d.ts.map +1 -0
  43. package/dist/observable/operators/index.d.ts +4 -0
  44. package/dist/observable/operators/index.d.ts.map +1 -0
  45. package/dist/observable/operators/map.d.ts +3 -0
  46. package/dist/observable/operators/map.d.ts.map +1 -0
  47. package/dist/observable/operators/share.d.ts +6 -0
  48. package/dist/observable/operators/share.d.ts.map +1 -0
  49. package/dist/observable/operators/tap.d.ts +3 -0
  50. package/dist/observable/operators/tap.d.ts.map +1 -0
  51. package/dist/observable/types.d.ts +29 -0
  52. package/dist/observable/types.d.ts.map +1 -0
  53. package/dist/observable/util/identity.d.ts +2 -0
  54. package/dist/observable/util/identity.d.ts.map +1 -0
  55. package/dist/observable/util/observableToPromise.d.ts +10 -0
  56. package/dist/observable/util/observableToPromise.d.ts.map +1 -0
  57. package/dist/observable/util/pipe.d.ts +4 -0
  58. package/dist/observable/util/pipe.d.ts.map +1 -0
  59. package/dist/observable-16fde241.mjs +102 -0
  60. package/dist/observable-9aaca086.js +104 -0
  61. package/dist/share-4afc084f.js +110 -0
  62. package/dist/share-9f12d26c.mjs +108 -0
  63. package/dist/splitLink-8635d455.js +52 -0
  64. package/dist/splitLink-a736378a.mjs +49 -0
  65. package/dist/tap-aacf31bf.js +32 -0
  66. package/dist/tap-f567ea97.mjs +30 -0
  67. package/dist/wsLink-a6a0f3a8.mjs +440 -0
  68. package/dist/wsLink-c9323097.js +455 -0
  69. package/package.json +11 -41
  70. package/src/index.ts +1 -1
  71. package/src/internals/TRPCClient.ts +8 -5
  72. package/src/links/dedupeLink.test.ts +3 -3
  73. package/src/links/dedupeLink.ts +27 -28
  74. package/src/links/httpBatchLink.ts +7 -3
  75. package/src/links/httpLink.ts +3 -3
  76. package/src/links/index.ts +10 -0
  77. package/src/links/internals/createChain.test.ts +7 -7
  78. package/src/links/internals/createChain.ts +4 -4
  79. package/src/links/{httpUtils.ts → internals/httpUtils.ts} +1 -1
  80. package/src/links/loggerLink.ts +3 -2
  81. package/src/links/retryLink.ts +3 -2
  82. package/src/links/splitLink.test.ts +3 -3
  83. package/src/links/splitLink.ts +2 -2
  84. package/src/links/transformerLink.ts +2 -2
  85. package/src/links/types.ts +4 -3
  86. package/src/links/wsLink.ts +3 -4
  87. package/src/observable/index.ts +3 -0
  88. package/src/observable/observable.test.ts +103 -0
  89. package/src/observable/observable.ts +70 -0
  90. package/src/observable/operators/index.ts +3 -0
  91. package/src/observable/operators/map.test.ts +92 -0
  92. package/src/observable/operators/map.ts +25 -0
  93. package/src/observable/operators/share.test.ts +60 -0
  94. package/src/observable/operators/share.ts +67 -0
  95. package/src/observable/operators/tap.ts +26 -0
  96. package/src/observable/types.ts +69 -0
  97. package/src/observable/util/identity.ts +3 -0
  98. package/src/{rx.ts → observable/util/observableToPromise.ts} +6 -7
  99. package/src/observable/util/pipe.ts +22 -0
  100. package/dist/TRPCClientError-17b117e1.mjs +0 -81
  101. package/dist/TRPCClientError-ec6bd2ca.js +0 -94
  102. package/dist/createChain-3b458753.js +0 -27
  103. package/dist/createChain-b7cb1f5a.mjs +0 -25
  104. package/dist/links/httpUtils.d.ts.map +0 -1
  105. package/dist/rx.d.ts +0 -11
  106. package/dist/rx.d.ts.map +0 -1
  107. package/dist/rx.js +0 -88
  108. package/dist/rx.mjs +0 -73
  109. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.d.ts +0 -1
  110. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.dev.js +0 -214
  111. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.js +0 -7
  112. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.prod.js +0 -214
  113. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.esm.js +0 -210
  114. package/links/httpBatchLink/index.d.ts +0 -1
  115. package/links/httpBatchLink/index.js +0 -1
  116. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.d.ts +0 -1
  117. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.dev.js +0 -67
  118. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.js +0 -7
  119. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.prod.js +0 -67
  120. package/links/httpLink/dist/trpc-client-links-httpLink.esm.js +0 -63
  121. package/links/httpLink/index.d.ts +0 -1
  122. package/links/httpLink/index.js +0 -1
  123. package/links/loggerLink/dist/trpc-client-links-loggerLink.cjs.d.ts +0 -1
  124. package/links/loggerLink/dist/trpc-client-links-loggerLink.cjs.dev.js +0 -89
  125. package/links/loggerLink/dist/trpc-client-links-loggerLink.cjs.js +0 -7
  126. package/links/loggerLink/dist/trpc-client-links-loggerLink.cjs.prod.js +0 -89
  127. package/links/loggerLink/dist/trpc-client-links-loggerLink.esm.js +0 -85
  128. package/links/loggerLink/index.d.ts +0 -1
  129. package/links/loggerLink/index.js +0 -1
  130. package/links/splitLink/dist/trpc-client-links-splitLink.cjs.d.ts +0 -1
  131. package/links/splitLink/dist/trpc-client-links-splitLink.cjs.dev.js +0 -19
  132. package/links/splitLink/dist/trpc-client-links-splitLink.cjs.js +0 -7
  133. package/links/splitLink/dist/trpc-client-links-splitLink.cjs.prod.js +0 -19
  134. package/links/splitLink/dist/trpc-client-links-splitLink.esm.js +0 -15
  135. package/links/splitLink/index.d.ts +0 -1
  136. package/links/splitLink/index.js +0 -1
  137. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.d.ts +0 -1
  138. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.dev.js +0 -67
  139. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.js +0 -7
  140. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.prod.js +0 -67
  141. package/links/transformerLink/dist/trpc-client-links-transformerLink.esm.js +0 -63
  142. package/links/transformerLink/index.d.ts +0 -1
  143. package/links/transformerLink/index.js +0 -1
  144. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.d.ts +0 -1
  145. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.dev.js +0 -395
  146. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.js +0 -7
  147. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.prod.js +0 -395
  148. package/links/wsLink/dist/trpc-client-links-wsLink.esm.js +0 -390
  149. package/links/wsLink/index.d.ts +0 -1
  150. package/links/wsLink/index.js +0 -1
@@ -1,8 +1,12 @@
1
1
  import { AnyRouter, ProcedureType } from '@trpc/server';
2
2
  import { dataLoader } from '../internals/dataLoader';
3
- import { Observable } from 'rxjs';
3
+ import { observable } from '../observable/observable';
4
4
  import { TRPCLink } from './types';
5
- import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
5
+ import {
6
+ HTTPLinkOptions,
7
+ httpRequest,
8
+ ResponseShape,
9
+ } from './internals/httpUtils';
6
10
 
7
11
  export interface HttpBatchLinkOptions extends HTTPLinkOptions {
8
12
  maxBatchSize?: number;
@@ -52,7 +56,7 @@ export function httpBatchLink<TRouter extends AnyRouter>(
52
56
 
53
57
  const loaders = { query, subscription, mutation };
54
58
  return ({ op }) => {
55
- return new Observable((observer) => {
59
+ return observable((observer) => {
56
60
  const loader = loaders[op.type];
57
61
  const { promise, cancel } = loader.load(op);
58
62
 
@@ -1,7 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Observable } from 'rxjs';
2
+ import { observable } from '../observable/observable';
3
3
  import { TRPCLink } from './types';
4
- import { HTTPLinkOptions, httpRequest } from './httpUtils';
4
+ import { HTTPLinkOptions, httpRequest } from './internals/httpUtils';
5
5
 
6
6
  export function httpLink<TRouter extends AnyRouter>(
7
7
  opts: HTTPLinkOptions,
@@ -9,7 +9,7 @@ export function httpLink<TRouter extends AnyRouter>(
9
9
  const { url } = opts;
10
10
  return (runtime) =>
11
11
  ({ op }) =>
12
- new Observable((observer) => {
12
+ observable((observer) => {
13
13
  const { path, input, type } = op;
14
14
  const { promise, cancel } = httpRequest({
15
15
  runtime,
@@ -0,0 +1,10 @@
1
+ export * from './dedupeLink';
2
+ export * from './httpBatchLink';
3
+ export * from './httpLink';
4
+ export * from './loggerLink';
5
+ export * from './loggerLink';
6
+ export * from './retryLink';
7
+ export * from './splitLink';
8
+ export * from './transformerLink';
9
+ export * from './wsLink';
10
+ export * from './types';
@@ -1,13 +1,13 @@
1
1
  import { AnyRouter } from '@trpc/server/src';
2
2
  import { createChain } from './createChain';
3
- import { Observable } from 'rxjs';
3
+ import { observable } from '../../observable/observable';
4
4
 
5
5
  describe('chain', () => {
6
6
  test('trivial', () => {
7
7
  const result$ = createChain<AnyRouter, unknown, unknown>({
8
8
  links: [
9
9
  ({ next, op }) => {
10
- return new Observable((observer) => {
10
+ return observable((observer) => {
11
11
  const subscription = next(op).subscribe(observer);
12
12
  return () => {
13
13
  subscription.unsubscribe();
@@ -15,7 +15,7 @@ describe('chain', () => {
15
15
  });
16
16
  },
17
17
  ({ op }) => {
18
- return new Observable((observer) => {
18
+ return observable((observer) => {
19
19
  observer.next({
20
20
  context: {},
21
21
  data: {
@@ -51,7 +51,7 @@ describe('chain', () => {
51
51
  const result$ = createChain<AnyRouter, unknown, unknown>({
52
52
  links: [
53
53
  ({ next, op }) => {
54
- return new Observable((observer) => {
54
+ return observable((observer) => {
55
55
  observer.next({
56
56
  context: {},
57
57
  data: {
@@ -62,14 +62,14 @@ describe('chain', () => {
62
62
  },
63
63
  },
64
64
  });
65
- const next$ = next(op).subscribe(observer);
65
+ const subscription = next(op).subscribe(observer);
66
66
  return () => {
67
- next$.unsubscribe();
67
+ subscription.unsubscribe();
68
68
  };
69
69
  });
70
70
  },
71
71
  ({ op }) => {
72
- return new Observable((observer) => {
72
+ return observable((observer) => {
73
73
  observer.next({
74
74
  data: {
75
75
  id: null,
@@ -1,5 +1,5 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Observable } from 'rxjs';
2
+ import { observable } from '../../observable/observable';
3
3
  import { Operation, OperationLink, OperationResultObservable } from '../types';
4
4
 
5
5
  /** @internal */
@@ -11,10 +11,10 @@ export function createChain<
11
11
  links: OperationLink<TRouter, TInput, TOutput>[];
12
12
  op: Operation<TInput>;
13
13
  }): OperationResultObservable<TRouter, TOutput> {
14
- return new Observable((observer) => {
14
+ return observable((observer) => {
15
15
  function execute(index = 0, op = opts.op) {
16
16
  const next = opts.links[index];
17
- const next$ = next({
17
+ const subscription = next({
18
18
  op,
19
19
  next(nextOp) {
20
20
  const nextObserver = execute(index + 1, nextOp);
@@ -22,7 +22,7 @@ export function createChain<
22
22
  return nextObserver;
23
23
  },
24
24
  });
25
- return next$;
25
+ return subscription;
26
26
  }
27
27
 
28
28
  const obs$ = execute();
@@ -1,5 +1,5 @@
1
1
  import { ProcedureType } from '@trpc/server';
2
- import { LinkRuntime, PromiseAndCancel } from './types';
2
+ import { LinkRuntime, PromiseAndCancel } from '../types';
3
3
  export interface HTTPLinkOptions {
4
4
  url: string;
5
5
  }
@@ -1,6 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
2
  import { TRPCClientError } from '..';
3
- import { Observable, tap } from 'rxjs';
3
+ import { observable } from '../observable/observable';
4
+ import { tap } from '../observable/operators';
4
5
  import { Operation, OperationResult, TRPCLink } from './types';
5
6
 
6
7
  type ConsoleEsque = {
@@ -107,7 +108,7 @@ export function loggerLink<TRouter extends AnyRouter = AnyRouter>(
107
108
 
108
109
  return () => {
109
110
  return ({ op, next }) => {
110
- return new Observable((observer) => {
111
+ return observable((observer) => {
111
112
  // ->
112
113
  enabled({ ...op, direction: 'up' }) &&
113
114
  logger({
@@ -1,5 +1,6 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Observable, Unsubscribable } from 'rxjs';
2
+ import { observable } from '../observable/observable';
3
+ import { Unsubscribable } from '../observable/types';
3
4
  import { TRPCLink } from './types';
4
5
 
5
6
  export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
@@ -10,7 +11,7 @@ export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
10
11
  // initialized in app
11
12
  return ({ op, next }) => {
12
13
  // initialized for request
13
- return new Observable((observer) => {
14
+ return observable((observer) => {
14
15
  let next$: Unsubscribable | null = null;
15
16
  let attempts = 0;
16
17
  let isDone = false;
@@ -3,17 +3,17 @@ import { AnyRouter } from '../../../server/src';
3
3
  import { createChain } from '../links/internals/createChain';
4
4
  import { splitLink } from '../links/splitLink';
5
5
  import { OperationLink, TRPCLink } from '../links/types';
6
- import { Observable } from 'rxjs';
6
+ import { observable } from '../observable';
7
7
 
8
8
  test('splitLink', () => {
9
9
  const wsLinkSpy = jest.fn();
10
10
  const wsLink: TRPCLink<any> = () => () =>
11
- new Observable(() => {
11
+ observable(() => {
12
12
  wsLinkSpy();
13
13
  });
14
14
  const httpLinkSpy = jest.fn();
15
15
  const httpLink: TRPCLink<any> = () => () =>
16
- new Observable(() => {
16
+ observable(() => {
17
17
  httpLinkSpy();
18
18
  });
19
19
  const links: OperationLink<AnyRouter, any, any>[] = [
@@ -1,5 +1,5 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Observable } from 'rxjs';
2
+ import { observable } from '../observable/observable';
3
3
  import { TRPCLink, Operation } from './types';
4
4
  import { createChain } from './internals/createChain';
5
5
 
@@ -21,7 +21,7 @@ export function splitLink<TRouter extends AnyRouter = AnyRouter>(opts: {
21
21
  const yes = asArray(opts.true).map((link) => link(rt));
22
22
  const no = asArray(opts.false).map((link) => link(rt));
23
23
  return (props) => {
24
- return new Observable((observer) => {
24
+ return observable((observer) => {
25
25
  const links = opts.condition(props.op) ? yes : no;
26
26
  return createChain({ op: props.op, links }).subscribe(observer);
27
27
  });
@@ -3,7 +3,7 @@ import {
3
3
  ClientDataTransformerOptions,
4
4
  DataTransformer,
5
5
  } from '@trpc/server';
6
- import { Observable } from 'rxjs';
6
+ import { observable } from '../observable/observable';
7
7
  import { OperationResult, TRPCLink } from './types';
8
8
 
9
9
  /**
@@ -54,7 +54,7 @@ export function transformerLink<TRouter extends AnyRouter = AnyRouter>(
54
54
  return () => {
55
55
  return (props) => {
56
56
  const input = _transformer.serialize(props.op.input);
57
- return new Observable((observer) => {
57
+ return observable((observer) => {
58
58
  const subscription = props.next({ ...props.op, input }).subscribe({
59
59
  next(value) {
60
60
  const transformed = transformOperationResult(value, _transformer);
@@ -1,6 +1,7 @@
1
1
  import { AnyRouter, inferRouterError, Dict } from '@trpc/server';
2
2
  import { TRPCResponse } from '@trpc/server/rpc';
3
- import { Observable, Observer } from 'rxjs';
3
+ import { Observable, Observer } from '../observable/types';
4
+ import { TRPCClientError } from '../TRPCClientError';
4
5
 
5
6
  export type CancelFn = () => void;
6
7
 
@@ -43,12 +44,12 @@ export interface OperationResult<TRouter extends AnyRouter, TOutput> {
43
44
  export type OperationResultObservable<
44
45
  TRouter extends AnyRouter,
45
46
  TOutput,
46
- > = Observable<OperationResult<TRouter, TOutput>>;
47
+ > = Observable<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
47
48
 
48
49
  export type OperationResultObserver<
49
50
  TRouter extends AnyRouter,
50
51
  TOutput,
51
- > = Observer<OperationResult<TRouter, TOutput>>;
52
+ > = Observer<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
52
53
 
53
54
  export type OperationLink<
54
55
  TRouter extends AnyRouter,
@@ -6,12 +6,11 @@ import {
6
6
  TRPCResponse,
7
7
  } from '@trpc/server/rpc';
8
8
  import { retryDelay } from '../internals/retryDelay';
9
-
10
- import { Observable } from 'rxjs';
9
+ import { UnsubscribeFn } from '../observable';
10
+ import { observable } from '../observable/observable';
11
11
  import { TRPCClientError } from '../TRPCClientError';
12
12
  import { Operation, OperationResultObserver, TRPCLink } from './types';
13
13
 
14
- type UnsubscribeFn = () => void;
15
14
  export interface WebSocketClientOptions {
16
15
  url: string;
17
16
  WebSocket?: WebSocket;
@@ -283,7 +282,7 @@ export function wsLink<TRouter extends AnyRouter>(
283
282
  return () => {
284
283
  const { client } = opts;
285
284
  return ({ op }) => {
286
- return new Observable((observer) => {
285
+ return observable((observer) => {
287
286
  const { type, input, path, id, context } = op;
288
287
 
289
288
  let isDone = false;
@@ -0,0 +1,3 @@
1
+ export * from './observable';
2
+ export * from './types';
3
+ export * from './operators';
@@ -0,0 +1,103 @@
1
+ /* eslint-disable @typescript-eslint/no-empty-function */
2
+ import { observable } from './observable';
3
+ import { tap } from './operators';
4
+ import { share } from './operators/share';
5
+
6
+ test('vanilla observable - complete()', () => {
7
+ const obs = observable<number, Error>((observer) => {
8
+ observer.next(1);
9
+ observer.complete();
10
+ });
11
+
12
+ const next = jest.fn();
13
+ const error = jest.fn();
14
+ const complete = jest.fn();
15
+ obs.subscribe({
16
+ next,
17
+ error,
18
+ complete,
19
+ });
20
+ expect(next.mock.calls).toHaveLength(1);
21
+ expect(complete.mock.calls).toHaveLength(1);
22
+ expect(error.mock.calls).toHaveLength(0);
23
+ expect(next.mock.calls[0][0]).toBe(1);
24
+ });
25
+
26
+ test('vanilla observable - unsubscribe()', () => {
27
+ const obs$ = observable<number, Error>((observer) => {
28
+ observer.next(1);
29
+ });
30
+
31
+ const next = jest.fn();
32
+ const error = jest.fn();
33
+ const complete = jest.fn();
34
+ const sub = obs$.subscribe({
35
+ next,
36
+ error,
37
+ complete,
38
+ });
39
+ sub.unsubscribe();
40
+ expect(next.mock.calls).toHaveLength(1);
41
+ expect(complete.mock.calls).toHaveLength(0);
42
+ expect(error.mock.calls).toHaveLength(0);
43
+ expect(next.mock.calls[0][0]).toBe(1);
44
+ });
45
+
46
+ test('pipe - combine operators', () => {
47
+ const taps = {
48
+ next: jest.fn(),
49
+ complete: jest.fn(),
50
+ error: jest.fn(),
51
+ };
52
+ const obs = observable<number, Error>((observer) => {
53
+ observer.next(1);
54
+ }).pipe(
55
+ // operators:
56
+ share(),
57
+ tap(taps),
58
+ );
59
+ {
60
+ const next = jest.fn();
61
+ const error = jest.fn();
62
+ const complete = jest.fn();
63
+ obs.subscribe({
64
+ next,
65
+ error,
66
+ complete,
67
+ });
68
+ expect(next.mock.calls).toHaveLength(1);
69
+ expect(complete.mock.calls).toHaveLength(0);
70
+ expect(error.mock.calls).toHaveLength(0);
71
+ expect(next.mock.calls[0][0]).toBe(1);
72
+ }
73
+
74
+ {
75
+ const next = jest.fn();
76
+ const error = jest.fn();
77
+ const complete = jest.fn();
78
+ obs.subscribe({
79
+ next,
80
+ error,
81
+ complete,
82
+ });
83
+ expect(next.mock.calls).toHaveLength(0);
84
+ expect(complete.mock.calls).toHaveLength(0);
85
+ expect(error.mock.calls).toHaveLength(0);
86
+ }
87
+
88
+ expect({
89
+ next: taps.next.mock.calls,
90
+ error: taps.error.mock.calls,
91
+ complete: taps.complete.mock.calls,
92
+ }).toMatchInlineSnapshot(`
93
+ Object {
94
+ "complete": Array [],
95
+ "error": Array [],
96
+ "next": Array [
97
+ Array [
98
+ 1,
99
+ ],
100
+ ],
101
+ }
102
+ `);
103
+ });
@@ -0,0 +1,70 @@
1
+ import { pipeFromArray } from './util/pipe';
2
+ import { Observable, Observer, OperatorFunction, TeardownLogic } from './types';
3
+
4
+ export type inferObservableValue<TObservable extends Observable<any, any>> =
5
+ TObservable extends Observable<infer TValue, any> ? TValue : never;
6
+
7
+ export function observable<TValue, TError = unknown>(
8
+ subscribe: (observer: Observer<TValue, TError>) => TeardownLogic,
9
+ ): Observable<TValue, TError> {
10
+ const self: Observable<TValue, TError> = {
11
+ subscribe(observer) {
12
+ let teardownRef: TeardownLogic | null = null;
13
+ let isDone = false;
14
+ let unsubscribed = false;
15
+ let teardownImmediately = false;
16
+ function unsubscribe() {
17
+ if (teardownRef === null) {
18
+ teardownImmediately = true;
19
+ return;
20
+ }
21
+ if (unsubscribed) {
22
+ return;
23
+ }
24
+ unsubscribed = true;
25
+
26
+ if (typeof teardownRef === 'function') {
27
+ teardownRef();
28
+ } else if (teardownRef) {
29
+ teardownRef.unsubscribe();
30
+ }
31
+ }
32
+ teardownRef = subscribe({
33
+ next(value) {
34
+ if (isDone) {
35
+ return;
36
+ }
37
+ observer.next?.(value);
38
+ },
39
+ error(err) {
40
+ if (isDone) {
41
+ return;
42
+ }
43
+ isDone = true;
44
+ observer.error?.(err);
45
+ unsubscribe();
46
+ },
47
+ complete() {
48
+ if (isDone) {
49
+ return;
50
+ }
51
+ isDone = true;
52
+ observer.complete?.();
53
+ unsubscribe();
54
+ },
55
+ });
56
+ if (teardownImmediately) {
57
+ unsubscribe();
58
+ }
59
+ return {
60
+ unsubscribe,
61
+ };
62
+ },
63
+ pipe(
64
+ ...operations: OperatorFunction<any, any, any, any>[]
65
+ ): Observable<any, any> {
66
+ return pipeFromArray(operations)(self) as any;
67
+ },
68
+ };
69
+ return self;
70
+ }
@@ -0,0 +1,3 @@
1
+ export * from './share';
2
+ export * from './map';
3
+ export * from './tap';
@@ -0,0 +1,92 @@
1
+ import { expectTypeOf } from 'expect-type';
2
+ import { observable } from '../observable';
3
+ import { map } from '.';
4
+ import { EventEmitter } from 'events';
5
+
6
+ interface SubscriptionEvents<TOutput> {
7
+ data: (data: TOutput) => void;
8
+ }
9
+
10
+ declare interface CustomEventEmitter<TOutput> {
11
+ on<U extends keyof SubscriptionEvents<TOutput>>(
12
+ event: U,
13
+ listener: SubscriptionEvents<TOutput>[U],
14
+ ): this;
15
+
16
+ once<U extends keyof SubscriptionEvents<TOutput>>(
17
+ event: U,
18
+ listener: SubscriptionEvents<TOutput>[U],
19
+ ): this;
20
+
21
+ emit<U extends keyof SubscriptionEvents<TOutput>>(
22
+ event: U,
23
+ ...args: Parameters<SubscriptionEvents<TOutput>[U]>
24
+ ): boolean;
25
+ }
26
+ class CustomEventEmitter<TOutput>
27
+ extends EventEmitter
28
+ implements CustomEventEmitter<TOutput> {}
29
+ test('map', () => {
30
+ type EventShape = { num: number };
31
+ const ee = new CustomEventEmitter<EventShape>();
32
+ const eventObservable = observable<EventShape, unknown>((observer) => {
33
+ const callback = (data: EventShape) => {
34
+ observer.next(data);
35
+ };
36
+ ee.on('data', callback);
37
+
38
+ return () => {
39
+ ee.off('data', callback);
40
+ };
41
+ });
42
+ const pipeCalls = jest.fn();
43
+ const piped = eventObservable.pipe(
44
+ map((...args) => {
45
+ pipeCalls(...args);
46
+ const [value] = args;
47
+ return value.num;
48
+ }),
49
+ );
50
+
51
+ const next = jest.fn();
52
+ const subscription = piped.subscribe({
53
+ next(value) {
54
+ expectTypeOf<number>(value);
55
+ next(value);
56
+ },
57
+ });
58
+ expect(next).not.toHaveBeenCalled();
59
+ ee.emit('data', { num: 1 });
60
+ ee.emit('data', { num: 2 });
61
+ expect(next).toHaveBeenCalledTimes(2);
62
+ expect(next.mock.calls).toMatchInlineSnapshot(`
63
+ Array [
64
+ Array [
65
+ 1,
66
+ ],
67
+ Array [
68
+ 2,
69
+ ],
70
+ ]
71
+ `);
72
+ expect(pipeCalls.mock.calls).toMatchInlineSnapshot(`
73
+ Array [
74
+ Array [
75
+ Object {
76
+ "num": 1,
77
+ },
78
+ 0,
79
+ ],
80
+ Array [
81
+ Object {
82
+ "num": 2,
83
+ },
84
+ 1,
85
+ ],
86
+ ]
87
+ `);
88
+
89
+ expect(ee.listeners('data')).toHaveLength(1);
90
+ subscription.unsubscribe();
91
+ expect(ee.listeners('data')).toHaveLength(0);
92
+ });
@@ -0,0 +1,25 @@
1
+ import { OperatorFunction } from '../types';
2
+
3
+ export function map<TValueBefore, TError, TValueAfter>(
4
+ project: (value: TValueBefore, index: number) => TValueAfter,
5
+ ): OperatorFunction<TValueBefore, TError, TValueAfter, TError> {
6
+ return (originalObserver) => {
7
+ return {
8
+ subscribe(observer) {
9
+ let index = 0;
10
+ const subscription = originalObserver.subscribe({
11
+ next(value) {
12
+ observer.next?.(project(value, index++));
13
+ },
14
+ error(error) {
15
+ observer.error?.(error);
16
+ },
17
+ complete() {
18
+ observer.complete?.();
19
+ },
20
+ });
21
+ return subscription;
22
+ },
23
+ };
24
+ };
25
+ }
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-var */
2
+ import { observable } from '../observable';
3
+ import { share } from './share';
4
+
5
+ test('share', () => {
6
+ const obs = share()(
7
+ observable<number, Error>((observer) => {
8
+ observer.next(1);
9
+ }),
10
+ );
11
+
12
+ {
13
+ const next = jest.fn();
14
+ const error = jest.fn();
15
+ const complete = jest.fn();
16
+ var subscription1 = obs.subscribe({
17
+ next,
18
+ error,
19
+ complete,
20
+ });
21
+ expect(next.mock.calls).toHaveLength(1);
22
+ expect(complete.mock.calls).toHaveLength(0);
23
+ expect(error.mock.calls).toHaveLength(0);
24
+ expect(next.mock.calls[0][0]).toBe(1);
25
+ }
26
+
27
+ {
28
+ // subscribe again - it's shared so should not propagate any results
29
+ const next = jest.fn();
30
+ const error = jest.fn();
31
+ const complete = jest.fn();
32
+ var subscription2 = obs.subscribe({
33
+ next,
34
+ error,
35
+ complete,
36
+ });
37
+ expect(next.mock.calls).toHaveLength(0);
38
+ expect(complete.mock.calls).toHaveLength(0);
39
+ expect(error.mock.calls).toHaveLength(0);
40
+ }
41
+
42
+ subscription1.unsubscribe();
43
+ subscription2.unsubscribe();
44
+ // now it should be reset so we can do a new subscription
45
+ {
46
+ const next = jest.fn();
47
+ const error = jest.fn();
48
+ const complete = jest.fn();
49
+ var subscription3 = obs.subscribe({
50
+ next,
51
+ error,
52
+ complete,
53
+ });
54
+ expect(next.mock.calls).toHaveLength(1);
55
+ expect(complete.mock.calls).toHaveLength(0);
56
+ expect(error.mock.calls).toHaveLength(0);
57
+ expect(next.mock.calls[0][0]).toBe(1);
58
+ subscription3.unsubscribe();
59
+ }
60
+ });