@trpc/server 11.0.0-alpha-tmp-export-from-main.221 → 11.0.0-alpha-tmp-export-from-main.222
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/adapters/aws-lambda/index.d.mts +68 -0
- package/dist/adapters/aws-lambda/index.d.ts +54 -6
- package/dist/adapters/aws-lambda/index.js +110 -20
- package/dist/adapters/aws-lambda/index.mjs +94 -4
- package/dist/adapters/express.d.mts +19 -0
- package/dist/adapters/express.d.ts +9 -6
- package/dist/adapters/express.js +3 -3
- package/dist/adapters/express.mjs +1 -1
- package/dist/adapters/fastify/index.d.mts +33 -0
- package/dist/adapters/fastify/index.d.ts +33 -3
- package/dist/adapters/fastify/index.js +124 -5
- package/dist/adapters/fastify/index.mjs +125 -2
- package/dist/adapters/fetch/index.d.mts +51 -0
- package/dist/adapters/fetch/index.d.ts +51 -3
- package/dist/adapters/fetch/index.js +115 -4
- package/dist/adapters/fetch/index.mjs +116 -1
- package/dist/adapters/next.d.mts +21 -0
- package/dist/adapters/next.d.ts +11 -7
- package/dist/adapters/next.js +6 -6
- package/dist/adapters/next.mjs +2 -2
- package/dist/adapters/node-http/content-type/form-data/index.d.mts +219 -0
- package/dist/adapters/node-http/content-type/form-data/index.d.ts +201 -10
- package/dist/adapters/node-http/content-type/form-data/index.js +662 -23
- package/dist/adapters/node-http/content-type/form-data/index.mjs +646 -10
- package/dist/adapters/node-http/{types.d.ts → content-type/json/index.d.mts} +21 -15
- package/dist/adapters/node-http/content-type/json/index.d.ts +89 -2
- package/dist/adapters/node-http/content-type/json/index.js +48 -7
- package/dist/adapters/node-http/content-type/json/index.mjs +44 -3
- package/dist/adapters/node-http/index.d.mts +100 -0
- package/dist/adapters/node-http/index.d.ts +100 -3
- package/dist/adapters/node-http/index.js +106 -4
- package/dist/adapters/node-http/index.mjs +107 -1
- package/dist/adapters/standalone.d.mts +21 -0
- package/dist/adapters/standalone.d.ts +11 -9
- package/dist/adapters/standalone.js +9 -5
- package/dist/adapters/standalone.mjs +2 -2
- package/dist/adapters/ws.d.mts +36 -0
- package/dist/adapters/ws.d.ts +12 -13
- package/dist/adapters/ws.js +30 -28
- package/dist/adapters/ws.mjs +12 -10
- package/dist/http.d.mts +1 -0
- package/dist/http.d.ts +1 -7
- package/dist/http.js +7 -7
- package/dist/http.mjs +1 -1
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +5 -65
- package/dist/index.js +809 -46
- package/dist/index.mjs +798 -1
- package/dist/observable.d.mts +1 -0
- package/dist/observable.d.ts +1 -3
- package/dist/observable.js +8 -8
- package/dist/observable.mjs +1 -1
- package/dist/rpc.d.mts +1 -0
- package/dist/rpc.d.ts +1 -3
- package/dist/rpc.js +5 -5
- package/dist/rpc.mjs +1 -1
- package/dist/shared.d.mts +1 -0
- package/dist/shared.d.ts +1 -26
- package/dist/shared.js +4 -4
- package/dist/shared.mjs +1 -1
- package/dist/unstableDontImportMe.d.mts +1 -0
- package/dist/unstableDontImportMe.d.ts +1 -10
- package/dist/unstableDontImportMe.js +1549 -142
- package/dist/unstableDontImportMe.mjs +1514 -1
- package/package.json +6 -4
- package/dist/@trpc-server/http.d.ts +0 -2
- package/dist/@trpc-server/http.d.ts.map +0 -1
- package/dist/adapters/aws-lambda/index.d.ts.map +0 -1
- package/dist/adapters/aws-lambda/utils.d.ts +0 -48
- package/dist/adapters/aws-lambda/utils.d.ts.map +0 -1
- package/dist/adapters/aws-lambda/utils.js +0 -100
- package/dist/adapters/aws-lambda/utils.mjs +0 -93
- package/dist/adapters/express.d.ts.map +0 -1
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts +0 -13
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts.map +0 -1
- package/dist/adapters/fastify/fastifyRequestHandler.js +0 -81
- package/dist/adapters/fastify/fastifyRequestHandler.mjs +0 -79
- package/dist/adapters/fastify/fastifyTRPCPlugin.d.ts +0 -22
- package/dist/adapters/fastify/fastifyTRPCPlugin.d.ts.map +0 -1
- package/dist/adapters/fastify/fastifyTRPCPlugin.js +0 -51
- package/dist/adapters/fastify/fastifyTRPCPlugin.mjs +0 -49
- package/dist/adapters/fastify/index.d.ts.map +0 -1
- package/dist/adapters/fetch/fetchRequestHandler.d.ts +0 -18
- package/dist/adapters/fetch/fetchRequestHandler.d.ts.map +0 -1
- package/dist/adapters/fetch/fetchRequestHandler.js +0 -118
- package/dist/adapters/fetch/fetchRequestHandler.mjs +0 -116
- package/dist/adapters/fetch/index.d.ts.map +0 -1
- package/dist/adapters/fetch/types.d.ts +0 -31
- package/dist/adapters/fetch/types.d.ts.map +0 -1
- package/dist/adapters/next.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.d.ts +0 -70
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.js +0 -161
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.mjs +0 -157
- package/dist/adapters/node-http/content-type/form-data/index.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/memoryUploadHandler.d.ts +0 -31
- package/dist/adapters/node-http/content-type/form-data/memoryUploadHandler.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/memoryUploadHandler.js +0 -29
- package/dist/adapters/node-http/content-type/form-data/memoryUploadHandler.mjs +0 -27
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts +0 -16
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/streamSlice.js +0 -46
- package/dist/adapters/node-http/content-type/form-data/streamSlice.mjs +0 -44
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.d.ts +0 -45
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.js +0 -30
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.mjs +0 -26
- package/dist/adapters/node-http/content-type/json/getPostBody.d.ts +0 -7
- package/dist/adapters/node-http/content-type/json/getPostBody.d.ts.map +0 -1
- package/dist/adapters/node-http/content-type/json/getPostBody.js +0 -42
- package/dist/adapters/node-http/content-type/json/getPostBody.mjs +0 -40
- package/dist/adapters/node-http/content-type/json/index.d.ts.map +0 -1
- package/dist/adapters/node-http/index.d.ts.map +0 -1
- package/dist/adapters/node-http/internals/contentType.d.ts +0 -9
- package/dist/adapters/node-http/internals/contentType.d.ts.map +0 -1
- package/dist/adapters/node-http/internals/contentType.js +0 -8
- package/dist/adapters/node-http/internals/contentType.mjs +0 -6
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts +0 -14
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +0 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +0 -109
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +0 -107
- package/dist/adapters/node-http/types.d.ts.map +0 -1
- package/dist/adapters/standalone.d.ts.map +0 -1
- package/dist/adapters/ws.d.ts.map +0 -1
- package/dist/http.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/index.js +0 -203
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/index.mjs +0 -201
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/search.js +0 -167
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/search.mjs +0 -163
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/utils.js +0 -35
- package/dist/node_modules/.pnpm/@web3-storage_multipart-parser@1.0.0/node_modules/@web3-storage/multipart-parser/esm/src/utils.mjs +0 -30
- package/dist/observable.d.ts.map +0 -1
- package/dist/rpc.d.ts.map +0 -1
- package/dist/shared.d.ts.map +0 -1
- package/dist/unstableDontImportMe.d.ts.map +0 -1
|
@@ -1,142 +1,1549 @@
|
|
|
1
|
-
'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Object.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/ function invert(obj) {
|
|
6
|
+
const newObj = Object.create(null);
|
|
7
|
+
for(const key in obj){
|
|
8
|
+
const v = obj[key];
|
|
9
|
+
newObj[v] = key;
|
|
10
|
+
}
|
|
11
|
+
return newObj;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ensures there are no duplicate keys when building a procedure.
|
|
15
|
+
* @internal
|
|
16
|
+
*/ function mergeWithoutOverrides(obj1, ...objs) {
|
|
17
|
+
const newObj = Object.assign(Object.create(null), obj1);
|
|
18
|
+
for (const overrides of objs){
|
|
19
|
+
for(const key in overrides){
|
|
20
|
+
if (key in newObj && newObj[key] !== overrides[key]) {
|
|
21
|
+
throw new Error(`Duplicate key ${key}`);
|
|
22
|
+
}
|
|
23
|
+
newObj[key] = overrides[key];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return newObj;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check that value is object
|
|
30
|
+
* @internal
|
|
31
|
+
*/ function isObject(value) {
|
|
32
|
+
return !!value && !Array.isArray(value) && typeof value === 'object';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create an object without inheriting anything from `Object.prototype`
|
|
36
|
+
* @internal
|
|
37
|
+
*/ function omitPrototype(obj) {
|
|
38
|
+
return Object.assign(Object.create(null), obj);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @internal
|
|
42
|
+
*/ function identity(x) {
|
|
43
|
+
return x;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// reference: https://www.jsonrpc.org/specification
|
|
47
|
+
/**
|
|
48
|
+
* JSON-RPC 2.0 Error codes
|
|
49
|
+
*
|
|
50
|
+
* `-32000` to `-32099` are reserved for implementation-defined server-errors.
|
|
51
|
+
* For tRPC we're copying the last digits of HTTP 4XX errors.
|
|
52
|
+
*/ const TRPC_ERROR_CODES_BY_KEY = {
|
|
53
|
+
/**
|
|
54
|
+
* Invalid JSON was received by the server.
|
|
55
|
+
* An error occurred on the server while parsing the JSON text.
|
|
56
|
+
*/ PARSE_ERROR: -32700,
|
|
57
|
+
/**
|
|
58
|
+
* The JSON sent is not a valid Request object.
|
|
59
|
+
*/ BAD_REQUEST: -32600,
|
|
60
|
+
// Internal JSON-RPC error
|
|
61
|
+
INTERNAL_SERVER_ERROR: -32603,
|
|
62
|
+
NOT_IMPLEMENTED: -32603,
|
|
63
|
+
// Implementation specific errors
|
|
64
|
+
UNAUTHORIZED: -32001,
|
|
65
|
+
FORBIDDEN: -32003,
|
|
66
|
+
NOT_FOUND: -32004,
|
|
67
|
+
METHOD_NOT_SUPPORTED: -32005,
|
|
68
|
+
TIMEOUT: -32008,
|
|
69
|
+
CONFLICT: -32009,
|
|
70
|
+
PRECONDITION_FAILED: -32012,
|
|
71
|
+
PAYLOAD_TOO_LARGE: -32013,
|
|
72
|
+
UNPROCESSABLE_CONTENT: -32022,
|
|
73
|
+
TOO_MANY_REQUESTS: -32029,
|
|
74
|
+
CLIENT_CLOSED_REQUEST: -32099
|
|
75
|
+
};
|
|
76
|
+
const TRPC_ERROR_CODES_BY_NUMBER = invert(TRPC_ERROR_CODES_BY_KEY);
|
|
77
|
+
|
|
78
|
+
const procedureTypes = [
|
|
79
|
+
'query',
|
|
80
|
+
'mutation',
|
|
81
|
+
'subscription'
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
/* istanbul ignore next -- @preserve */ function assertIsObject(obj) {
|
|
85
|
+
if (!isObject(obj)) {
|
|
86
|
+
throw new Error('Not an object');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/* istanbul ignore next -- @preserve */ function assertIsProcedureType(obj) {
|
|
90
|
+
if (!procedureTypes.includes(obj)) {
|
|
91
|
+
throw new Error('Invalid procedure type');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/* istanbul ignore next -- @preserve */ function assertIsRequestId(obj) {
|
|
95
|
+
if (obj !== null && typeof obj === 'number' && isNaN(obj) && typeof obj !== 'string') {
|
|
96
|
+
throw new Error('Invalid request id');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/* istanbul ignore next -- @preserve */ function assertIsString(obj) {
|
|
100
|
+
if (typeof obj !== 'string') {
|
|
101
|
+
throw new Error('Invalid string');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/* istanbul ignore next -- @preserve */ function assertIsJSONRPC2OrUndefined(obj) {
|
|
105
|
+
if (typeof obj !== 'undefined' && obj !== '2.0') {
|
|
106
|
+
throw new Error('Must be JSONRPC 2.0');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** @public */ function parseTRPCMessage(obj, transformer) {
|
|
110
|
+
assertIsObject(obj);
|
|
111
|
+
const { id, jsonrpc, method, params } = obj;
|
|
112
|
+
assertIsRequestId(id);
|
|
113
|
+
assertIsJSONRPC2OrUndefined(jsonrpc);
|
|
114
|
+
if (method === 'subscription.stop') {
|
|
115
|
+
return {
|
|
116
|
+
id,
|
|
117
|
+
jsonrpc,
|
|
118
|
+
method
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
assertIsProcedureType(method);
|
|
122
|
+
assertIsObject(params);
|
|
123
|
+
const { input: rawInput, path } = params;
|
|
124
|
+
assertIsString(path);
|
|
125
|
+
const input = transformer.input.deserialize(rawInput);
|
|
126
|
+
return {
|
|
127
|
+
id,
|
|
128
|
+
jsonrpc,
|
|
129
|
+
method,
|
|
130
|
+
params: {
|
|
131
|
+
input,
|
|
132
|
+
path
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const JSONRPC2_TO_HTTP_CODE = {
|
|
138
|
+
PARSE_ERROR: 400,
|
|
139
|
+
BAD_REQUEST: 400,
|
|
140
|
+
UNAUTHORIZED: 401,
|
|
141
|
+
NOT_FOUND: 404,
|
|
142
|
+
FORBIDDEN: 403,
|
|
143
|
+
METHOD_NOT_SUPPORTED: 405,
|
|
144
|
+
TIMEOUT: 408,
|
|
145
|
+
CONFLICT: 409,
|
|
146
|
+
PRECONDITION_FAILED: 412,
|
|
147
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
148
|
+
UNPROCESSABLE_CONTENT: 422,
|
|
149
|
+
TOO_MANY_REQUESTS: 429,
|
|
150
|
+
CLIENT_CLOSED_REQUEST: 499,
|
|
151
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
152
|
+
NOT_IMPLEMENTED: 501
|
|
153
|
+
};
|
|
154
|
+
function getStatusCodeFromKey(code) {
|
|
155
|
+
return JSONRPC2_TO_HTTP_CODE[code] ?? 500;
|
|
156
|
+
}
|
|
157
|
+
function getHTTPStatusCode(json) {
|
|
158
|
+
const arr = Array.isArray(json) ? json : [
|
|
159
|
+
json
|
|
160
|
+
];
|
|
161
|
+
const httpStatuses = new Set(arr.map((res)=>{
|
|
162
|
+
if ('error' in res) {
|
|
163
|
+
const data = res.error.data;
|
|
164
|
+
if (typeof data['httpStatus'] === 'number') {
|
|
165
|
+
return data['httpStatus'];
|
|
166
|
+
}
|
|
167
|
+
const code = TRPC_ERROR_CODES_BY_NUMBER[res.error.code];
|
|
168
|
+
return getStatusCodeFromKey(code);
|
|
169
|
+
}
|
|
170
|
+
return 200;
|
|
171
|
+
}));
|
|
172
|
+
if (httpStatuses.size !== 1) {
|
|
173
|
+
return 207;
|
|
174
|
+
}
|
|
175
|
+
const httpStatus = httpStatuses.values().next().value;
|
|
176
|
+
return httpStatus;
|
|
177
|
+
}
|
|
178
|
+
function getHTTPStatusCodeFromError(error) {
|
|
179
|
+
return getStatusCodeFromKey(error.code);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @internal
|
|
184
|
+
*/ function getErrorShape(opts) {
|
|
185
|
+
const { path, error, config } = opts;
|
|
186
|
+
const { code } = opts.error;
|
|
187
|
+
const shape = {
|
|
188
|
+
message: error.message,
|
|
189
|
+
code: TRPC_ERROR_CODES_BY_KEY[code],
|
|
190
|
+
data: {
|
|
191
|
+
code,
|
|
192
|
+
httpStatus: getHTTPStatusCodeFromError(error)
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
if (config.isDev && typeof opts.error.stack === 'string') {
|
|
196
|
+
shape.data.stack = opts.error.stack;
|
|
197
|
+
}
|
|
198
|
+
if (typeof path === 'string') {
|
|
199
|
+
shape.data.path = path;
|
|
200
|
+
}
|
|
201
|
+
return config.errorFormatter({
|
|
202
|
+
...opts,
|
|
203
|
+
shape
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
class UnknownCauseError extends Error {
|
|
208
|
+
}
|
|
209
|
+
function getCauseFromUnknown(cause) {
|
|
210
|
+
if (cause instanceof Error) {
|
|
211
|
+
return cause;
|
|
212
|
+
}
|
|
213
|
+
const type = typeof cause;
|
|
214
|
+
if (type === 'undefined' || type === 'function' || cause === null) {
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
// Primitive types just get wrapped in an error
|
|
218
|
+
if (type !== 'object') {
|
|
219
|
+
return new Error(String(cause));
|
|
220
|
+
}
|
|
221
|
+
// If it's an object, we'll create a synthetic error
|
|
222
|
+
if (isObject(cause)) {
|
|
223
|
+
const err = new UnknownCauseError();
|
|
224
|
+
for(const key in cause){
|
|
225
|
+
err[key] = cause[key];
|
|
226
|
+
}
|
|
227
|
+
return err;
|
|
228
|
+
}
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
function getTRPCErrorFromUnknown(cause) {
|
|
232
|
+
if (cause instanceof TRPCError) {
|
|
233
|
+
return cause;
|
|
234
|
+
}
|
|
235
|
+
if (cause instanceof Error && cause.name === 'TRPCError') {
|
|
236
|
+
// https://github.com/trpc/trpc/pull/4848
|
|
237
|
+
return cause;
|
|
238
|
+
}
|
|
239
|
+
const trpcError = new TRPCError({
|
|
240
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
241
|
+
cause
|
|
242
|
+
});
|
|
243
|
+
// Inherit stack from error
|
|
244
|
+
if (cause instanceof Error && cause.stack) {
|
|
245
|
+
trpcError.stack = cause.stack;
|
|
246
|
+
}
|
|
247
|
+
return trpcError;
|
|
248
|
+
}
|
|
249
|
+
class TRPCError extends Error {
|
|
250
|
+
constructor(opts){
|
|
251
|
+
const cause = getCauseFromUnknown(opts.cause);
|
|
252
|
+
const message = opts.message ?? cause?.message ?? opts.code;
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
254
|
+
// @ts-ignore https://github.com/tc39/proposal-error-cause
|
|
255
|
+
super(message, {
|
|
256
|
+
cause
|
|
257
|
+
});
|
|
258
|
+
this.code = opts.code;
|
|
259
|
+
this.name = 'TRPCError';
|
|
260
|
+
if (!this.cause) {
|
|
261
|
+
// < ES2022 / < Node 16.9.0 compatability
|
|
262
|
+
this.cause = cause;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const noop = ()=>{
|
|
268
|
+
// noop
|
|
269
|
+
};
|
|
270
|
+
function createInnerProxy(callback, path) {
|
|
271
|
+
const proxy = new Proxy(noop, {
|
|
272
|
+
get (_obj, key) {
|
|
273
|
+
if (typeof key !== 'string' || key === 'then') {
|
|
274
|
+
// special case for if the proxy is accidentally treated
|
|
275
|
+
// like a PromiseLike (like in `Promise.resolve(proxy)`)
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
return createInnerProxy(callback, [
|
|
279
|
+
...path,
|
|
280
|
+
key
|
|
281
|
+
]);
|
|
282
|
+
},
|
|
283
|
+
apply (_1, _2, args) {
|
|
284
|
+
const isApply = path[path.length - 1] === 'apply';
|
|
285
|
+
return callback({
|
|
286
|
+
args: isApply ? args.length >= 2 ? args[1] : [] : args,
|
|
287
|
+
path: isApply ? path.slice(0, -1) : path
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
return proxy;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Creates a proxy that calls the callback with the path and arguments
|
|
295
|
+
*
|
|
296
|
+
* @internal
|
|
297
|
+
*/ const createRecursiveProxy = (callback)=>createInnerProxy(callback, []);
|
|
298
|
+
/**
|
|
299
|
+
* Used in place of `new Proxy` where each handler will map 1 level deep to another value.
|
|
300
|
+
*
|
|
301
|
+
* @internal
|
|
302
|
+
*/ const createFlatProxy = (callback)=>{
|
|
303
|
+
return new Proxy(noop, {
|
|
304
|
+
get (_obj, name) {
|
|
305
|
+
if (typeof name !== 'string' || name === 'then') {
|
|
306
|
+
// special case for if the proxy is accidentally treated
|
|
307
|
+
// like a PromiseLike (like in `Promise.resolve(proxy)`)
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
return callback(name);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const defaultFormatter = ({ shape })=>{
|
|
316
|
+
return shape;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/** @internal */ const middlewareMarker = 'middlewareMarker';
|
|
320
|
+
/**
|
|
321
|
+
* @internal
|
|
322
|
+
*/ function createMiddlewareFactory() {
|
|
323
|
+
function createMiddlewareInner(middlewares) {
|
|
324
|
+
return {
|
|
325
|
+
_middlewares: middlewares,
|
|
326
|
+
unstable_pipe (middlewareBuilderOrFn) {
|
|
327
|
+
const pipedMiddleware = '_middlewares' in middlewareBuilderOrFn ? middlewareBuilderOrFn._middlewares : [
|
|
328
|
+
middlewareBuilderOrFn
|
|
329
|
+
];
|
|
330
|
+
return createMiddlewareInner([
|
|
331
|
+
...middlewares,
|
|
332
|
+
...pipedMiddleware
|
|
333
|
+
]);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function createMiddleware(fn) {
|
|
338
|
+
return createMiddlewareInner([
|
|
339
|
+
fn
|
|
340
|
+
]);
|
|
341
|
+
}
|
|
342
|
+
return createMiddleware;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Create a standalone middleware
|
|
346
|
+
* @link https://trpc.io/docs/v11/server/middlewares#experimental-standalone-middlewares
|
|
347
|
+
*/ const experimental_standaloneMiddleware = ()=>({
|
|
348
|
+
create: createMiddlewareFactory()
|
|
349
|
+
});
|
|
350
|
+
/**
|
|
351
|
+
* @internal
|
|
352
|
+
* Please note, `trpc-openapi` uses this function.
|
|
353
|
+
*/ function createInputMiddleware(parse) {
|
|
354
|
+
const inputMiddleware = async function inputValidatorMiddleware(opts) {
|
|
355
|
+
let parsedInput;
|
|
356
|
+
const rawInput = await opts.getRawInput();
|
|
357
|
+
try {
|
|
358
|
+
parsedInput = await parse(rawInput);
|
|
359
|
+
} catch (cause) {
|
|
360
|
+
throw new TRPCError({
|
|
361
|
+
code: 'BAD_REQUEST',
|
|
362
|
+
cause
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// Multiple input parsers
|
|
366
|
+
const combinedInput = isObject(opts.input) && isObject(parsedInput) ? {
|
|
367
|
+
...opts.input,
|
|
368
|
+
...parsedInput
|
|
369
|
+
} : parsedInput;
|
|
370
|
+
return opts.next({
|
|
371
|
+
input: combinedInput
|
|
372
|
+
});
|
|
373
|
+
};
|
|
374
|
+
inputMiddleware._type = 'input';
|
|
375
|
+
return inputMiddleware;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* @internal
|
|
379
|
+
*/ function createOutputMiddleware(parse) {
|
|
380
|
+
const outputMiddleware = async function outputValidatorMiddleware({ next }) {
|
|
381
|
+
const result = await next();
|
|
382
|
+
if (!result.ok) {
|
|
383
|
+
// pass through failures without validating
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
const data = await parse(result.data);
|
|
388
|
+
return {
|
|
389
|
+
...result,
|
|
390
|
+
data
|
|
391
|
+
};
|
|
392
|
+
} catch (cause) {
|
|
393
|
+
throw new TRPCError({
|
|
394
|
+
message: 'Output validation failed',
|
|
395
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
396
|
+
cause
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
outputMiddleware._type = 'output';
|
|
401
|
+
return outputMiddleware;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// zod / @decs/typeschema
|
|
405
|
+
function getParseFn(procedureParser) {
|
|
406
|
+
const parser = procedureParser;
|
|
407
|
+
if (typeof parser === 'function') {
|
|
408
|
+
// ParserCustomValidatorEsque
|
|
409
|
+
return parser;
|
|
410
|
+
}
|
|
411
|
+
if (typeof parser.parseAsync === 'function') {
|
|
412
|
+
// ParserZodEsque
|
|
413
|
+
return parser.parseAsync.bind(parser);
|
|
414
|
+
}
|
|
415
|
+
if (typeof parser.parse === 'function') {
|
|
416
|
+
// ParserZodEsque
|
|
417
|
+
// ParserValibotEsque (<= v0.12.X)
|
|
418
|
+
return parser.parse.bind(parser);
|
|
419
|
+
}
|
|
420
|
+
if (typeof parser.validateSync === 'function') {
|
|
421
|
+
// ParserYupEsque
|
|
422
|
+
return parser.validateSync.bind(parser);
|
|
423
|
+
}
|
|
424
|
+
if (typeof parser.create === 'function') {
|
|
425
|
+
// ParserSuperstructEsque
|
|
426
|
+
return parser.create.bind(parser);
|
|
427
|
+
}
|
|
428
|
+
if (typeof parser.assert === 'function') {
|
|
429
|
+
// ParserScaleEsque
|
|
430
|
+
return (value)=>{
|
|
431
|
+
parser.assert(value);
|
|
432
|
+
return value;
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
throw new Error('Could not find a validator fn');
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** @internal */ const unsetMarker = Symbol('unsetMarker');
|
|
439
|
+
function createNewBuilder(def1, def2) {
|
|
440
|
+
const { middlewares = [], inputs, meta, ...rest } = def2;
|
|
441
|
+
// TODO: maybe have a fn here to warn about calls
|
|
442
|
+
return createBuilder({
|
|
443
|
+
...mergeWithoutOverrides(def1, rest),
|
|
444
|
+
inputs: [
|
|
445
|
+
...def1.inputs,
|
|
446
|
+
...inputs ?? []
|
|
447
|
+
],
|
|
448
|
+
middlewares: [
|
|
449
|
+
...def1.middlewares,
|
|
450
|
+
...middlewares
|
|
451
|
+
],
|
|
452
|
+
meta: def1.meta && meta ? {
|
|
453
|
+
...def1.meta,
|
|
454
|
+
...meta
|
|
455
|
+
} : meta ?? def1.meta
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
function createBuilder(initDef = {}) {
|
|
459
|
+
const _def = {
|
|
460
|
+
procedure: true,
|
|
461
|
+
inputs: [],
|
|
462
|
+
middlewares: [],
|
|
463
|
+
...initDef
|
|
464
|
+
};
|
|
465
|
+
const builder = {
|
|
466
|
+
_def,
|
|
467
|
+
input (input) {
|
|
468
|
+
const parser = getParseFn(input);
|
|
469
|
+
return createNewBuilder(_def, {
|
|
470
|
+
inputs: [
|
|
471
|
+
input
|
|
472
|
+
],
|
|
473
|
+
middlewares: [
|
|
474
|
+
createInputMiddleware(parser)
|
|
475
|
+
]
|
|
476
|
+
});
|
|
477
|
+
},
|
|
478
|
+
output (output) {
|
|
479
|
+
const parser = getParseFn(output);
|
|
480
|
+
return createNewBuilder(_def, {
|
|
481
|
+
output,
|
|
482
|
+
middlewares: [
|
|
483
|
+
createOutputMiddleware(parser)
|
|
484
|
+
]
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
meta (meta) {
|
|
488
|
+
return createNewBuilder(_def, {
|
|
489
|
+
meta
|
|
490
|
+
});
|
|
491
|
+
},
|
|
492
|
+
use (middlewareBuilderOrFn) {
|
|
493
|
+
// Distinguish between a middleware builder and a middleware function
|
|
494
|
+
const middlewares = '_middlewares' in middlewareBuilderOrFn ? middlewareBuilderOrFn._middlewares : [
|
|
495
|
+
middlewareBuilderOrFn
|
|
496
|
+
];
|
|
497
|
+
return createNewBuilder(_def, {
|
|
498
|
+
middlewares: middlewares
|
|
499
|
+
});
|
|
500
|
+
},
|
|
501
|
+
query (resolver) {
|
|
502
|
+
return createResolver({
|
|
503
|
+
..._def,
|
|
504
|
+
type: 'query'
|
|
505
|
+
}, resolver);
|
|
506
|
+
},
|
|
507
|
+
mutation (resolver) {
|
|
508
|
+
return createResolver({
|
|
509
|
+
..._def,
|
|
510
|
+
type: 'mutation'
|
|
511
|
+
}, resolver);
|
|
512
|
+
},
|
|
513
|
+
subscription (resolver) {
|
|
514
|
+
return createResolver({
|
|
515
|
+
..._def,
|
|
516
|
+
type: 'subscription'
|
|
517
|
+
}, resolver);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
return builder;
|
|
521
|
+
}
|
|
522
|
+
function createResolver(_def, resolver) {
|
|
523
|
+
const finalBuilder = createNewBuilder(_def, {
|
|
524
|
+
resolver,
|
|
525
|
+
middlewares: [
|
|
526
|
+
async function resolveMiddleware(opts) {
|
|
527
|
+
const data = await resolver(opts);
|
|
528
|
+
return {
|
|
529
|
+
marker: middlewareMarker,
|
|
530
|
+
ok: true,
|
|
531
|
+
data,
|
|
532
|
+
ctx: opts.ctx
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
]
|
|
536
|
+
});
|
|
537
|
+
return createProcedureCaller(finalBuilder._def);
|
|
538
|
+
}
|
|
539
|
+
const codeblock = `
|
|
540
|
+
This is a client-only function.
|
|
541
|
+
If you want to call this function on the server, see https://trpc.io/docs/v11/server/server-side-calls
|
|
542
|
+
`.trim();
|
|
543
|
+
function createProcedureCaller(_def) {
|
|
544
|
+
async function procedure(opts) {
|
|
545
|
+
// is direct server-side call
|
|
546
|
+
if (!opts || !('getRawInput' in opts)) {
|
|
547
|
+
throw new Error(codeblock);
|
|
548
|
+
}
|
|
549
|
+
// run the middlewares recursively with the resolver as the last one
|
|
550
|
+
async function callRecursive(callOpts = {
|
|
551
|
+
index: 0,
|
|
552
|
+
ctx: opts.ctx
|
|
553
|
+
}) {
|
|
554
|
+
try {
|
|
555
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
556
|
+
const middleware = _def.middlewares[callOpts.index];
|
|
557
|
+
const result = await middleware({
|
|
558
|
+
ctx: callOpts.ctx,
|
|
559
|
+
type: opts.type,
|
|
560
|
+
path: opts.path,
|
|
561
|
+
getRawInput: callOpts.getRawInput ?? opts.getRawInput,
|
|
562
|
+
meta: _def.meta,
|
|
563
|
+
input: callOpts.input,
|
|
564
|
+
next (_nextOpts) {
|
|
565
|
+
const nextOpts = _nextOpts;
|
|
566
|
+
return callRecursive({
|
|
567
|
+
index: callOpts.index + 1,
|
|
568
|
+
ctx: nextOpts && 'ctx' in nextOpts ? {
|
|
569
|
+
...callOpts.ctx,
|
|
570
|
+
...nextOpts.ctx
|
|
571
|
+
} : callOpts.ctx,
|
|
572
|
+
input: nextOpts && 'input' in nextOpts ? nextOpts.input : callOpts.input,
|
|
573
|
+
getRawInput: nextOpts && 'getRawInput' in nextOpts ? nextOpts.getRawInput : callOpts.getRawInput
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
return result;
|
|
578
|
+
} catch (cause) {
|
|
579
|
+
return {
|
|
580
|
+
ok: false,
|
|
581
|
+
error: getTRPCErrorFromUnknown(cause),
|
|
582
|
+
marker: middlewareMarker
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
// there's always at least one "next" since we wrap this.resolver in a middleware
|
|
587
|
+
const result = await callRecursive();
|
|
588
|
+
if (!result) {
|
|
589
|
+
throw new TRPCError({
|
|
590
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
591
|
+
message: 'No result from middlewares - did you forget to `return next()`?'
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
if (!result.ok) {
|
|
595
|
+
// re-throw original error
|
|
596
|
+
throw result.error;
|
|
597
|
+
}
|
|
598
|
+
return result.data;
|
|
599
|
+
}
|
|
600
|
+
procedure._def = _def;
|
|
601
|
+
// FIXME typecast shouldn't be needed - fixittt
|
|
602
|
+
return procedure;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* The default check to see if we're in a server
|
|
607
|
+
*/ const isServerDefault = typeof window === 'undefined' || 'Deno' in window || // eslint-disable-next-line @typescript-eslint/dot-notation
|
|
608
|
+
globalThis.process?.env?.['NODE_ENV'] === 'test' || !!globalThis.process?.env?.['JEST_WORKER_ID'] || !!globalThis.process?.env?.['VITEST_WORKER_ID'];
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* @internal
|
|
612
|
+
*/ function getDataTransformer(transformer) {
|
|
613
|
+
if ('input' in transformer) {
|
|
614
|
+
return transformer;
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
input: transformer,
|
|
618
|
+
output: transformer
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* @internal
|
|
623
|
+
*/ const defaultTransformer = {
|
|
624
|
+
_default: true,
|
|
625
|
+
input: {
|
|
626
|
+
serialize: (obj)=>obj,
|
|
627
|
+
deserialize: (obj)=>obj
|
|
628
|
+
},
|
|
629
|
+
output: {
|
|
630
|
+
serialize: (obj)=>obj,
|
|
631
|
+
deserialize: (obj)=>obj
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
function transformTRPCResponseItem(config, item) {
|
|
635
|
+
if ('error' in item) {
|
|
636
|
+
return {
|
|
637
|
+
...item,
|
|
638
|
+
error: config.transformer.output.serialize(item.error)
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
if ('data' in item.result) {
|
|
642
|
+
return {
|
|
643
|
+
...item,
|
|
644
|
+
result: {
|
|
645
|
+
...item.result,
|
|
646
|
+
data: config.transformer.output.serialize(item.result.data)
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
return item;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Takes a unserialized `TRPCResponse` and serializes it with the router's transformers
|
|
654
|
+
**/ function transformTRPCResponse(config, itemOrItems) {
|
|
655
|
+
return Array.isArray(itemOrItems) ? itemOrItems.map((item)=>transformTRPCResponseItem(config, item)) : transformTRPCResponseItem(config, itemOrItems);
|
|
656
|
+
}
|
|
657
|
+
// FIXME:
|
|
658
|
+
// - the generics here are probably unnecessary
|
|
659
|
+
// - the RPC-spec could probably be simplified to combine HTTP + WS
|
|
660
|
+
/** @internal */ function transformResultInner(response, transformer) {
|
|
661
|
+
if ('error' in response) {
|
|
662
|
+
const error = transformer.deserialize(response.error);
|
|
663
|
+
return {
|
|
664
|
+
ok: false,
|
|
665
|
+
error: {
|
|
666
|
+
...response,
|
|
667
|
+
error
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
const result = {
|
|
672
|
+
...response.result,
|
|
673
|
+
...(!response.result.type || response.result.type === 'data') && {
|
|
674
|
+
type: 'data',
|
|
675
|
+
data: transformer.deserialize(response.result.data)
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
return {
|
|
679
|
+
ok: true,
|
|
680
|
+
result
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
class TransformResultError extends Error {
|
|
684
|
+
constructor(){
|
|
685
|
+
super('Unable to transform response from server');
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Transforms and validates that the result is a valid TRPCResponse
|
|
690
|
+
* @internal
|
|
691
|
+
*/ function transformResult(response, transformer) {
|
|
692
|
+
let result;
|
|
693
|
+
try {
|
|
694
|
+
// Use the data transformers on the JSON-response
|
|
695
|
+
result = transformResultInner(response, transformer);
|
|
696
|
+
} catch (err) {
|
|
697
|
+
throw new TransformResultError();
|
|
698
|
+
}
|
|
699
|
+
// check that output of the transformers is a valid TRPCResponse
|
|
700
|
+
if (!result.ok && (!isObject(result.error.error) || typeof result.error.error['code'] !== 'number')) {
|
|
701
|
+
throw new TransformResultError();
|
|
702
|
+
}
|
|
703
|
+
if (result.ok && !isObject(result.result)) {
|
|
704
|
+
throw new TransformResultError();
|
|
705
|
+
}
|
|
706
|
+
return result;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function isRouter(procedureOrRouter) {
|
|
710
|
+
return 'router' in procedureOrRouter._def;
|
|
711
|
+
}
|
|
712
|
+
const emptyRouter = {
|
|
713
|
+
_ctx: null,
|
|
714
|
+
_errorShape: null,
|
|
715
|
+
_meta: null,
|
|
716
|
+
queries: {},
|
|
717
|
+
mutations: {},
|
|
718
|
+
subscriptions: {},
|
|
719
|
+
errorFormatter: defaultFormatter,
|
|
720
|
+
transformer: defaultTransformer
|
|
721
|
+
};
|
|
722
|
+
/**
|
|
723
|
+
* Reserved words that can't be used as router or procedure names
|
|
724
|
+
*/ const reservedWords = [
|
|
725
|
+
/**
|
|
726
|
+
* Then is a reserved word because otherwise we can't return a promise that returns a Proxy
|
|
727
|
+
* since JS will think that `.then` is something that exists
|
|
728
|
+
*/ 'then'
|
|
729
|
+
];
|
|
730
|
+
/**
|
|
731
|
+
* @internal
|
|
732
|
+
*/ function createRouterFactory(config) {
|
|
733
|
+
return function createRouterInner(procedures) {
|
|
734
|
+
const reservedWordsUsed = new Set(Object.keys(procedures).filter((v)=>reservedWords.includes(v)));
|
|
735
|
+
if (reservedWordsUsed.size > 0) {
|
|
736
|
+
throw new Error('Reserved words used in `router({})` call: ' + Array.from(reservedWordsUsed).join(', '));
|
|
737
|
+
}
|
|
738
|
+
const routerProcedures = omitPrototype({});
|
|
739
|
+
function recursiveGetPaths(procedures, path = '') {
|
|
740
|
+
for (const [key, procedureOrRouter] of Object.entries(procedures ?? {})){
|
|
741
|
+
const newPath = `${path}${key}`;
|
|
742
|
+
if (isRouter(procedureOrRouter)) {
|
|
743
|
+
recursiveGetPaths(procedureOrRouter._def.procedures, `${newPath}.`);
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (routerProcedures[newPath]) {
|
|
747
|
+
throw new Error(`Duplicate key: ${newPath}`);
|
|
748
|
+
}
|
|
749
|
+
routerProcedures[newPath] = procedureOrRouter;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
recursiveGetPaths(procedures);
|
|
753
|
+
const _def = {
|
|
754
|
+
_config: config,
|
|
755
|
+
router: true,
|
|
756
|
+
procedures: routerProcedures,
|
|
757
|
+
...emptyRouter,
|
|
758
|
+
record: procedures
|
|
759
|
+
};
|
|
760
|
+
const router = {
|
|
761
|
+
...procedures,
|
|
762
|
+
_def,
|
|
763
|
+
createCaller (ctx) {
|
|
764
|
+
const proxy = createRecursiveProxy(({ path, args })=>{
|
|
765
|
+
const fullPath = path.join('.');
|
|
766
|
+
const procedure = _def.procedures[fullPath];
|
|
767
|
+
return procedure({
|
|
768
|
+
path: fullPath,
|
|
769
|
+
getRawInput: async ()=>args[0],
|
|
770
|
+
ctx,
|
|
771
|
+
type: procedure._def.type
|
|
772
|
+
});
|
|
773
|
+
});
|
|
774
|
+
return proxy;
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
return router;
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function isProcedure(procedureOrRouter) {
|
|
781
|
+
return !!procedureOrRouter._def.procedure;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* @internal
|
|
785
|
+
*/ function callProcedure(opts) {
|
|
786
|
+
const { type, path } = opts;
|
|
787
|
+
const proc = opts.procedures[path];
|
|
788
|
+
if (!proc || !isProcedure(proc) || proc._def.type !== type) {
|
|
789
|
+
throw new TRPCError({
|
|
790
|
+
code: 'NOT_FOUND',
|
|
791
|
+
message: `No "${type}"-procedure on path "${path}"`
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
return proc(opts);
|
|
795
|
+
}
|
|
796
|
+
function createCallerFactory() {
|
|
797
|
+
return function createCallerInner(router) {
|
|
798
|
+
const _def = router._def;
|
|
799
|
+
return function createCaller(maybeContext) {
|
|
800
|
+
const proxy = createRecursiveProxy(({ path, args })=>{
|
|
801
|
+
const fullPath = path.join('.');
|
|
802
|
+
const procedure = _def.procedures[fullPath];
|
|
803
|
+
const callProc = (ctx)=>procedure({
|
|
804
|
+
path: fullPath,
|
|
805
|
+
getRawInput: async ()=>args[0],
|
|
806
|
+
ctx,
|
|
807
|
+
type: procedure._def.type
|
|
808
|
+
});
|
|
809
|
+
if (typeof maybeContext === 'function') {
|
|
810
|
+
const context = maybeContext();
|
|
811
|
+
if (context instanceof Promise) {
|
|
812
|
+
return context.then(callProc);
|
|
813
|
+
}
|
|
814
|
+
return callProc(context);
|
|
815
|
+
}
|
|
816
|
+
return callProc(maybeContext);
|
|
817
|
+
});
|
|
818
|
+
return proxy;
|
|
819
|
+
};
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
function mergeRouters(...routerList) {
|
|
823
|
+
const record = mergeWithoutOverrides({}, ...routerList.map((r)=>r._def.record));
|
|
824
|
+
const errorFormatter = routerList.reduce((currentErrorFormatter, nextRouter)=>{
|
|
825
|
+
if (nextRouter._def._config.errorFormatter && nextRouter._def._config.errorFormatter !== defaultFormatter) {
|
|
826
|
+
if (currentErrorFormatter !== defaultFormatter && currentErrorFormatter !== nextRouter._def._config.errorFormatter) {
|
|
827
|
+
throw new Error('You seem to have several error formatters');
|
|
828
|
+
}
|
|
829
|
+
return nextRouter._def._config.errorFormatter;
|
|
830
|
+
}
|
|
831
|
+
return currentErrorFormatter;
|
|
832
|
+
}, defaultFormatter);
|
|
833
|
+
const transformer = routerList.reduce((prev, current)=>{
|
|
834
|
+
if (current._def._config.transformer && current._def._config.transformer !== defaultTransformer) {
|
|
835
|
+
if (prev !== defaultTransformer && prev !== current._def._config.transformer) {
|
|
836
|
+
throw new Error('You seem to have several transformers');
|
|
837
|
+
}
|
|
838
|
+
return current._def._config.transformer;
|
|
839
|
+
}
|
|
840
|
+
return prev;
|
|
841
|
+
}, defaultTransformer);
|
|
842
|
+
const router = createRouterFactory({
|
|
843
|
+
errorFormatter,
|
|
844
|
+
transformer,
|
|
845
|
+
isDev: routerList.some((r)=>r._def._config.isDev),
|
|
846
|
+
allowOutsideOfServer: routerList.some((r)=>r._def._config.allowOutsideOfServer),
|
|
847
|
+
isServer: routerList.some((r)=>r._def._config.isServer),
|
|
848
|
+
$types: routerList[0]?._def._config.$types
|
|
849
|
+
})(record);
|
|
850
|
+
return router;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* TODO: This can be improved:
|
|
855
|
+
* - We should be able to chain `.meta()`/`.context()` only once
|
|
856
|
+
* - Simplify typings
|
|
857
|
+
* - Doesn't need to be a class but it doesn't really hurt either
|
|
858
|
+
*/ class TRPCBuilder {
|
|
859
|
+
/**
|
|
860
|
+
* Add a context shape as a generic to the root object
|
|
861
|
+
* @link https://trpc.io/docs/v11/server/context
|
|
862
|
+
*/ context() {
|
|
863
|
+
return new TRPCBuilder();
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Add a meta shape as a generic to the root object
|
|
867
|
+
* @link https://trpc.io/docs/v11/quickstart
|
|
868
|
+
*/ meta() {
|
|
869
|
+
return new TRPCBuilder();
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Create the root object
|
|
873
|
+
* @link https://trpc.io/docs/v11/server/routers#initialize-trpc
|
|
874
|
+
*/ create(options) {
|
|
875
|
+
return createTRPCInner()(options);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Builder to initialize the tRPC root object - use this exactly once per backend
|
|
880
|
+
* @link https://trpc.io/docs/v11/quickstart
|
|
881
|
+
*/ const initTRPC = new TRPCBuilder();
|
|
882
|
+
function createTRPCInner() {
|
|
883
|
+
return function initTRPCInner(runtime) {
|
|
884
|
+
const errorFormatter = runtime?.errorFormatter ?? defaultFormatter;
|
|
885
|
+
const transformer = getDataTransformer(runtime?.transformer ?? defaultTransformer);
|
|
886
|
+
const config = {
|
|
887
|
+
transformer,
|
|
888
|
+
isDev: runtime?.isDev ?? // eslint-disable-next-line @typescript-eslint/dot-notation
|
|
889
|
+
globalThis.process?.env?.['NODE_ENV'] !== 'production',
|
|
890
|
+
allowOutsideOfServer: runtime?.allowOutsideOfServer ?? false,
|
|
891
|
+
errorFormatter,
|
|
892
|
+
isServer: runtime?.isServer ?? isServerDefault,
|
|
893
|
+
/**
|
|
894
|
+
* @internal
|
|
895
|
+
*/ $types: createFlatProxy((key)=>{
|
|
896
|
+
throw new Error(`Tried to access "$types.${key}" which is not available at runtime`);
|
|
897
|
+
})
|
|
898
|
+
};
|
|
899
|
+
{
|
|
900
|
+
// Server check
|
|
901
|
+
const isServer = runtime?.isServer ?? isServerDefault;
|
|
902
|
+
if (!isServer && runtime?.allowOutsideOfServer !== true) {
|
|
903
|
+
throw new Error(`You're trying to use @trpc/server in a non-server environment. This is not supported by default.`);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return {
|
|
907
|
+
/**
|
|
908
|
+
* These are just types, they can't be used
|
|
909
|
+
* @internal
|
|
910
|
+
*/ _config: config,
|
|
911
|
+
/**
|
|
912
|
+
* Builder object for creating procedures
|
|
913
|
+
* @link https://trpc.io/docs/v11/server/procedures
|
|
914
|
+
*/ procedure: createBuilder({
|
|
915
|
+
meta: runtime?.defaultMeta
|
|
916
|
+
}),
|
|
917
|
+
/**
|
|
918
|
+
* Create reusable middlewares
|
|
919
|
+
* @link https://trpc.io/docs/v11/server/middlewares
|
|
920
|
+
*/ middleware: createMiddlewareFactory(),
|
|
921
|
+
/**
|
|
922
|
+
* Create a router
|
|
923
|
+
* @link https://trpc.io/docs/v11/server/routers
|
|
924
|
+
*/ router: createRouterFactory(config),
|
|
925
|
+
/**
|
|
926
|
+
* Merge Routers
|
|
927
|
+
* @link https://trpc.io/docs/v11/server/merging-routers
|
|
928
|
+
*/ mergeRouters,
|
|
929
|
+
/**
|
|
930
|
+
* Create a server-side caller for a router
|
|
931
|
+
* @link https://trpc.io/docs/v11/server/server-side-calls
|
|
932
|
+
*/ createCallerFactory: createCallerFactory()
|
|
933
|
+
};
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/** @public */ function isObservable(x) {
|
|
938
|
+
return typeof x === 'object' && x !== null && 'subscribe' in x;
|
|
939
|
+
}
|
|
940
|
+
/** @public */ function observable(subscribe) {
|
|
941
|
+
const self = {
|
|
942
|
+
subscribe (observer) {
|
|
943
|
+
let teardownRef = null;
|
|
944
|
+
let isDone = false;
|
|
945
|
+
let unsubscribed = false;
|
|
946
|
+
let teardownImmediately = false;
|
|
947
|
+
function unsubscribe() {
|
|
948
|
+
if (teardownRef === null) {
|
|
949
|
+
teardownImmediately = true;
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (unsubscribed) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
unsubscribed = true;
|
|
956
|
+
if (typeof teardownRef === 'function') {
|
|
957
|
+
teardownRef();
|
|
958
|
+
} else if (teardownRef) {
|
|
959
|
+
teardownRef.unsubscribe();
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
teardownRef = subscribe({
|
|
963
|
+
next (value) {
|
|
964
|
+
if (isDone) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
observer.next?.(value);
|
|
968
|
+
},
|
|
969
|
+
error (err) {
|
|
970
|
+
if (isDone) {
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
isDone = true;
|
|
974
|
+
observer.error?.(err);
|
|
975
|
+
unsubscribe();
|
|
976
|
+
},
|
|
977
|
+
complete () {
|
|
978
|
+
if (isDone) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
isDone = true;
|
|
982
|
+
observer.complete?.();
|
|
983
|
+
unsubscribe();
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
if (teardownImmediately) {
|
|
987
|
+
unsubscribe();
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
unsubscribe
|
|
991
|
+
};
|
|
992
|
+
},
|
|
993
|
+
pipe (...operations) {
|
|
994
|
+
return pipeFromArray(operations)(self);
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
return self;
|
|
998
|
+
}
|
|
999
|
+
function pipeFromArray(fns) {
|
|
1000
|
+
if (fns.length === 0) {
|
|
1001
|
+
return identity;
|
|
1002
|
+
}
|
|
1003
|
+
if (fns.length === 1) {
|
|
1004
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1005
|
+
return fns[0];
|
|
1006
|
+
}
|
|
1007
|
+
return function piped(input) {
|
|
1008
|
+
return fns.reduce((prev, fn)=>fn(prev), input);
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
class ObservableAbortError extends Error {
|
|
1012
|
+
constructor(message){
|
|
1013
|
+
super(message);
|
|
1014
|
+
this.name = 'ObservableAbortError';
|
|
1015
|
+
Object.setPrototypeOf(this, ObservableAbortError.prototype);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
/** @internal */ function observableToPromise(observable) {
|
|
1019
|
+
let abort;
|
|
1020
|
+
const promise = new Promise((resolve, reject)=>{
|
|
1021
|
+
let isDone = false;
|
|
1022
|
+
function onDone() {
|
|
1023
|
+
if (isDone) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
isDone = true;
|
|
1027
|
+
reject(new ObservableAbortError('This operation was aborted.'));
|
|
1028
|
+
obs$.unsubscribe();
|
|
1029
|
+
}
|
|
1030
|
+
const obs$ = observable.subscribe({
|
|
1031
|
+
next (data) {
|
|
1032
|
+
isDone = true;
|
|
1033
|
+
resolve(data);
|
|
1034
|
+
onDone();
|
|
1035
|
+
},
|
|
1036
|
+
error (data) {
|
|
1037
|
+
isDone = true;
|
|
1038
|
+
reject(data);
|
|
1039
|
+
onDone();
|
|
1040
|
+
},
|
|
1041
|
+
complete () {
|
|
1042
|
+
isDone = true;
|
|
1043
|
+
onDone();
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
abort = onDone;
|
|
1047
|
+
});
|
|
1048
|
+
return {
|
|
1049
|
+
promise,
|
|
1050
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1051
|
+
abort: abort
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
function map(project) {
|
|
1056
|
+
return (originalObserver)=>{
|
|
1057
|
+
return {
|
|
1058
|
+
subscribe (observer) {
|
|
1059
|
+
let index = 0;
|
|
1060
|
+
const subscription = originalObserver.subscribe({
|
|
1061
|
+
next (value) {
|
|
1062
|
+
observer.next?.(project(value, index++));
|
|
1063
|
+
},
|
|
1064
|
+
error (error) {
|
|
1065
|
+
observer.error?.(error);
|
|
1066
|
+
},
|
|
1067
|
+
complete () {
|
|
1068
|
+
observer.complete?.();
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
return subscription;
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
function share(_opts) {
|
|
1077
|
+
return (originalObserver)=>{
|
|
1078
|
+
let refCount = 0;
|
|
1079
|
+
let subscription = null;
|
|
1080
|
+
const observers = [];
|
|
1081
|
+
function startIfNeeded() {
|
|
1082
|
+
if (subscription) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
subscription = originalObserver.subscribe({
|
|
1086
|
+
next (value) {
|
|
1087
|
+
for (const observer of observers){
|
|
1088
|
+
observer.next?.(value);
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
error (error) {
|
|
1092
|
+
for (const observer of observers){
|
|
1093
|
+
observer.error?.(error);
|
|
1094
|
+
}
|
|
1095
|
+
},
|
|
1096
|
+
complete () {
|
|
1097
|
+
for (const observer of observers){
|
|
1098
|
+
observer.complete?.();
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
function resetIfNeeded() {
|
|
1104
|
+
// "resetOnRefCountZero"
|
|
1105
|
+
if (refCount === 0 && subscription) {
|
|
1106
|
+
const _sub = subscription;
|
|
1107
|
+
subscription = null;
|
|
1108
|
+
_sub.unsubscribe();
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return {
|
|
1112
|
+
subscribe (observer) {
|
|
1113
|
+
refCount++;
|
|
1114
|
+
observers.push(observer);
|
|
1115
|
+
startIfNeeded();
|
|
1116
|
+
return {
|
|
1117
|
+
unsubscribe () {
|
|
1118
|
+
refCount--;
|
|
1119
|
+
resetIfNeeded();
|
|
1120
|
+
const index = observers.findIndex((v)=>v === observer);
|
|
1121
|
+
if (index > -1) {
|
|
1122
|
+
observers.splice(index, 1);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function tap(observer) {
|
|
1131
|
+
return (originalObserver)=>{
|
|
1132
|
+
return {
|
|
1133
|
+
subscribe (observer2) {
|
|
1134
|
+
return originalObserver.subscribe({
|
|
1135
|
+
next (v) {
|
|
1136
|
+
observer.next?.(v);
|
|
1137
|
+
observer2.next?.(v);
|
|
1138
|
+
},
|
|
1139
|
+
error (v) {
|
|
1140
|
+
observer.error?.(v);
|
|
1141
|
+
observer2.error?.(v);
|
|
1142
|
+
},
|
|
1143
|
+
complete () {
|
|
1144
|
+
observer.complete?.();
|
|
1145
|
+
observer2.complete?.();
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function getRawProcedureInputOrThrow(opts) {
|
|
1154
|
+
const { req } = opts;
|
|
1155
|
+
try {
|
|
1156
|
+
if (req.method === 'GET') {
|
|
1157
|
+
if (!req.query.has('input')) {
|
|
1158
|
+
return undefined;
|
|
1159
|
+
}
|
|
1160
|
+
const raw = req.query.get('input');
|
|
1161
|
+
return JSON.parse(raw);
|
|
1162
|
+
}
|
|
1163
|
+
if (!opts.preprocessedBody && typeof req.body === 'string') {
|
|
1164
|
+
// A mutation with no inputs will have req.body === ''
|
|
1165
|
+
return req.body.length === 0 ? undefined : JSON.parse(req.body);
|
|
1166
|
+
}
|
|
1167
|
+
return req.body;
|
|
1168
|
+
} catch (cause) {
|
|
1169
|
+
throw new TRPCError({
|
|
1170
|
+
code: 'PARSE_ERROR',
|
|
1171
|
+
cause
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
const deserializeInputValue = (rawValue, transformer)=>{
|
|
1176
|
+
return typeof rawValue !== 'undefined' ? transformer.input.deserialize(rawValue) : rawValue;
|
|
1177
|
+
};
|
|
1178
|
+
const getJsonContentTypeInputs = (opts)=>{
|
|
1179
|
+
const rawInput = getRawProcedureInputOrThrow(opts);
|
|
1180
|
+
const transformer = opts.router._def._config.transformer;
|
|
1181
|
+
if (!opts.isBatchCall) {
|
|
1182
|
+
return {
|
|
1183
|
+
0: deserializeInputValue(rawInput, transformer)
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
/* istanbul ignore if */ if (rawInput == null || typeof rawInput !== 'object' || Array.isArray(rawInput)) {
|
|
1187
|
+
throw new TRPCError({
|
|
1188
|
+
code: 'BAD_REQUEST',
|
|
1189
|
+
message: '"input" needs to be an object when doing a batch call'
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
const input = {};
|
|
1193
|
+
for(const key in rawInput){
|
|
1194
|
+
const k = key;
|
|
1195
|
+
const rawValue = rawInput[k];
|
|
1196
|
+
const value = deserializeInputValue(rawValue, transformer);
|
|
1197
|
+
input[k] = value;
|
|
1198
|
+
}
|
|
1199
|
+
return input;
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
const HTTP_METHOD_PROCEDURE_TYPE_MAP = {
|
|
1203
|
+
GET: 'query',
|
|
1204
|
+
POST: 'mutation'
|
|
1205
|
+
};
|
|
1206
|
+
const fallbackContentTypeHandler = {
|
|
1207
|
+
getInputs: getJsonContentTypeInputs
|
|
1208
|
+
};
|
|
1209
|
+
function initResponse(initOpts) {
|
|
1210
|
+
const { ctx, paths, type, responseMeta, untransformedJSON, errors = [] } = initOpts;
|
|
1211
|
+
let status = untransformedJSON ? getHTTPStatusCode(untransformedJSON) : 200;
|
|
1212
|
+
const headers = {
|
|
1213
|
+
'Content-Type': 'application/json'
|
|
1214
|
+
};
|
|
1215
|
+
const eagerGeneration = !untransformedJSON;
|
|
1216
|
+
const data = eagerGeneration ? [] : Array.isArray(untransformedJSON) ? untransformedJSON : [
|
|
1217
|
+
untransformedJSON
|
|
1218
|
+
];
|
|
1219
|
+
const meta = responseMeta?.({
|
|
1220
|
+
ctx,
|
|
1221
|
+
paths,
|
|
1222
|
+
type,
|
|
1223
|
+
data,
|
|
1224
|
+
errors,
|
|
1225
|
+
eagerGeneration
|
|
1226
|
+
}) ?? {};
|
|
1227
|
+
for (const [key, value] of Object.entries(meta.headers ?? {})){
|
|
1228
|
+
headers[key] = value;
|
|
1229
|
+
}
|
|
1230
|
+
if (meta.status) {
|
|
1231
|
+
status = meta.status;
|
|
1232
|
+
}
|
|
1233
|
+
return {
|
|
1234
|
+
status,
|
|
1235
|
+
headers
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
async function inputToProcedureCall(procedureOpts) {
|
|
1239
|
+
const { opts, ctx, type, input, path } = procedureOpts;
|
|
1240
|
+
try {
|
|
1241
|
+
const data = await callProcedure({
|
|
1242
|
+
procedures: opts.router._def.procedures,
|
|
1243
|
+
path,
|
|
1244
|
+
getRawInput: async ()=>input,
|
|
1245
|
+
ctx,
|
|
1246
|
+
type
|
|
1247
|
+
});
|
|
1248
|
+
return {
|
|
1249
|
+
result: {
|
|
1250
|
+
data
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
} catch (cause) {
|
|
1254
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
1255
|
+
opts.onError?.({
|
|
1256
|
+
error,
|
|
1257
|
+
path,
|
|
1258
|
+
input,
|
|
1259
|
+
ctx,
|
|
1260
|
+
type: type,
|
|
1261
|
+
req: opts.req
|
|
1262
|
+
});
|
|
1263
|
+
return {
|
|
1264
|
+
error: getErrorShape({
|
|
1265
|
+
config: opts.router._def._config,
|
|
1266
|
+
error,
|
|
1267
|
+
type,
|
|
1268
|
+
path,
|
|
1269
|
+
input,
|
|
1270
|
+
ctx
|
|
1271
|
+
})
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
function caughtErrorToData(cause, errorOpts) {
|
|
1276
|
+
const { router, req, onError } = errorOpts.opts;
|
|
1277
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
1278
|
+
onError?.({
|
|
1279
|
+
error,
|
|
1280
|
+
path: errorOpts.path,
|
|
1281
|
+
input: errorOpts.input,
|
|
1282
|
+
ctx: errorOpts.ctx,
|
|
1283
|
+
type: errorOpts.type,
|
|
1284
|
+
req
|
|
1285
|
+
});
|
|
1286
|
+
const untransformedJSON = {
|
|
1287
|
+
error: getErrorShape({
|
|
1288
|
+
config: router._def._config,
|
|
1289
|
+
error,
|
|
1290
|
+
type: errorOpts.type,
|
|
1291
|
+
path: errorOpts.path,
|
|
1292
|
+
input: errorOpts.input,
|
|
1293
|
+
ctx: errorOpts.ctx
|
|
1294
|
+
})
|
|
1295
|
+
};
|
|
1296
|
+
const transformedJSON = transformTRPCResponse(router._def._config, untransformedJSON);
|
|
1297
|
+
const body = JSON.stringify(transformedJSON);
|
|
1298
|
+
return {
|
|
1299
|
+
error,
|
|
1300
|
+
untransformedJSON,
|
|
1301
|
+
body
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
// implementation
|
|
1305
|
+
async function resolveHTTPResponse(opts) {
|
|
1306
|
+
const { router, req, unstable_onHead, unstable_onChunk } = opts;
|
|
1307
|
+
if (req.method === 'HEAD') {
|
|
1308
|
+
// can be used for lambda warmup
|
|
1309
|
+
const headResponse = {
|
|
1310
|
+
status: 204
|
|
1311
|
+
};
|
|
1312
|
+
unstable_onHead?.(headResponse, false);
|
|
1313
|
+
unstable_onChunk?.([
|
|
1314
|
+
-1,
|
|
1315
|
+
''
|
|
1316
|
+
]);
|
|
1317
|
+
return headResponse;
|
|
1318
|
+
}
|
|
1319
|
+
const contentTypeHandler = opts.contentTypeHandler ?? fallbackContentTypeHandler;
|
|
1320
|
+
const batchingEnabled = opts.batching?.enabled ?? true;
|
|
1321
|
+
const type = HTTP_METHOD_PROCEDURE_TYPE_MAP[req.method] ?? 'unknown';
|
|
1322
|
+
let ctx = undefined;
|
|
1323
|
+
let paths;
|
|
1324
|
+
const isBatchCall = !!req.query.get('batch');
|
|
1325
|
+
const isStreamCall = isBatchCall && unstable_onHead && unstable_onChunk && req.headers['trpc-batch-mode'] === 'stream';
|
|
1326
|
+
try {
|
|
1327
|
+
if (opts.error) {
|
|
1328
|
+
throw opts.error;
|
|
1329
|
+
}
|
|
1330
|
+
if (isBatchCall && !batchingEnabled) {
|
|
1331
|
+
throw new Error(`Batching is not enabled on the server`);
|
|
1332
|
+
}
|
|
1333
|
+
/* istanbul ignore if -- @preserve */ if (type === 'subscription') {
|
|
1334
|
+
throw new TRPCError({
|
|
1335
|
+
message: 'Subscriptions should use wsLink',
|
|
1336
|
+
code: 'METHOD_NOT_SUPPORTED'
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
if (type === 'unknown') {
|
|
1340
|
+
throw new TRPCError({
|
|
1341
|
+
message: `Unexpected request method ${req.method}`,
|
|
1342
|
+
code: 'METHOD_NOT_SUPPORTED'
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
const inputs = await contentTypeHandler.getInputs({
|
|
1346
|
+
isBatchCall,
|
|
1347
|
+
req,
|
|
1348
|
+
router,
|
|
1349
|
+
preprocessedBody: opts.preprocessedBody ?? false
|
|
1350
|
+
});
|
|
1351
|
+
paths = isBatchCall ? decodeURIComponent(opts.path).split(',') : [
|
|
1352
|
+
opts.path
|
|
1353
|
+
];
|
|
1354
|
+
const info = {
|
|
1355
|
+
isBatchCall,
|
|
1356
|
+
calls: paths.map((path, idx)=>({
|
|
1357
|
+
path,
|
|
1358
|
+
type,
|
|
1359
|
+
input: inputs[idx] ?? undefined
|
|
1360
|
+
}))
|
|
1361
|
+
};
|
|
1362
|
+
ctx = await opts.createContext({
|
|
1363
|
+
info
|
|
1364
|
+
});
|
|
1365
|
+
const promises = paths.map((path, index)=>inputToProcedureCall({
|
|
1366
|
+
opts,
|
|
1367
|
+
ctx,
|
|
1368
|
+
type,
|
|
1369
|
+
input: inputs[index],
|
|
1370
|
+
path
|
|
1371
|
+
}));
|
|
1372
|
+
if (!isStreamCall) {
|
|
1373
|
+
/**
|
|
1374
|
+
* Non-streaming response:
|
|
1375
|
+
* - await all responses in parallel, blocking on the slowest one
|
|
1376
|
+
* - create headers with known response body
|
|
1377
|
+
* - return a complete HTTPResponse
|
|
1378
|
+
*/ const untransformedJSON = await Promise.all(promises);
|
|
1379
|
+
const errors = untransformedJSON.flatMap((response)=>'error' in response ? [
|
|
1380
|
+
response.error
|
|
1381
|
+
] : []);
|
|
1382
|
+
const headResponse = initResponse({
|
|
1383
|
+
ctx,
|
|
1384
|
+
paths,
|
|
1385
|
+
type,
|
|
1386
|
+
responseMeta: opts.responseMeta,
|
|
1387
|
+
untransformedJSON,
|
|
1388
|
+
errors
|
|
1389
|
+
});
|
|
1390
|
+
unstable_onHead?.(headResponse, false);
|
|
1391
|
+
// return body stuff
|
|
1392
|
+
const result = isBatchCall ? untransformedJSON : untransformedJSON[0]; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- `untransformedJSON` should be the length of `paths` which should be at least 1 otherwise there wouldn't be a request at all
|
|
1393
|
+
const transformedJSON = transformTRPCResponse(router._def._config, result);
|
|
1394
|
+
const body = JSON.stringify(transformedJSON);
|
|
1395
|
+
unstable_onChunk?.([
|
|
1396
|
+
-1,
|
|
1397
|
+
body
|
|
1398
|
+
]);
|
|
1399
|
+
return {
|
|
1400
|
+
status: headResponse.status,
|
|
1401
|
+
headers: headResponse.headers,
|
|
1402
|
+
body
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Streaming response:
|
|
1407
|
+
* - block on none, call `onChunk` as soon as each response is ready
|
|
1408
|
+
* - create headers with minimal data (cannot know the response body in advance)
|
|
1409
|
+
* - return void
|
|
1410
|
+
*/ const headResponse = initResponse({
|
|
1411
|
+
ctx,
|
|
1412
|
+
paths,
|
|
1413
|
+
type,
|
|
1414
|
+
responseMeta: opts.responseMeta
|
|
1415
|
+
});
|
|
1416
|
+
unstable_onHead(headResponse, true);
|
|
1417
|
+
const indexedPromises = new Map(promises.map((promise, index)=>[
|
|
1418
|
+
index,
|
|
1419
|
+
promise.then((r)=>[
|
|
1420
|
+
index,
|
|
1421
|
+
r
|
|
1422
|
+
])
|
|
1423
|
+
]));
|
|
1424
|
+
for (const _ of paths){
|
|
1425
|
+
const [index, untransformedJSON] = await Promise.race(indexedPromises.values());
|
|
1426
|
+
indexedPromises.delete(index);
|
|
1427
|
+
try {
|
|
1428
|
+
const transformedJSON = transformTRPCResponse(router._def._config, untransformedJSON);
|
|
1429
|
+
const body = JSON.stringify(transformedJSON);
|
|
1430
|
+
unstable_onChunk([
|
|
1431
|
+
index,
|
|
1432
|
+
body
|
|
1433
|
+
]);
|
|
1434
|
+
} catch (cause) {
|
|
1435
|
+
const path = paths[index];
|
|
1436
|
+
const input = inputs[index];
|
|
1437
|
+
const { body } = caughtErrorToData(cause, {
|
|
1438
|
+
opts,
|
|
1439
|
+
ctx,
|
|
1440
|
+
type,
|
|
1441
|
+
path,
|
|
1442
|
+
input
|
|
1443
|
+
});
|
|
1444
|
+
unstable_onChunk([
|
|
1445
|
+
index,
|
|
1446
|
+
body
|
|
1447
|
+
]);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return;
|
|
1451
|
+
} catch (cause) {
|
|
1452
|
+
// we get here if
|
|
1453
|
+
// - batching is called when it's not enabled
|
|
1454
|
+
// - `createContext()` throws
|
|
1455
|
+
// - `router._def._config.transformer.output.serialize()` throws
|
|
1456
|
+
// - post body is too large
|
|
1457
|
+
// - input deserialization fails
|
|
1458
|
+
// - `errorFormatter` return value is malformed
|
|
1459
|
+
const { error, untransformedJSON, body } = caughtErrorToData(cause, {
|
|
1460
|
+
opts,
|
|
1461
|
+
ctx,
|
|
1462
|
+
type
|
|
1463
|
+
});
|
|
1464
|
+
const headResponse = initResponse({
|
|
1465
|
+
ctx,
|
|
1466
|
+
paths,
|
|
1467
|
+
type,
|
|
1468
|
+
responseMeta: opts.responseMeta,
|
|
1469
|
+
untransformedJSON,
|
|
1470
|
+
errors: [
|
|
1471
|
+
error
|
|
1472
|
+
]
|
|
1473
|
+
});
|
|
1474
|
+
unstable_onHead?.(headResponse, false);
|
|
1475
|
+
unstable_onChunk?.([
|
|
1476
|
+
-1,
|
|
1477
|
+
body
|
|
1478
|
+
]);
|
|
1479
|
+
return {
|
|
1480
|
+
status: headResponse.status,
|
|
1481
|
+
headers: headResponse.headers,
|
|
1482
|
+
body
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Format a batch response as a line-delimited JSON stream
|
|
1489
|
+
* that the `unstable_httpBatchStreamLink` can parse:
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* ```ts
|
|
1493
|
+
* const formatter = getBatchStreamFormatter();
|
|
1494
|
+
* res.send(formatter(1, 'response #2'));
|
|
1495
|
+
* res.send(formatter(0, 'response #1'));
|
|
1496
|
+
* res.send(formatter.end());
|
|
1497
|
+
* ```
|
|
1498
|
+
*
|
|
1499
|
+
* Expected format:
|
|
1500
|
+
* ```json
|
|
1501
|
+
* {"1":"response #2"
|
|
1502
|
+
* ,"0":"response #1"
|
|
1503
|
+
* }
|
|
1504
|
+
* ```
|
|
1505
|
+
*/ function getBatchStreamFormatter() {
|
|
1506
|
+
let first = true;
|
|
1507
|
+
function format(index, string) {
|
|
1508
|
+
const prefix = first ? '{' : ',';
|
|
1509
|
+
first = false;
|
|
1510
|
+
return `${prefix}"${index}":${string}\n`;
|
|
1511
|
+
}
|
|
1512
|
+
format.end = ()=>'}';
|
|
1513
|
+
return format;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
exports.TRPCError = TRPCError;
|
|
1517
|
+
exports.TRPC_ERROR_CODES_BY_KEY = TRPC_ERROR_CODES_BY_KEY;
|
|
1518
|
+
exports.TRPC_ERROR_CODES_BY_NUMBER = TRPC_ERROR_CODES_BY_NUMBER;
|
|
1519
|
+
exports.callProcedure = callProcedure;
|
|
1520
|
+
exports.createBuilder = createBuilder;
|
|
1521
|
+
exports.createFlatProxy = createFlatProxy;
|
|
1522
|
+
exports.createInputMiddleware = createInputMiddleware;
|
|
1523
|
+
exports.createOutputMiddleware = createOutputMiddleware;
|
|
1524
|
+
exports.createRecursiveProxy = createRecursiveProxy;
|
|
1525
|
+
exports.createRouterFactory = createRouterFactory;
|
|
1526
|
+
exports.experimental_standaloneMiddleware = experimental_standaloneMiddleware;
|
|
1527
|
+
exports.getBatchStreamFormatter = getBatchStreamFormatter;
|
|
1528
|
+
exports.getCauseFromUnknown = getCauseFromUnknown;
|
|
1529
|
+
exports.getErrorShape = getErrorShape;
|
|
1530
|
+
exports.getHTTPStatusCode = getHTTPStatusCode;
|
|
1531
|
+
exports.getHTTPStatusCodeFromError = getHTTPStatusCodeFromError;
|
|
1532
|
+
exports.getJsonContentTypeInputs = getJsonContentTypeInputs;
|
|
1533
|
+
exports.getTRPCErrorFromUnknown = getTRPCErrorFromUnknown;
|
|
1534
|
+
exports.initTRPC = initTRPC;
|
|
1535
|
+
exports.isObject = isObject;
|
|
1536
|
+
exports.isObservable = isObservable;
|
|
1537
|
+
exports.map = map;
|
|
1538
|
+
exports.mergeRouters = mergeRouters;
|
|
1539
|
+
exports.middlewareMarker = middlewareMarker;
|
|
1540
|
+
exports.observable = observable;
|
|
1541
|
+
exports.observableToPromise = observableToPromise;
|
|
1542
|
+
exports.parseTRPCMessage = parseTRPCMessage;
|
|
1543
|
+
exports.procedureTypes = procedureTypes;
|
|
1544
|
+
exports.resolveHTTPResponse = resolveHTTPResponse;
|
|
1545
|
+
exports.share = share;
|
|
1546
|
+
exports.tap = tap;
|
|
1547
|
+
exports.transformResult = transformResult;
|
|
1548
|
+
exports.transformTRPCResponse = transformTRPCResponse;
|
|
1549
|
+
exports.unsetMarker = unsetMarker;
|