@trpc/server 10.0.0-alpha.21 → 10.0.0-alpha.24
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/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.d.ts +1 -0
- package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.dev.js +90 -0
- package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.js +7 -0
- package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.prod.js +90 -0
- package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.esm.js +86 -0
- package/adapters/express/dist/trpc-server-adapters-express.cjs.dev.js +3 -3
- package/adapters/express/dist/trpc-server-adapters-express.cjs.prod.js +3 -3
- package/adapters/express/dist/trpc-server-adapters-express.esm.js +3 -3
- package/adapters/fastify/dist/trpc-server-adapters-fastify.cjs.dev.js +3 -3
- package/adapters/fastify/dist/trpc-server-adapters-fastify.cjs.prod.js +3 -3
- package/adapters/fastify/dist/trpc-server-adapters-fastify.esm.js +3 -3
- package/adapters/fastify/index.js +1 -1
- package/adapters/fetch/index.d.ts +1 -0
- package/adapters/fetch/index.js +1 -0
- package/adapters/next/dist/trpc-server-adapters-next.cjs.dev.js +3 -3
- package/adapters/next/dist/trpc-server-adapters-next.cjs.prod.js +3 -3
- package/adapters/next/dist/trpc-server-adapters-next.esm.js +3 -3
- package/adapters/node-http/dist/trpc-server-adapters-node-http.cjs.dev.js +3 -3
- package/adapters/node-http/dist/trpc-server-adapters-node-http.cjs.prod.js +3 -3
- package/adapters/node-http/dist/trpc-server-adapters-node-http.esm.js +3 -3
- package/adapters/standalone/dist/trpc-server-adapters-standalone.cjs.dev.js +3 -3
- package/adapters/standalone/dist/trpc-server-adapters-standalone.cjs.prod.js +3 -3
- package/adapters/standalone/dist/trpc-server-adapters-standalone.esm.js +3 -3
- package/dist/{transformTRPCResponse-9fdeecca.mjs → TRPCError-7971540a.mjs} +1 -53
- package/dist/{transformTRPCResponse-a57d3226.js → TRPCError-ddec3395.js} +0 -54
- package/dist/adapters/express.js +5 -4
- package/dist/adapters/express.mjs +5 -4
- package/dist/adapters/fastify/index.js +6 -6
- package/dist/adapters/fastify/index.mjs +6 -6
- package/dist/adapters/fetch/fetchRequestHandler.d.ts +8 -0
- package/dist/adapters/fetch/fetchRequestHandler.d.ts.map +1 -0
- package/dist/adapters/fetch/index.d.ts +3 -0
- package/dist/adapters/fetch/index.d.ts.map +1 -0
- package/dist/adapters/fetch/index.js +69 -0
- package/dist/adapters/fetch/index.mjs +65 -0
- package/dist/adapters/fetch/index.ts.js +1 -0
- package/dist/adapters/fetch/types.d.ts +21 -0
- package/dist/adapters/fetch/types.d.ts.map +1 -0
- package/dist/adapters/next.d.ts.map +1 -1
- package/dist/adapters/next.js +9 -9
- package/dist/adapters/next.mjs +8 -8
- package/dist/adapters/node-http/index.js +5 -4
- package/dist/adapters/node-http/index.mjs +5 -4
- package/dist/adapters/node-http/types.d.ts +6 -5
- package/dist/adapters/node-http/types.d.ts.map +1 -1
- package/dist/adapters/standalone.js +5 -4
- package/dist/adapters/standalone.mjs +5 -4
- package/dist/adapters/ws.d.ts +1 -1
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/adapters/ws.js +117 -80
- package/dist/adapters/ws.mjs +111 -74
- package/dist/{codes-6c13cf43.mjs → envelopes-1deb2fa7.mjs} +17 -1
- package/dist/{codes-4e4d55a9.js → envelopes-a953b930.js} +16 -0
- package/dist/http/index.d.ts +1 -1
- package/dist/http/internals/types.d.ts +2 -2
- package/dist/http/resolveHTTPResponse.d.ts.map +1 -1
- package/dist/http/{ResponseMeta.d.ts → responseMeta.d.ts} +1 -1
- package/dist/http/responseMeta.d.ts.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -52
- package/dist/index.mjs +31 -43
- package/dist/internals/{BaseHandlerOptions.d.ts → baseHandlerOptions.d.ts} +2 -2
- package/dist/internals/{BaseHandlerOptions.d.ts.map → baseHandlerOptions.d.ts.map} +1 -1
- package/dist/internals/callProcedure.d.ts +2 -2
- package/dist/internals/callProcedure.d.ts.map +1 -1
- package/dist/internals/middlewares.d.ts +3 -1
- package/dist/internals/middlewares.d.ts.map +1 -1
- package/dist/internals/{OnErrorFunction.d.ts → onErrorFunction.d.ts} +1 -1
- package/dist/internals/{OnErrorFunction.d.ts.map → onErrorFunction.d.ts.map} +1 -1
- package/dist/internals/procedure.d.ts +4 -3
- package/dist/internals/procedure.d.ts.map +1 -1
- package/dist/internals/transformTRPCResponse.d.ts +4 -2
- package/dist/internals/transformTRPCResponse.d.ts.map +1 -1
- package/dist/{nodeHTTPRequestHandler-13c4bded.mjs → nodeHTTPRequestHandler-1cdb6383.mjs} +2 -2
- package/dist/{nodeHTTPRequestHandler-745e43e5.js → nodeHTTPRequestHandler-848f07b5.js} +3 -3
- package/dist/observable/index.d.ts +5 -0
- package/dist/observable/index.d.ts.map +1 -0
- package/dist/observable/index.js +204 -0
- package/dist/observable/index.mjs +195 -0
- package/dist/observable/index.ts.js +1 -0
- package/dist/observable/internals/identity.d.ts +2 -0
- package/dist/observable/internals/identity.d.ts.map +1 -0
- package/dist/observable/internals/observableToPromise.d.ts +10 -0
- package/dist/observable/internals/observableToPromise.d.ts.map +1 -0
- package/dist/observable/internals/pipe.d.ts +4 -0
- package/dist/observable/internals/pipe.d.ts.map +1 -0
- package/dist/observable/observable.d.ts +5 -0
- package/dist/observable/observable.d.ts.map +1 -0
- package/dist/observable/operators/index.d.ts +4 -0
- package/dist/observable/operators/index.d.ts.map +1 -0
- package/dist/observable/operators/map.d.ts +3 -0
- package/dist/observable/operators/map.d.ts.map +1 -0
- package/dist/observable/operators/share.d.ts +6 -0
- package/dist/observable/operators/share.d.ts.map +1 -0
- package/dist/observable/operators/tap.d.ts +3 -0
- package/dist/observable/operators/tap.d.ts.map +1 -0
- package/dist/observable/types.d.ts +29 -0
- package/dist/observable/types.d.ts.map +1 -0
- package/dist/observable-137ea1bd.mjs +105 -0
- package/dist/observable-3aa4d911.js +108 -0
- package/dist/{resolveHTTPResponse-de40fda7.mjs → resolveHTTPResponse-54a79e6c.mjs} +14 -20
- package/dist/{resolveHTTPResponse-b1167b6a.js → resolveHTTPResponse-ec3dccaa.js} +21 -27
- package/dist/router.d.ts +6 -6
- package/dist/router.d.ts.map +1 -1
- package/dist/rpc/envelopes.d.ts +61 -39
- package/dist/rpc/envelopes.d.ts.map +1 -1
- package/dist/rpc/index.js +7 -3
- package/dist/rpc/index.mjs +1 -1
- package/dist/subscription.d.ts +3 -52
- package/dist/subscription.d.ts.map +1 -1
- package/dist/subscription.js +44 -0
- package/dist/subscription.mjs +40 -0
- package/dist/subscription.ts.js +1 -0
- package/dist/transformTRPCResponse-333bed6c.js +56 -0
- package/dist/transformTRPCResponse-e0cba527.mjs +53 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/observable/index.d.ts +1 -0
- package/observable/index.js +1 -0
- package/package.json +25 -7
- package/rpc/dist/trpc-server-rpc.cjs.dev.js +1 -1
- package/rpc/dist/trpc-server-rpc.cjs.prod.js +1 -1
- package/rpc/dist/trpc-server-rpc.esm.js +1 -1
- package/src/adapters/fastify/fastifyTRPCPlugin.ts +1 -1
- package/src/adapters/fetch/fetchRequestHandler.ts +61 -0
- package/src/adapters/fetch/index.ts +2 -0
- package/src/adapters/fetch/types.ts +28 -0
- package/src/adapters/next.ts +3 -5
- package/src/adapters/node-http/types.ts +6 -5
- package/src/adapters/ws.ts +110 -72
- package/src/http/index.ts +1 -1
- package/src/http/internals/types.ts +2 -2
- package/src/http/resolveHTTPResponse.ts +16 -20
- package/src/http/{ResponseMeta.ts → responseMeta.ts} +0 -0
- package/src/index.ts +0 -1
- package/src/internals/{BaseHandlerOptions.ts → baseHandlerOptions.ts} +1 -1
- package/src/internals/callProcedure.ts +6 -3
- package/src/internals/middlewares.ts +4 -1
- package/src/internals/{OnErrorFunction.ts → onErrorFunction.ts} +0 -0
- package/src/internals/procedure.ts +40 -27
- package/src/internals/transformTRPCResponse.ts +20 -15
- package/src/observable/index.ts +4 -0
- package/src/observable/internals/identity.ts +3 -0
- package/src/observable/internals/observableToPromise.ts +49 -0
- package/src/observable/internals/pipe.ts +22 -0
- package/src/observable/observable.test.ts +101 -0
- package/src/observable/observable.ts +75 -0
- package/src/observable/operators/index.ts +3 -0
- package/src/observable/operators/map.test.ts +92 -0
- package/src/observable/operators/map.ts +25 -0
- package/src/observable/operators/share.test.ts +60 -0
- package/src/observable/operators/share.ts +67 -0
- package/src/observable/operators/tap.ts +26 -0
- package/src/observable/types.ts +69 -0
- package/src/router.ts +7 -9
- package/src/rpc/envelopes.ts +87 -68
- package/src/subscription.ts +5 -123
- package/src/types.ts +7 -0
- package/dist/http/ResponseMeta.d.ts.map +0 -1
- package/dist/internals/wrapCallSafe.d.ts +0 -16
- package/dist/internals/wrapCallSafe.d.ts.map +0 -1
- package/dist/subscription-4b936ba3.js +0 -136
- package/dist/subscription-8a85f253.mjs +0 -133
- package/src/internals/wrapCallSafe.ts +0 -19
- package/ws/dist/trpc-server-ws.cjs.d.ts +0 -1
- package/ws/dist/trpc-server-ws.cjs.dev.js +0 -15
- package/ws/dist/trpc-server-ws.cjs.js +0 -7
- package/ws/dist/trpc-server-ws.cjs.prod.js +0 -15
- package/ws/dist/trpc-server-ws.esm.js +0 -11
- package/ws/index.d.ts +0 -1
- package/ws/index.js +0 -1
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
inferRouterContext,
|
|
10
10
|
inferRouterError,
|
|
11
11
|
} from '../router';
|
|
12
|
-
import {
|
|
12
|
+
import { TRPCResponse } from '../rpc';
|
|
13
13
|
import { Maybe } from '../types';
|
|
14
14
|
import { getHTTPStatusCode } from './internals/getHTTPStatusCode';
|
|
15
15
|
import {
|
|
@@ -196,12 +196,11 @@ export async function resolveHTTPResponse<
|
|
|
196
196
|
}),
|
|
197
197
|
);
|
|
198
198
|
const errors = rawResults.flatMap((obj) => (obj.error ? [obj.error] : []));
|
|
199
|
-
const resultEnvelopes = rawResults.map((obj) => {
|
|
199
|
+
const resultEnvelopes = rawResults.map((obj): TRouterResponse => {
|
|
200
200
|
const { path, input } = obj;
|
|
201
201
|
|
|
202
202
|
if (obj.error) {
|
|
203
|
-
|
|
204
|
-
id: null,
|
|
203
|
+
return {
|
|
205
204
|
error: router.getErrorShape({
|
|
206
205
|
error: obj.error,
|
|
207
206
|
type,
|
|
@@ -210,16 +209,12 @@ export async function resolveHTTPResponse<
|
|
|
210
209
|
ctx,
|
|
211
210
|
}),
|
|
212
211
|
};
|
|
213
|
-
return json;
|
|
214
212
|
} else {
|
|
215
|
-
|
|
216
|
-
id: null,
|
|
213
|
+
return {
|
|
217
214
|
result: {
|
|
218
|
-
type: 'data',
|
|
219
215
|
data: obj.data,
|
|
220
216
|
},
|
|
221
217
|
};
|
|
222
|
-
return json;
|
|
223
218
|
}
|
|
224
219
|
});
|
|
225
220
|
|
|
@@ -233,16 +228,6 @@ export async function resolveHTTPResponse<
|
|
|
233
228
|
// - input deserialization fails
|
|
234
229
|
const error = getErrorFromUnknown(cause);
|
|
235
230
|
|
|
236
|
-
const json: TRPCErrorResponse<TRouterError> = {
|
|
237
|
-
id: null,
|
|
238
|
-
error: router.getErrorShape({
|
|
239
|
-
error,
|
|
240
|
-
type,
|
|
241
|
-
path: undefined,
|
|
242
|
-
input: undefined,
|
|
243
|
-
ctx,
|
|
244
|
-
}),
|
|
245
|
-
};
|
|
246
231
|
onError?.({
|
|
247
232
|
error,
|
|
248
233
|
path: undefined,
|
|
@@ -251,6 +236,17 @@ export async function resolveHTTPResponse<
|
|
|
251
236
|
type: type,
|
|
252
237
|
req,
|
|
253
238
|
});
|
|
254
|
-
return endResponse(
|
|
239
|
+
return endResponse(
|
|
240
|
+
{
|
|
241
|
+
error: router.getErrorShape({
|
|
242
|
+
error,
|
|
243
|
+
type,
|
|
244
|
+
path: undefined,
|
|
245
|
+
input: undefined,
|
|
246
|
+
ctx,
|
|
247
|
+
}),
|
|
248
|
+
},
|
|
249
|
+
[error],
|
|
250
|
+
);
|
|
255
251
|
}
|
|
256
252
|
}
|
|
File without changes
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { Observable } from '../observable';
|
|
1
2
|
import { AnyRouter, ProcedureType } from '../router';
|
|
2
|
-
import { Subscription } from '../subscription';
|
|
3
3
|
|
|
4
4
|
export async function callProcedure<
|
|
5
5
|
TRouter extends AnyRouter<TContext>,
|
|
@@ -10,7 +10,7 @@ export async function callProcedure<
|
|
|
10
10
|
router: TRouter;
|
|
11
11
|
ctx: TContext;
|
|
12
12
|
type: ProcedureType;
|
|
13
|
-
}): Promise<unknown |
|
|
13
|
+
}): Promise<unknown | Observable<TRouter, any>> {
|
|
14
14
|
const { type, path, input } = opts;
|
|
15
15
|
|
|
16
16
|
const caller = opts.router.createCaller(opts.ctx);
|
|
@@ -21,7 +21,10 @@ export async function callProcedure<
|
|
|
21
21
|
return caller.mutation(path, input as any);
|
|
22
22
|
}
|
|
23
23
|
if (type === 'subscription') {
|
|
24
|
-
const sub = (await caller.subscription(path, input as any)) as
|
|
24
|
+
const sub = (await caller.subscription(path, input as any)) as Observable<
|
|
25
|
+
any,
|
|
26
|
+
any
|
|
27
|
+
>;
|
|
25
28
|
return sub;
|
|
26
29
|
}
|
|
27
30
|
/* istanbul ignore next */
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { TRPCError } from '../TRPCError';
|
|
2
2
|
import { ProcedureType } from '../router';
|
|
3
3
|
|
|
4
|
-
export const middlewareMarker =
|
|
4
|
+
export const middlewareMarker = 'middlewareMarker' as 'middlewareMarker' & {
|
|
5
|
+
__brand: 'middlewareMarker';
|
|
6
|
+
};
|
|
7
|
+
|
|
5
8
|
interface MiddlewareResultBase<TContext> {
|
|
6
9
|
/**
|
|
7
10
|
* All middlewares should pass through their `next()`'s output.
|
|
File without changes
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
import { TRPCError } from '../TRPCError';
|
|
3
3
|
import { assertNotBrowser } from '../assertNotBrowser';
|
|
4
4
|
import { ProcedureType } from '../router';
|
|
5
|
+
import { InferLast } from '../types';
|
|
5
6
|
import { getCauseFromUnknown, getErrorFromUnknown } from './errors';
|
|
6
|
-
import {
|
|
7
|
-
|
|
7
|
+
import {
|
|
8
|
+
MiddlewareFunction,
|
|
9
|
+
MiddlewareResult,
|
|
10
|
+
middlewareMarker,
|
|
11
|
+
} from './middlewares';
|
|
8
12
|
|
|
9
13
|
assertNotBrowser();
|
|
10
14
|
|
|
@@ -166,7 +170,7 @@ export class Procedure<
|
|
|
166
170
|
): Promise<TFinalOutput> {
|
|
167
171
|
// wrap the actual resolver and treat as the last "middleware"
|
|
168
172
|
const middlewaresWithResolver = this.middlewares.concat([
|
|
169
|
-
async ({ ctx }: { ctx:
|
|
173
|
+
async ({ ctx }: { ctx: any }) => {
|
|
170
174
|
const input = await this.parseInput(opts.rawInput);
|
|
171
175
|
const rawOutput = await this.resolver({
|
|
172
176
|
...opts,
|
|
@@ -183,31 +187,40 @@ export class Procedure<
|
|
|
183
187
|
},
|
|
184
188
|
]);
|
|
185
189
|
|
|
186
|
-
//
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
190
|
+
// run the middlewares recursively with the resolver as the last one
|
|
191
|
+
const callRecursive = async (
|
|
192
|
+
callOpts: { ctx: any; index: number } = {
|
|
193
|
+
index: 0,
|
|
194
|
+
ctx: opts.ctx,
|
|
195
|
+
},
|
|
196
|
+
): Promise<MiddlewareResult<any>> => {
|
|
197
|
+
try {
|
|
198
|
+
const result = await middlewaresWithResolver[callOpts.index]({
|
|
199
|
+
ctx: callOpts.ctx,
|
|
200
|
+
type: opts.type,
|
|
201
|
+
path: opts.path,
|
|
202
|
+
rawInput: opts.rawInput,
|
|
203
|
+
meta: this.meta,
|
|
204
|
+
next: async (nextOpts?: { ctx: any }) => {
|
|
205
|
+
return await callRecursive({
|
|
206
|
+
index: callOpts.index + 1,
|
|
207
|
+
ctx: nextOpts ? nextOpts.ctx : callOpts.ctx,
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
return result;
|
|
212
|
+
} catch (cause) {
|
|
202
213
|
return {
|
|
203
|
-
|
|
204
|
-
|
|
214
|
+
ctx: callOpts.ctx,
|
|
215
|
+
ok: false,
|
|
216
|
+
error: getErrorFromUnknown(cause),
|
|
217
|
+
marker: middlewareMarker,
|
|
205
218
|
};
|
|
206
|
-
}
|
|
207
|
-
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
208
221
|
|
|
209
222
|
// there's always at least one "next" since we wrap this.resolver in a middleware
|
|
210
|
-
const result = await
|
|
223
|
+
const result = await callRecursive();
|
|
211
224
|
if (!result) {
|
|
212
225
|
throw new TRPCError({
|
|
213
226
|
code: 'INTERNAL_SERVER_ERROR',
|
|
@@ -266,7 +279,7 @@ export type CreateProcedureWithInput<TContext, TMeta, TInput, TOutput> = {
|
|
|
266
279
|
input: ProcedureParser<TInput>;
|
|
267
280
|
output?: ProcedureParser<TOutput>;
|
|
268
281
|
meta?: TMeta;
|
|
269
|
-
resolve: ProcedureResolver<TContext, TInput, TOutput
|
|
282
|
+
resolve: ProcedureResolver<TContext, TInput, InferLast<TOutput>>;
|
|
270
283
|
};
|
|
271
284
|
|
|
272
285
|
export type CreateProcedureWithInputOutputParser<
|
|
@@ -280,7 +293,7 @@ export type CreateProcedureWithInputOutputParser<
|
|
|
280
293
|
input: ProcedureParserWithInputOutput<TInput, TParsedInput>;
|
|
281
294
|
output?: ProcedureParserWithInputOutput<TOutput, TParsedOutput>;
|
|
282
295
|
meta?: TMeta;
|
|
283
|
-
resolve: ProcedureResolver<TContext, TParsedInput, TOutput
|
|
296
|
+
resolve: ProcedureResolver<TContext, TParsedInput, InferLast<TOutput>>;
|
|
284
297
|
};
|
|
285
298
|
|
|
286
299
|
export type CreateProcedureWithoutInput<
|
|
@@ -293,7 +306,7 @@ export type CreateProcedureWithoutInput<
|
|
|
293
306
|
| ProcedureParserWithInputOutput<TOutput, TParsedOutput>
|
|
294
307
|
| ProcedureParser<TOutput>;
|
|
295
308
|
meta?: TMeta;
|
|
296
|
-
resolve: ProcedureResolver<TContext, undefined, TOutput
|
|
309
|
+
resolve: ProcedureResolver<TContext, undefined, InferLast<TOutput>>;
|
|
297
310
|
};
|
|
298
311
|
|
|
299
312
|
export type CreateProcedureOptions<
|
|
@@ -1,33 +1,38 @@
|
|
|
1
1
|
import { AnyRouter } from '../router';
|
|
2
|
-
import { TRPCResponse } from '../rpc';
|
|
2
|
+
import { TRPCResponse, TRPCResponseMessage } from '../rpc';
|
|
3
3
|
|
|
4
|
-
function transformTRPCResponseItem
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
): TRPCResponse {
|
|
4
|
+
function transformTRPCResponseItem<
|
|
5
|
+
TResponseItem extends TRPCResponse | TRPCResponseMessage,
|
|
6
|
+
>(router: AnyRouter, item: TResponseItem): TResponseItem {
|
|
8
7
|
if ('error' in item) {
|
|
9
8
|
return {
|
|
10
9
|
...item,
|
|
11
10
|
error: router._def.transformer.output.serialize(item.error),
|
|
12
11
|
};
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
|
|
14
|
+
if ('data' in item.result) {
|
|
15
|
+
return {
|
|
16
|
+
...item,
|
|
17
|
+
result: {
|
|
18
|
+
...item.result,
|
|
19
|
+
data: router._def.transformer.output.serialize(item.result.data),
|
|
20
|
+
},
|
|
21
|
+
};
|
|
16
22
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
result: {
|
|
20
|
-
...item.result,
|
|
21
|
-
data: router._def.transformer.output.serialize(item.result.data),
|
|
22
|
-
},
|
|
23
|
-
};
|
|
23
|
+
|
|
24
|
+
return item;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Takes a unserialized `TRPCResponse` and serializes it with the router's transformers
|
|
28
29
|
**/
|
|
29
30
|
export function transformTRPCResponse<
|
|
30
|
-
TResponse extends
|
|
31
|
+
TResponse extends
|
|
32
|
+
| TRPCResponse
|
|
33
|
+
| TRPCResponse[]
|
|
34
|
+
| TRPCResponseMessage
|
|
35
|
+
| TRPCResponseMessage[],
|
|
31
36
|
>(router: AnyRouter, itemOrItems: TResponse) {
|
|
32
37
|
return Array.isArray(itemOrItems)
|
|
33
38
|
? itemOrItems.map((item) => transformTRPCResponseItem(router, item))
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Observable } from '../types';
|
|
2
|
+
|
|
3
|
+
export class ObservableAbortError extends Error {
|
|
4
|
+
constructor(message: string) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'ObservableAbortError';
|
|
7
|
+
Object.setPrototypeOf(this, ObservableAbortError.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** @internal */
|
|
12
|
+
export function observableToPromise<TValue>(
|
|
13
|
+
observable: Observable<TValue, unknown>,
|
|
14
|
+
) {
|
|
15
|
+
let abort: () => void;
|
|
16
|
+
const promise = new Promise<TValue>((resolve, reject) => {
|
|
17
|
+
let isDone = false;
|
|
18
|
+
function onDone() {
|
|
19
|
+
if (isDone) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
isDone = true;
|
|
23
|
+
reject(new ObservableAbortError('This operation was cancelled.'));
|
|
24
|
+
obs$.unsubscribe();
|
|
25
|
+
}
|
|
26
|
+
const obs$ = observable.subscribe({
|
|
27
|
+
next(data) {
|
|
28
|
+
isDone = true;
|
|
29
|
+
resolve(data);
|
|
30
|
+
onDone();
|
|
31
|
+
},
|
|
32
|
+
error(data) {
|
|
33
|
+
isDone = true;
|
|
34
|
+
reject(data);
|
|
35
|
+
onDone();
|
|
36
|
+
},
|
|
37
|
+
complete() {
|
|
38
|
+
isDone = true;
|
|
39
|
+
onDone();
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
abort = onDone;
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
promise,
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
47
|
+
abort: abort!,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { UnaryFunction } from '../types';
|
|
2
|
+
import { identity } from './identity';
|
|
3
|
+
|
|
4
|
+
/** @internal */
|
|
5
|
+
export function pipeFromArray<T, R>(
|
|
6
|
+
fns: Array<UnaryFunction<T, R>>,
|
|
7
|
+
): UnaryFunction<T, R> {
|
|
8
|
+
if (fns.length === 0) {
|
|
9
|
+
return identity as UnaryFunction<any, any>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (fns.length === 1) {
|
|
13
|
+
return fns[0];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return function piped(input: T): R {
|
|
17
|
+
return fns.reduce(
|
|
18
|
+
(prev: any, fn: UnaryFunction<T, R>) => fn(prev),
|
|
19
|
+
input as any,
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
+
import { observable, share, tap } from '.';
|
|
3
|
+
|
|
4
|
+
test('vanilla observable - complete()', () => {
|
|
5
|
+
const obs = observable<number, Error>((observer) => {
|
|
6
|
+
observer.next(1);
|
|
7
|
+
observer.complete();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const next = jest.fn();
|
|
11
|
+
const error = jest.fn();
|
|
12
|
+
const complete = jest.fn();
|
|
13
|
+
obs.subscribe({
|
|
14
|
+
next,
|
|
15
|
+
error,
|
|
16
|
+
complete,
|
|
17
|
+
});
|
|
18
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
19
|
+
expect(complete.mock.calls).toHaveLength(1);
|
|
20
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
21
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('vanilla observable - unsubscribe()', () => {
|
|
25
|
+
const obs$ = observable<number, Error>((observer) => {
|
|
26
|
+
observer.next(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const next = jest.fn();
|
|
30
|
+
const error = jest.fn();
|
|
31
|
+
const complete = jest.fn();
|
|
32
|
+
const sub = obs$.subscribe({
|
|
33
|
+
next,
|
|
34
|
+
error,
|
|
35
|
+
complete,
|
|
36
|
+
});
|
|
37
|
+
sub.unsubscribe();
|
|
38
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
39
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
40
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
41
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('pipe - combine operators', () => {
|
|
45
|
+
const taps = {
|
|
46
|
+
next: jest.fn(),
|
|
47
|
+
complete: jest.fn(),
|
|
48
|
+
error: jest.fn(),
|
|
49
|
+
};
|
|
50
|
+
const obs = observable<number, Error>((observer) => {
|
|
51
|
+
observer.next(1);
|
|
52
|
+
}).pipe(
|
|
53
|
+
// operators:
|
|
54
|
+
share(),
|
|
55
|
+
tap(taps),
|
|
56
|
+
);
|
|
57
|
+
{
|
|
58
|
+
const next = jest.fn();
|
|
59
|
+
const error = jest.fn();
|
|
60
|
+
const complete = jest.fn();
|
|
61
|
+
obs.subscribe({
|
|
62
|
+
next,
|
|
63
|
+
error,
|
|
64
|
+
complete,
|
|
65
|
+
});
|
|
66
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
67
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
68
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
69
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
const next = jest.fn();
|
|
74
|
+
const error = jest.fn();
|
|
75
|
+
const complete = jest.fn();
|
|
76
|
+
obs.subscribe({
|
|
77
|
+
next,
|
|
78
|
+
error,
|
|
79
|
+
complete,
|
|
80
|
+
});
|
|
81
|
+
expect(next.mock.calls).toHaveLength(0);
|
|
82
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
83
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
expect({
|
|
87
|
+
next: taps.next.mock.calls,
|
|
88
|
+
error: taps.error.mock.calls,
|
|
89
|
+
complete: taps.complete.mock.calls,
|
|
90
|
+
}).toMatchInlineSnapshot(`
|
|
91
|
+
Object {
|
|
92
|
+
"complete": Array [],
|
|
93
|
+
"error": Array [],
|
|
94
|
+
"next": Array [
|
|
95
|
+
Array [
|
|
96
|
+
1,
|
|
97
|
+
],
|
|
98
|
+
],
|
|
99
|
+
}
|
|
100
|
+
`);
|
|
101
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { pipeFromArray } from './internals/pipe';
|
|
2
|
+
import { Observable, Observer, OperatorFunction, TeardownLogic } from './types';
|
|
3
|
+
|
|
4
|
+
export type inferObservableValue<
|
|
5
|
+
TObservable extends Observable<unknown, unknown>,
|
|
6
|
+
> = TObservable extends Observable<infer TValue, unknown> ? TValue : never;
|
|
7
|
+
|
|
8
|
+
export function isObservable(x: unknown): x is Observable<unknown, unknown> {
|
|
9
|
+
return typeof x === 'object' && x !== null && 'subscribe' in x;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function observable<TValue, TError = unknown>(
|
|
13
|
+
subscribe: (observer: Observer<TValue, TError>) => TeardownLogic,
|
|
14
|
+
): Observable<TValue, TError> {
|
|
15
|
+
const self: Observable<TValue, TError> = {
|
|
16
|
+
subscribe(observer) {
|
|
17
|
+
let teardownRef: TeardownLogic | null = null;
|
|
18
|
+
let isDone = false;
|
|
19
|
+
let unsubscribed = false;
|
|
20
|
+
let teardownImmediately = false;
|
|
21
|
+
function unsubscribe() {
|
|
22
|
+
if (teardownRef === null) {
|
|
23
|
+
teardownImmediately = true;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (unsubscribed) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
unsubscribed = true;
|
|
30
|
+
|
|
31
|
+
if (typeof teardownRef === 'function') {
|
|
32
|
+
teardownRef();
|
|
33
|
+
} else if (teardownRef) {
|
|
34
|
+
teardownRef.unsubscribe();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
teardownRef = subscribe({
|
|
38
|
+
next(value) {
|
|
39
|
+
if (isDone) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
observer.next?.(value);
|
|
43
|
+
},
|
|
44
|
+
error(err) {
|
|
45
|
+
if (isDone) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
isDone = true;
|
|
49
|
+
observer.error?.(err);
|
|
50
|
+
unsubscribe();
|
|
51
|
+
},
|
|
52
|
+
complete() {
|
|
53
|
+
if (isDone) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
isDone = true;
|
|
57
|
+
observer.complete?.();
|
|
58
|
+
unsubscribe();
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (teardownImmediately) {
|
|
62
|
+
unsubscribe();
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
unsubscribe,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
pipe(
|
|
69
|
+
...operations: OperatorFunction<any, any, any, any>[]
|
|
70
|
+
): Observable<any, any> {
|
|
71
|
+
return pipeFromArray(operations)(self) as any;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
return self;
|
|
75
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { expectTypeOf } from 'expect-type';
|
|
3
|
+
import { map } from '.';
|
|
4
|
+
import { observable } from '../observable';
|
|
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
|
+
}
|