@orpc/client 0.41.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/chunk-4FUUNP74.js +212 -0
- package/dist/{chunk-2UPNYYFF.js → chunk-OGAGXWCU.js} +1 -8
- package/dist/fetch.js +4 -4
- package/dist/index.js +1 -1
- package/dist/openapi.js +147 -245
- package/dist/rpc.js +6 -6
- package/dist/src/openapi/bracket-notation.d.ts +8 -83
- package/dist/src/openapi/index.d.ts +1 -1
- package/dist/src/openapi/json-serializer.d.ts +4 -2
- package/dist/src/openapi/serializer.d.ts +6 -6
- package/dist/src/rpc/index.d.ts +1 -0
- package/dist/src/rpc/json-serializer.d.ts +12 -0
- package/dist/src/rpc/serializer.d.ts +6 -19
- package/package.json +2 -2
- package/dist/chunk-TPEMQB7D.js +0 -178
package/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<image align="center" src="https://orpc.unnoq.com/logo.webp" width=280 />
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<h1></h1>
|
6
|
+
|
7
|
+
<div align="center">
|
8
|
+
<a href="https://codecov.io/gh/unnoq/orpc">
|
9
|
+
<img alt="codecov" src="https://codecov.io/gh/unnoq/orpc/branch/main/graph/badge.svg">
|
10
|
+
</a>
|
11
|
+
<a href="https://www.npmjs.com/package/@orpc/client">
|
12
|
+
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fclient?logo=npm" />
|
13
|
+
</a>
|
14
|
+
<a href="https://github.com/unnoq/orpc/blob/main/LICENSE">
|
15
|
+
<img alt="MIT License" src="https://img.shields.io/github/license/unnoq/orpc?logo=open-source-initiative" />
|
16
|
+
</a>
|
17
|
+
<a href="https://discord.gg/TXEbwRBvQn">
|
18
|
+
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
|
19
|
+
</a>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<h3 align="center">Typesafe APIs Made Simple 🪄</h3>
|
23
|
+
|
24
|
+
**oRPC is a powerful combination of RPC and OpenAPI**, makes it easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards, ensuring a smooth and enjoyable developer experience.
|
25
|
+
|
26
|
+
---
|
27
|
+
|
28
|
+
## Highlights
|
29
|
+
|
30
|
+
- **End-to-End Type Safety 🔒**: Ensure complete type safety from inputs to outputs and errors, bridging server and client seamlessly.
|
31
|
+
- **First-Class OpenAPI 📄**: Adheres to the OpenAPI standard out of the box, ensuring seamless integration and comprehensive API documentation.
|
32
|
+
- **Contract-First Development 📜**: (Optional) Define your API contract upfront and implement it with confidence.
|
33
|
+
- **Exceptional Developer Experience ✨**: Enjoy a streamlined workflow with robust typing and clear, in-code documentation.
|
34
|
+
- **Multi-Runtime Support 🌍**: Run your code seamlessly on Cloudflare, Deno, Bun, Node.js, and more.
|
35
|
+
- **Framework Integrations 🧩**: Supports Tanstack Query (React, Vue), Pinia Colada, and more.
|
36
|
+
- **Server Actions ⚡️**: Fully compatible with React Server Actions on Next.js, TanStack Start, and more.
|
37
|
+
- **Standard Schema Support 🗂️**: Effortlessly work with Zod, Valibot, ArkType, and others right out of the box.
|
38
|
+
- **Fast & Lightweight 💨**: Built on native APIs across all runtimes – optimized for speed and efficiency.
|
39
|
+
- **Native Types 📦**: Enjoy built-in support for Date, File, Blob, BigInt, URL and more with no extra setup.
|
40
|
+
- **Lazy Router ⏱️**: Improve cold start times with our lazy routing feature.
|
41
|
+
- **SSE & Streaming 📡**: Provides SSE and streaming features – perfect for real-time notifications and AI-powered streaming responses.
|
42
|
+
- **Reusability 🔄**: Write once and reuse your code across multiple purposes effortlessly.
|
43
|
+
- **Extendability 🔌**: Easily enhance oRPC with plugins, middleware, and interceptors.
|
44
|
+
- **Reliability 🛡️**: Well-tested, fully TypeScript, production-ready, and MIT licensed for peace of mind.
|
45
|
+
- **Simplicity 💡**: Enjoy straightforward, clean code with no hidden magic.
|
46
|
+
|
47
|
+
## Documentation
|
48
|
+
|
49
|
+
You can find the full documentation [here](https://orpc.unnoq.com).
|
50
|
+
|
51
|
+
## Packages
|
52
|
+
|
53
|
+
- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
|
54
|
+
- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
|
55
|
+
- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
|
56
|
+
- [@orpc/react-query](https://www.npmjs.com/package/@orpc/react-query): Integration with [React Query](https://tanstack.com/query/latest/docs/framework/react/overview).
|
57
|
+
- [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview).
|
58
|
+
- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
|
59
|
+
- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
|
60
|
+
- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
|
61
|
+
|
62
|
+
## `@orpc/client`
|
63
|
+
|
64
|
+
Consume your API on the client with type-safety. Read the [documentation](https://orpc.unnoq.com/docs/client/client-side) for more information.
|
65
|
+
|
66
|
+
```ts
|
67
|
+
import { createORPCClient } from '@orpc/client'
|
68
|
+
import { RPCLink } from '@orpc/client/fetch'
|
69
|
+
import { ContractRouterClient } from '@orpc/contract'
|
70
|
+
import { RouterClient } from '@orpc/server'
|
71
|
+
|
72
|
+
const link = new RPCLink({
|
73
|
+
url: 'http://localhost:3000/rpc',
|
74
|
+
headers: () => ({
|
75
|
+
authorization: 'Bearer token',
|
76
|
+
}),
|
77
|
+
// fetch: <-- provide fetch polyfill fetch if needed
|
78
|
+
})
|
79
|
+
|
80
|
+
// Create a client for your router
|
81
|
+
const client: RouterClient<typeof router> = createORPCClient(link)
|
82
|
+
// Or, create a client using a contract
|
83
|
+
const client: ContractRouterClient<typeof contract> = createORPCClient(link)
|
84
|
+
```
|
85
|
+
|
86
|
+
## License
|
87
|
+
|
88
|
+
Distributed under the MIT License. See [LICENSE](https://github.com/unnoq/orpc/blob/main/LICENSE) for more information.
|
@@ -0,0 +1,212 @@
|
|
1
|
+
import {
|
2
|
+
ORPCError,
|
3
|
+
mapEventIterator,
|
4
|
+
toORPCError
|
5
|
+
} from "./chunk-OGAGXWCU.js";
|
6
|
+
|
7
|
+
// src/rpc/json-serializer.ts
|
8
|
+
import { isObject } from "@orpc/shared";
|
9
|
+
var RPCJsonSerializer = class {
|
10
|
+
serialize(data, segments = [], meta = [], maps = [], blobs = []) {
|
11
|
+
if (data instanceof Blob) {
|
12
|
+
maps.push(segments);
|
13
|
+
blobs.push(data);
|
14
|
+
return [data, meta, maps, blobs];
|
15
|
+
}
|
16
|
+
if (typeof data === "bigint") {
|
17
|
+
meta.push([0, segments]);
|
18
|
+
return [data.toString(), meta, maps, blobs];
|
19
|
+
}
|
20
|
+
if (data instanceof Date) {
|
21
|
+
meta.push([1, segments]);
|
22
|
+
if (Number.isNaN(data.getTime())) {
|
23
|
+
return [null, meta, maps, blobs];
|
24
|
+
}
|
25
|
+
return [data.toISOString(), meta, maps, blobs];
|
26
|
+
}
|
27
|
+
if (Number.isNaN(data)) {
|
28
|
+
meta.push([2, segments]);
|
29
|
+
return [null, meta, maps, blobs];
|
30
|
+
}
|
31
|
+
if (data instanceof URL) {
|
32
|
+
meta.push([4, segments]);
|
33
|
+
return [data.toString(), meta, maps, blobs];
|
34
|
+
}
|
35
|
+
if (data instanceof RegExp) {
|
36
|
+
meta.push([5, segments]);
|
37
|
+
return [data.toString(), meta, maps, blobs];
|
38
|
+
}
|
39
|
+
if (data instanceof Set) {
|
40
|
+
const result = this.serialize(Array.from(data), segments, meta, maps, blobs);
|
41
|
+
meta.push([6, segments]);
|
42
|
+
return result;
|
43
|
+
}
|
44
|
+
if (data instanceof Map) {
|
45
|
+
const result = this.serialize(Array.from(data.entries()), segments, meta, maps, blobs);
|
46
|
+
meta.push([7, segments]);
|
47
|
+
return result;
|
48
|
+
}
|
49
|
+
if (Array.isArray(data)) {
|
50
|
+
const json = data.map((v, i) => {
|
51
|
+
if (v === void 0) {
|
52
|
+
meta.push([3, [...segments, i]]);
|
53
|
+
return v;
|
54
|
+
}
|
55
|
+
return this.serialize(v, [...segments, i], meta, maps, blobs)[0];
|
56
|
+
});
|
57
|
+
return [json, meta, maps, blobs];
|
58
|
+
}
|
59
|
+
if (isObject(data)) {
|
60
|
+
const json = {};
|
61
|
+
for (const k in data) {
|
62
|
+
json[k] = this.serialize(data[k], [...segments, k], meta, maps, blobs)[0];
|
63
|
+
}
|
64
|
+
return [json, meta, maps, blobs];
|
65
|
+
}
|
66
|
+
return [data, meta, maps, blobs];
|
67
|
+
}
|
68
|
+
deserialize(json, meta, maps, getBlob) {
|
69
|
+
const ref = { data: json };
|
70
|
+
if (maps && getBlob) {
|
71
|
+
maps.forEach((segments, i) => {
|
72
|
+
let currentRef = ref;
|
73
|
+
let preSegment = "data";
|
74
|
+
segments.forEach((segment) => {
|
75
|
+
currentRef = currentRef[preSegment];
|
76
|
+
preSegment = segment;
|
77
|
+
});
|
78
|
+
currentRef[preSegment] = getBlob(i);
|
79
|
+
});
|
80
|
+
}
|
81
|
+
for (const [type, segments] of meta) {
|
82
|
+
let currentRef = ref;
|
83
|
+
let preSegment = "data";
|
84
|
+
segments.forEach((segment) => {
|
85
|
+
currentRef = currentRef[preSegment];
|
86
|
+
preSegment = segment;
|
87
|
+
});
|
88
|
+
switch (type) {
|
89
|
+
case 0:
|
90
|
+
currentRef[preSegment] = BigInt(currentRef[preSegment]);
|
91
|
+
break;
|
92
|
+
case 1:
|
93
|
+
currentRef[preSegment] = new Date(currentRef[preSegment] ?? "Invalid Date");
|
94
|
+
break;
|
95
|
+
case 2:
|
96
|
+
currentRef[preSegment] = Number.NaN;
|
97
|
+
break;
|
98
|
+
case 3:
|
99
|
+
currentRef[preSegment] = void 0;
|
100
|
+
break;
|
101
|
+
case 4:
|
102
|
+
currentRef[preSegment] = new URL(currentRef[preSegment]);
|
103
|
+
break;
|
104
|
+
case 5: {
|
105
|
+
const [, pattern, flags] = currentRef[preSegment].match(/^\/(.*)\/([a-z]*)$/);
|
106
|
+
currentRef[preSegment] = new RegExp(pattern, flags);
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
case 6:
|
110
|
+
currentRef[preSegment] = new Set(currentRef[preSegment]);
|
111
|
+
break;
|
112
|
+
case 7:
|
113
|
+
currentRef[preSegment] = new Map(currentRef[preSegment]);
|
114
|
+
break;
|
115
|
+
/* v8 ignore next 3 */
|
116
|
+
default: {
|
117
|
+
const _expected = type;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
return ref.data;
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
// src/rpc/serializer.ts
|
126
|
+
import { ErrorEvent, isAsyncIteratorObject } from "@orpc/server-standard";
|
127
|
+
var RPCSerializer = class {
|
128
|
+
constructor(jsonSerializer = new RPCJsonSerializer()) {
|
129
|
+
this.jsonSerializer = jsonSerializer;
|
130
|
+
}
|
131
|
+
serialize(data) {
|
132
|
+
if (isAsyncIteratorObject(data)) {
|
133
|
+
return mapEventIterator(data, {
|
134
|
+
value: async (value) => this.#serialize(value, false),
|
135
|
+
error: async (e) => {
|
136
|
+
if (e instanceof ErrorEvent) {
|
137
|
+
return new ErrorEvent({
|
138
|
+
data: this.#serialize(e.data, false),
|
139
|
+
cause: e
|
140
|
+
});
|
141
|
+
}
|
142
|
+
return new ErrorEvent({
|
143
|
+
data: this.#serialize(toORPCError(e).toJSON(), false),
|
144
|
+
cause: e
|
145
|
+
});
|
146
|
+
}
|
147
|
+
});
|
148
|
+
}
|
149
|
+
return this.#serialize(data, true);
|
150
|
+
}
|
151
|
+
#serialize(data, enableFormData) {
|
152
|
+
if (data === void 0 || data instanceof Blob) {
|
153
|
+
return data;
|
154
|
+
}
|
155
|
+
const [json, meta_, maps, blobs] = this.jsonSerializer.serialize(data);
|
156
|
+
const meta = meta_.length === 0 ? void 0 : meta_;
|
157
|
+
if (!enableFormData || blobs.length === 0) {
|
158
|
+
return {
|
159
|
+
json,
|
160
|
+
meta
|
161
|
+
};
|
162
|
+
}
|
163
|
+
const form = new FormData();
|
164
|
+
form.set("data", JSON.stringify({ json, meta, maps }));
|
165
|
+
blobs.forEach((blob, i) => {
|
166
|
+
form.set(i.toString(), blob);
|
167
|
+
});
|
168
|
+
return form;
|
169
|
+
}
|
170
|
+
deserialize(data) {
|
171
|
+
if (isAsyncIteratorObject(data)) {
|
172
|
+
return mapEventIterator(data, {
|
173
|
+
value: async (value) => this.#deserialize(value),
|
174
|
+
error: async (e) => {
|
175
|
+
if (!(e instanceof ErrorEvent)) {
|
176
|
+
return e;
|
177
|
+
}
|
178
|
+
const deserialized = this.#deserialize(e.data);
|
179
|
+
if (ORPCError.isValidJSON(deserialized)) {
|
180
|
+
return ORPCError.fromJSON(deserialized, { cause: e });
|
181
|
+
}
|
182
|
+
return new ErrorEvent({
|
183
|
+
data: deserialized,
|
184
|
+
cause: e
|
185
|
+
});
|
186
|
+
}
|
187
|
+
});
|
188
|
+
}
|
189
|
+
return this.#deserialize(data);
|
190
|
+
}
|
191
|
+
#deserialize(data) {
|
192
|
+
if (data === void 0 || data instanceof Blob) {
|
193
|
+
return data;
|
194
|
+
}
|
195
|
+
if (!(data instanceof FormData)) {
|
196
|
+
return this.jsonSerializer.deserialize(data.json, data.meta ?? []);
|
197
|
+
}
|
198
|
+
const serialized = JSON.parse(data.get("data"));
|
199
|
+
return this.jsonSerializer.deserialize(
|
200
|
+
serialized.json,
|
201
|
+
serialized.meta ?? [],
|
202
|
+
serialized.maps,
|
203
|
+
(i) => data.get(i.toString())
|
204
|
+
);
|
205
|
+
}
|
206
|
+
};
|
207
|
+
|
208
|
+
export {
|
209
|
+
RPCJsonSerializer,
|
210
|
+
RPCSerializer
|
211
|
+
};
|
212
|
+
//# sourceMappingURL=chunk-4FUUNP74.js.map
|
@@ -1,9 +1,3 @@
|
|
1
|
-
var __defProp = Object.defineProperty;
|
2
|
-
var __export = (target, all) => {
|
3
|
-
for (var name in all)
|
4
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
5
|
-
};
|
6
|
-
|
7
1
|
// src/error.ts
|
8
2
|
import { isObject } from "@orpc/shared";
|
9
3
|
var COMMON_ORPC_ERROR_DEFS = {
|
@@ -272,7 +266,6 @@ function createAutoRetryEventIterator(initial, reconnect, initialLastEventId) {
|
|
272
266
|
}
|
273
267
|
|
274
268
|
export {
|
275
|
-
__export,
|
276
269
|
COMMON_ORPC_ERROR_DEFS,
|
277
270
|
fallbackORPCErrorStatus,
|
278
271
|
fallbackORPCErrorMessage,
|
@@ -285,4 +278,4 @@ export {
|
|
285
278
|
mapEventIterator,
|
286
279
|
createAutoRetryEventIterator
|
287
280
|
};
|
288
|
-
//# sourceMappingURL=chunk-
|
281
|
+
//# sourceMappingURL=chunk-OGAGXWCU.js.map
|
package/dist/fetch.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
import {
|
2
2
|
RPCSerializer
|
3
|
-
} from "./chunk-
|
3
|
+
} from "./chunk-4FUUNP74.js";
|
4
4
|
import {
|
5
5
|
ORPCError,
|
6
6
|
createAutoRetryEventIterator
|
7
|
-
} from "./chunk-
|
7
|
+
} from "./chunk-OGAGXWCU.js";
|
8
8
|
|
9
9
|
// src/adapters/fetch/rpc-link.ts
|
10
10
|
import { isAsyncIteratorObject } from "@orpc/server-standard";
|
@@ -101,9 +101,9 @@ var RPCLink = class {
|
|
101
101
|
const headers = new Headers(await value(this.headers, options, path, input));
|
102
102
|
const url = new URL(`${trim(this.url, "/")}/${path.map(encodeURIComponent).join("/")}`);
|
103
103
|
const serialized = this.rpcSerializer.serialize(input);
|
104
|
-
if (expectedMethod === "GET" && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
|
104
|
+
if (expectedMethod === "GET" && !(serialized instanceof FormData) && !(serialized instanceof Blob) && !isAsyncIteratorObject(serialized)) {
|
105
105
|
const getUrl = new URL(url);
|
106
|
-
getUrl.searchParams.append("data", JSON.stringify(serialized));
|
106
|
+
getUrl.searchParams.append("data", JSON.stringify(serialized) ?? "");
|
107
107
|
if (getUrl.toString().length <= this.maxUrlLength) {
|
108
108
|
return {
|
109
109
|
body: void 0,
|
package/dist/index.js
CHANGED
package/dist/openapi.js
CHANGED
@@ -1,314 +1,216 @@
|
|
1
1
|
import {
|
2
2
|
ORPCError,
|
3
|
-
__export,
|
4
3
|
mapEventIterator,
|
5
4
|
toORPCError
|
6
|
-
} from "./chunk-
|
5
|
+
} from "./chunk-OGAGXWCU.js";
|
7
6
|
|
8
7
|
// src/openapi/bracket-notation.ts
|
9
|
-
var bracket_notation_exports = {};
|
10
|
-
__export(bracket_notation_exports, {
|
11
|
-
deserialize: () => deserialize,
|
12
|
-
escapeSegment: () => escapeSegment,
|
13
|
-
parsePath: () => parsePath,
|
14
|
-
serialize: () => serialize,
|
15
|
-
stringifyPath: () => stringifyPath
|
16
|
-
});
|
17
8
|
import { isObject } from "@orpc/shared";
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if (Array.isArray(value)) {
|
24
|
-
value.forEach((item, index) => {
|
25
|
-
helper(item, [...path, String(index)]);
|
9
|
+
var BracketNotationSerializer = class {
|
10
|
+
serialize(data, segments = [], result = []) {
|
11
|
+
if (Array.isArray(data)) {
|
12
|
+
data.forEach((item, i) => {
|
13
|
+
this.serialize(item, [...segments, i], result);
|
26
14
|
});
|
27
|
-
} else if (isObject(
|
28
|
-
for (const
|
29
|
-
|
15
|
+
} else if (isObject(data)) {
|
16
|
+
for (const key in data) {
|
17
|
+
this.serialize(data[key], [...segments, key], result);
|
30
18
|
}
|
31
19
|
} else {
|
32
|
-
result.push([stringifyPath(
|
20
|
+
result.push([this.stringifyPath(segments), data]);
|
33
21
|
}
|
22
|
+
return result;
|
34
23
|
}
|
35
|
-
|
36
|
-
|
37
|
-
}
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
for (const [path, _] of entities) {
|
46
|
-
const segments = parsePath(path);
|
47
|
-
const base = segments.slice(0, -1).join(".");
|
48
|
-
const last = segments[segments.length - 1];
|
49
|
-
if (last === "") {
|
50
|
-
arrayPushPaths.add(base);
|
51
|
-
} else {
|
52
|
-
arrayPushPaths.delete(base);
|
53
|
-
}
|
54
|
-
}
|
55
|
-
function setValue(obj, segments, value, fullPath) {
|
56
|
-
const [first, ...rest_] = segments;
|
57
|
-
if (Array.isArray(obj) && first === "") {
|
58
|
-
;
|
59
|
-
obj.push(value);
|
60
|
-
return;
|
61
|
-
}
|
62
|
-
const objAsRecord = obj;
|
63
|
-
if (rest_.length === 0) {
|
64
|
-
objAsRecord[first] = value;
|
65
|
-
return;
|
66
|
-
}
|
67
|
-
const rest = rest_;
|
68
|
-
if (rest[0] === "") {
|
69
|
-
const pathToCheck = segments.slice(0, -1).join(".");
|
70
|
-
if (rest.length === 1 && arrayPushPaths.has(pathToCheck)) {
|
71
|
-
if (!(first in objAsRecord)) {
|
72
|
-
objAsRecord[first] = [];
|
73
|
-
}
|
74
|
-
if (Array.isArray(objAsRecord[first])) {
|
75
|
-
;
|
76
|
-
objAsRecord[first].push(value);
|
77
|
-
return;
|
24
|
+
deserialize(serialized) {
|
25
|
+
const arrayPushStyles = /* @__PURE__ */ new WeakSet();
|
26
|
+
const ref = { value: [] };
|
27
|
+
for (const [path, value] of serialized) {
|
28
|
+
const segments = this.parsePath(path);
|
29
|
+
let currentRef = ref;
|
30
|
+
let nextSegment = "value";
|
31
|
+
segments.forEach((segment, i) => {
|
32
|
+
if (!Array.isArray(currentRef[nextSegment]) && !isObject(currentRef[nextSegment])) {
|
33
|
+
currentRef[nextSegment] = [];
|
78
34
|
}
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
83
|
-
const target = objAsRecord[first];
|
84
|
-
target[""] = value;
|
85
|
-
return;
|
86
|
-
}
|
87
|
-
if (!(first in objAsRecord)) {
|
88
|
-
objAsRecord[first] = {};
|
89
|
-
}
|
90
|
-
setValue(
|
91
|
-
objAsRecord[first],
|
92
|
-
rest,
|
93
|
-
value,
|
94
|
-
fullPath
|
95
|
-
);
|
96
|
-
}
|
97
|
-
for (const [path, value] of entities) {
|
98
|
-
const segments = parsePath(path);
|
99
|
-
setValue(result, segments, value, path);
|
100
|
-
}
|
101
|
-
return result;
|
102
|
-
}
|
103
|
-
function escapeSegment(segment) {
|
104
|
-
return segment.replace(/[\\[\]]/g, (match) => {
|
105
|
-
switch (match) {
|
106
|
-
case "\\":
|
107
|
-
return "\\\\";
|
108
|
-
case "[":
|
109
|
-
return "\\[";
|
110
|
-
case "]":
|
111
|
-
return "\\]";
|
112
|
-
default:
|
113
|
-
return match;
|
114
|
-
}
|
115
|
-
});
|
116
|
-
}
|
117
|
-
function stringifyPath(path) {
|
118
|
-
const [first, ...rest] = path;
|
119
|
-
const firstSegment = escapeSegment(first);
|
120
|
-
const base = first === "" ? "" : firstSegment;
|
121
|
-
return rest.reduce(
|
122
|
-
(result, segment) => `${result}[${escapeSegment(segment)}]`,
|
123
|
-
base
|
124
|
-
);
|
125
|
-
}
|
126
|
-
function parsePath(path) {
|
127
|
-
if (path === "")
|
128
|
-
return [""];
|
129
|
-
const result = [];
|
130
|
-
let currentSegment = "";
|
131
|
-
let inBracket = false;
|
132
|
-
let bracketContent = "";
|
133
|
-
let backslashCount = 0;
|
134
|
-
for (let i = 0; i < path.length; i++) {
|
135
|
-
const char = path[i];
|
136
|
-
if (char === "\\") {
|
137
|
-
backslashCount++;
|
138
|
-
continue;
|
139
|
-
}
|
140
|
-
if (backslashCount > 0) {
|
141
|
-
const literalBackslashes = "\\".repeat(Math.floor(backslashCount / 2));
|
142
|
-
if (char === "[" || char === "]") {
|
143
|
-
if (backslashCount % 2 === 1) {
|
144
|
-
if (inBracket) {
|
145
|
-
bracketContent += literalBackslashes + char;
|
146
|
-
} else {
|
147
|
-
currentSegment += literalBackslashes + char;
|
35
|
+
if (i !== segments.length - 1) {
|
36
|
+
if (Array.isArray(currentRef[nextSegment]) && !isValidArrayIndex(segment)) {
|
37
|
+
currentRef[nextSegment] = { ...currentRef[nextSegment] };
|
148
38
|
}
|
149
39
|
} else {
|
150
|
-
if (
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
if (char === "[" && !inBracket) {
|
156
|
-
if (currentSegment !== "" || result.length === 0) {
|
157
|
-
result.push(currentSegment);
|
158
|
-
}
|
159
|
-
inBracket = true;
|
160
|
-
bracketContent = "";
|
161
|
-
currentSegment = "";
|
162
|
-
} else if (char === "]" && inBracket) {
|
163
|
-
result.push(bracketContent);
|
164
|
-
inBracket = false;
|
165
|
-
bracketContent = "";
|
166
|
-
} else {
|
167
|
-
if (inBracket) {
|
168
|
-
bracketContent += char;
|
40
|
+
if (Array.isArray(currentRef[nextSegment])) {
|
41
|
+
if (segment === "") {
|
42
|
+
if (currentRef[nextSegment].length && !arrayPushStyles.has(currentRef[nextSegment])) {
|
43
|
+
currentRef[nextSegment] = { ...currentRef[nextSegment] };
|
44
|
+
}
|
169
45
|
} else {
|
170
|
-
|
46
|
+
if (arrayPushStyles.has(currentRef[nextSegment])) {
|
47
|
+
currentRef[nextSegment] = { "": currentRef[nextSegment].at(-1) };
|
48
|
+
} else if (!isValidArrayIndex(segment)) {
|
49
|
+
currentRef[nextSegment] = { ...currentRef[nextSegment] };
|
50
|
+
}
|
171
51
|
}
|
172
52
|
}
|
173
53
|
}
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
54
|
+
currentRef = currentRef[nextSegment];
|
55
|
+
nextSegment = segment;
|
56
|
+
});
|
57
|
+
if (Array.isArray(currentRef)) {
|
58
|
+
if (nextSegment === "") {
|
59
|
+
arrayPushStyles.add(currentRef);
|
60
|
+
currentRef.push(value);
|
178
61
|
} else {
|
179
|
-
|
62
|
+
currentRef[Number(nextSegment)] = value;
|
180
63
|
}
|
64
|
+
} else {
|
65
|
+
currentRef[nextSegment] = value;
|
181
66
|
}
|
182
|
-
backslashCount = 0;
|
183
|
-
continue;
|
184
67
|
}
|
185
|
-
|
186
|
-
|
187
|
-
|
68
|
+
return ref.value;
|
69
|
+
}
|
70
|
+
stringifyPath(segments) {
|
71
|
+
return segments.map((segment) => {
|
72
|
+
return segment.toString().replace(/[\\[\]]/g, (match) => {
|
73
|
+
switch (match) {
|
74
|
+
case "\\":
|
75
|
+
return "\\\\";
|
76
|
+
case "[":
|
77
|
+
return "\\[";
|
78
|
+
case "]":
|
79
|
+
return "\\]";
|
80
|
+
/* v8 ignore next 2 */
|
81
|
+
default:
|
82
|
+
return match;
|
83
|
+
}
|
84
|
+
});
|
85
|
+
}).reduce((result, segment, i) => {
|
86
|
+
if (i === 0) {
|
87
|
+
return segment;
|
188
88
|
}
|
189
|
-
|
190
|
-
|
191
|
-
currentSegment = "";
|
192
|
-
continue;
|
193
|
-
}
|
194
|
-
if (char === "]" && inBracket) {
|
195
|
-
result.push(bracketContent);
|
196
|
-
inBracket = false;
|
197
|
-
bracketContent = "";
|
198
|
-
continue;
|
199
|
-
}
|
200
|
-
if (inBracket) {
|
201
|
-
bracketContent += char;
|
202
|
-
} else {
|
203
|
-
currentSegment += char;
|
204
|
-
}
|
89
|
+
return `${result}[${segment}]`;
|
90
|
+
}, "");
|
205
91
|
}
|
206
|
-
|
207
|
-
const
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
92
|
+
parsePath(path) {
|
93
|
+
const segments = [];
|
94
|
+
let currentSegment = "";
|
95
|
+
let backslashCount = 0;
|
96
|
+
for (let i = 0; i < path.length; i++) {
|
97
|
+
const char = path[i];
|
98
|
+
const nextChar = path[i + 1];
|
99
|
+
if (char === "]" && (nextChar === void 0 || nextChar === "[") && backslashCount % 2 === 0) {
|
100
|
+
segments.push(currentSegment);
|
101
|
+
currentSegment = "";
|
102
|
+
i++;
|
103
|
+
} else if (segments.length === 0 && char === "[" && backslashCount % 2 === 0) {
|
104
|
+
segments.push(currentSegment);
|
105
|
+
currentSegment = "";
|
106
|
+
} else if (char === "\\") {
|
107
|
+
backslashCount++;
|
108
|
+
} else {
|
109
|
+
currentSegment += "\\".repeat(backslashCount / 2) + char;
|
110
|
+
backslashCount = 0;
|
111
|
+
}
|
212
112
|
}
|
213
|
-
|
214
|
-
|
215
|
-
if (currentSegment
|
216
|
-
|
113
|
+
if (!segments.length) {
|
114
|
+
segments.push(currentSegment);
|
115
|
+
} else if (currentSegment) {
|
116
|
+
segments[segments.length - 1] += segments.length === 1 ? `[${currentSegment}` : `][${currentSegment}`;
|
217
117
|
}
|
218
|
-
|
219
|
-
} else if (currentSegment !== "" || result.length === 0) {
|
220
|
-
result.push(currentSegment);
|
118
|
+
return segments;
|
221
119
|
}
|
222
|
-
|
120
|
+
};
|
121
|
+
function isValidArrayIndex(value) {
|
122
|
+
return /^0$|^[1-9]\d*$/.test(value);
|
223
123
|
}
|
224
124
|
|
225
125
|
// src/openapi/json-serializer.ts
|
226
126
|
import { isObject as isObject2 } from "@orpc/shared";
|
227
127
|
var OpenAPIJsonSerializer = class {
|
228
|
-
serialize(
|
229
|
-
if (
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if (
|
234
|
-
return
|
128
|
+
serialize(data, hasBlobRef = { value: false }) {
|
129
|
+
if (data instanceof Blob) {
|
130
|
+
hasBlobRef.value = true;
|
131
|
+
return [data, hasBlobRef.value];
|
132
|
+
}
|
133
|
+
if (data instanceof Set) {
|
134
|
+
return this.serialize(Array.from(data), hasBlobRef);
|
235
135
|
}
|
236
|
-
if (
|
237
|
-
return
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
return
|
136
|
+
if (data instanceof Map) {
|
137
|
+
return this.serialize(Array.from(data.entries()), hasBlobRef);
|
138
|
+
}
|
139
|
+
if (Array.isArray(data)) {
|
140
|
+
const json = data.map((v) => v === void 0 ? null : this.serialize(v, hasBlobRef)[0]);
|
141
|
+
return [json, hasBlobRef.value];
|
142
|
+
}
|
143
|
+
if (isObject2(data)) {
|
144
|
+
const json = {};
|
145
|
+
for (const k in data) {
|
146
|
+
json[k] = this.serialize(data[k], hasBlobRef)[0];
|
147
|
+
}
|
148
|
+
return [json, hasBlobRef.value];
|
242
149
|
}
|
243
|
-
if (
|
244
|
-
return
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
return carry;
|
254
|
-
},
|
255
|
-
{}
|
256
|
-
);
|
150
|
+
if (typeof data === "bigint" || data instanceof RegExp || data instanceof URL) {
|
151
|
+
return [data.toString(), hasBlobRef.value];
|
152
|
+
}
|
153
|
+
if (data instanceof Date) {
|
154
|
+
return [Number.isNaN(data.getTime()) ? null : data.toISOString(), hasBlobRef.value];
|
155
|
+
}
|
156
|
+
if (Number.isNaN(data)) {
|
157
|
+
return [null, hasBlobRef.value];
|
158
|
+
}
|
159
|
+
return [data, hasBlobRef.value];
|
257
160
|
}
|
258
161
|
};
|
259
162
|
|
260
163
|
// src/openapi/serializer.ts
|
261
164
|
import { ErrorEvent, isAsyncIteratorObject } from "@orpc/server-standard";
|
262
|
-
import { findDeepMatches } from "@orpc/shared";
|
263
165
|
var OpenAPISerializer = class {
|
264
|
-
jsonSerializer
|
265
|
-
|
266
|
-
this.
|
166
|
+
constructor(jsonSerializer = new OpenAPIJsonSerializer(), bracketNotation = new BracketNotationSerializer()) {
|
167
|
+
this.jsonSerializer = jsonSerializer;
|
168
|
+
this.bracketNotation = bracketNotation;
|
267
169
|
}
|
268
170
|
serialize(data) {
|
269
|
-
if (data instanceof Blob || data === void 0) {
|
270
|
-
return data;
|
271
|
-
}
|
272
171
|
if (isAsyncIteratorObject(data)) {
|
273
172
|
return mapEventIterator(data, {
|
274
|
-
value: async (value) => this
|
173
|
+
value: async (value) => this.#serialize(value, false),
|
275
174
|
error: async (e) => {
|
276
175
|
if (e instanceof ErrorEvent) {
|
277
176
|
return new ErrorEvent({
|
278
|
-
data: this
|
177
|
+
data: this.#serialize(e.data, false),
|
279
178
|
cause: e
|
280
179
|
});
|
281
180
|
}
|
282
181
|
return new ErrorEvent({
|
283
|
-
data: this
|
182
|
+
data: this.#serialize(toORPCError(e).toJSON(), false),
|
284
183
|
cause: e
|
285
184
|
});
|
286
185
|
}
|
287
186
|
});
|
288
187
|
}
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
188
|
+
return this.#serialize(data, true);
|
189
|
+
}
|
190
|
+
#serialize(data, enableFormData) {
|
191
|
+
if (data instanceof Blob || data === void 0) {
|
192
|
+
return data;
|
193
|
+
}
|
194
|
+
const [json, hasBlob] = this.jsonSerializer.serialize(data);
|
195
|
+
if (!enableFormData || !hasBlob) {
|
196
|
+
return json;
|
293
197
|
}
|
294
198
|
const form = new FormData();
|
295
|
-
for (const [path, value] of serialize(
|
199
|
+
for (const [path, value] of this.bracketNotation.serialize(json)) {
|
296
200
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
297
201
|
form.append(path, value.toString());
|
298
|
-
} else if (value instanceof Date) {
|
299
|
-
form.append(path, value.toISOString());
|
300
202
|
} else if (value instanceof Blob) {
|
301
203
|
form.append(path, value);
|
302
204
|
}
|
303
205
|
}
|
304
206
|
return form;
|
305
207
|
}
|
306
|
-
deserialize(
|
307
|
-
if (
|
308
|
-
return deserialize(
|
208
|
+
deserialize(data) {
|
209
|
+
if (data instanceof URLSearchParams || data instanceof FormData) {
|
210
|
+
return this.bracketNotation.deserialize(Array.from(data.entries()));
|
309
211
|
}
|
310
|
-
if (isAsyncIteratorObject(
|
311
|
-
return mapEventIterator(
|
212
|
+
if (isAsyncIteratorObject(data)) {
|
213
|
+
return mapEventIterator(data, {
|
312
214
|
value: async (value) => value,
|
313
215
|
error: async (e) => {
|
314
216
|
if (e instanceof ErrorEvent && ORPCError.isValidJSON(e.data)) {
|
@@ -318,11 +220,11 @@ var OpenAPISerializer = class {
|
|
318
220
|
}
|
319
221
|
});
|
320
222
|
}
|
321
|
-
return
|
223
|
+
return data;
|
322
224
|
}
|
323
225
|
};
|
324
226
|
export {
|
325
|
-
|
227
|
+
BracketNotationSerializer,
|
326
228
|
OpenAPIJsonSerializer,
|
327
229
|
OpenAPISerializer
|
328
230
|
};
|
package/dist/rpc.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
import {
|
2
|
-
|
3
|
-
|
4
|
-
} from "./chunk-
|
5
|
-
import "./chunk-
|
2
|
+
RPCJsonSerializer,
|
3
|
+
RPCSerializer
|
4
|
+
} from "./chunk-4FUUNP74.js";
|
5
|
+
import "./chunk-OGAGXWCU.js";
|
6
6
|
export {
|
7
|
-
|
8
|
-
|
7
|
+
RPCJsonSerializer,
|
8
|
+
RPCSerializer
|
9
9
|
};
|
10
10
|
//# sourceMappingURL=rpc.js.map
|
@@ -1,84 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
* const payload = {
|
10
|
-
* name: 'John Doe',
|
11
|
-
* pets: ['dog', 'cat'],
|
12
|
-
* }
|
13
|
-
*
|
14
|
-
* const entities = serialize(payload)
|
15
|
-
*
|
16
|
-
* expect(entities).toEqual([
|
17
|
-
* ['name', 'John Doe'],
|
18
|
-
* ['name[pets][0]', 'dog'],
|
19
|
-
* ['name[pets][1]', 'cat'],
|
20
|
-
* ])
|
21
|
-
* ```
|
22
|
-
*/
|
23
|
-
export declare function serialize(payload: unknown, parentKey?: string): [string, unknown][];
|
24
|
-
/**
|
25
|
-
* Deserialize a list of [key, value] pairs into an object or array.
|
26
|
-
* The key is expressed by using bracket-notation.
|
27
|
-
*
|
28
|
-
* @example
|
29
|
-
* ```ts
|
30
|
-
* const entities = [
|
31
|
-
* ['name', 'John Doe'],
|
32
|
-
* ['name[pets][0]', 'dog'],
|
33
|
-
* ['name[pets][1]', 'cat'],
|
34
|
-
* ['name[dogs][]', 'hello'],
|
35
|
-
* ['name[dogs][]', 'kitty'],
|
36
|
-
* ]
|
37
|
-
*
|
38
|
-
* const payload = deserialize(entities)
|
39
|
-
*
|
40
|
-
* expect(payload).toEqual({
|
41
|
-
* name: 'John Doe',
|
42
|
-
* pets: { 0: 'dog', 1: 'cat' },
|
43
|
-
* dogs: ['hello', 'kitty'],
|
44
|
-
* })
|
45
|
-
* ```
|
46
|
-
*/
|
47
|
-
export declare function deserialize(entities: readonly (readonly [string, unknown])[]): Record<string, unknown> | unknown[] | undefined;
|
48
|
-
/**
|
49
|
-
* Escape the `[`, `]`, and `\` chars in a path segment.
|
50
|
-
*
|
51
|
-
* @example
|
52
|
-
* ```ts
|
53
|
-
* expect(escapeSegment('name[pets')).toEqual('name\\[pets')
|
54
|
-
* ```
|
55
|
-
*/
|
56
|
-
export declare function escapeSegment(segment: string): string;
|
57
|
-
/**
|
58
|
-
* Convert an array of path segments into a path string using bracket-notation.
|
59
|
-
*
|
60
|
-
* For the special char `[`, `]`, and `\` will be escaped by adding `\` at start.
|
61
|
-
*
|
62
|
-
* @example
|
63
|
-
* ```ts
|
64
|
-
* expect(stringifyPath(['name', 'pets', '0'])).toEqual('name[pets][0]')
|
65
|
-
* ```
|
66
|
-
*/
|
67
|
-
export declare function stringifyPath(path: readonly [string, ...string[]]): string;
|
68
|
-
/**
|
69
|
-
* Convert a path string using bracket-notation into an array of path segments.
|
70
|
-
*
|
71
|
-
* For the special char `[`, `]`, and `\` you should escape by adding `\` at start.
|
72
|
-
* It only treats a pair `[${string}]` as a path segment.
|
73
|
-
* If missing or escape it will bypass and treat as normal string.
|
74
|
-
*
|
75
|
-
* @example
|
76
|
-
* ```ts
|
77
|
-
* expect(parsePath('name[pets][0]')).toEqual(['name', 'pets', '0'])
|
78
|
-
* expect(parsePath('name[pets][0')).toEqual(['name', 'pets', '[0'])
|
79
|
-
* expect(parsePath('name[pets[0]')).toEqual(['name', 'pets[0')
|
80
|
-
* expect(parsePath('name\\[pets][0]')).toEqual(['name[pets]', '0'])
|
81
|
-
* ```
|
82
|
-
*/
|
83
|
-
export declare function parsePath(path: string): [string, ...string[]];
|
1
|
+
import { type Segment } from '@orpc/shared';
|
2
|
+
export type BracketNotationSerialized = [string, unknown][];
|
3
|
+
export declare class BracketNotationSerializer {
|
4
|
+
serialize(data: unknown, segments?: Segment[], result?: BracketNotationSerialized): BracketNotationSerialized;
|
5
|
+
deserialize(serialized: BracketNotationSerialized): unknown;
|
6
|
+
stringifyPath(segments: readonly Segment[]): string;
|
7
|
+
parsePath(path: string): string[];
|
8
|
+
}
|
84
9
|
//# sourceMappingURL=bracket-notation.d.ts.map
|
@@ -1,5 +1,7 @@
|
|
1
|
+
export type OpenAPIJsonSerialized = [json: unknown, hasBlob: boolean];
|
1
2
|
export declare class OpenAPIJsonSerializer {
|
2
|
-
serialize(
|
3
|
+
serialize(data: unknown, hasBlobRef?: {
|
4
|
+
value: boolean;
|
5
|
+
}): OpenAPIJsonSerialized;
|
3
6
|
}
|
4
|
-
export type PublicOpenAPIJsonSerializer = Pick<OpenAPIJsonSerializer, keyof OpenAPIJsonSerializer>;
|
5
7
|
//# sourceMappingURL=json-serializer.d.ts.map
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
jsonSerializer?: PublicOpenAPIJsonSerializer;
|
4
|
-
}
|
1
|
+
import { BracketNotationSerializer } from './bracket-notation';
|
2
|
+
import { OpenAPIJsonSerializer } from './json-serializer';
|
5
3
|
export declare class OpenAPISerializer {
|
4
|
+
#private;
|
6
5
|
private readonly jsonSerializer;
|
7
|
-
|
6
|
+
private readonly bracketNotation;
|
7
|
+
constructor(jsonSerializer?: OpenAPIJsonSerializer, bracketNotation?: BracketNotationSerializer);
|
8
8
|
serialize(data: unknown): unknown;
|
9
|
-
deserialize(
|
9
|
+
deserialize(data: unknown): unknown;
|
10
10
|
}
|
11
11
|
//# sourceMappingURL=serializer.d.ts.map
|
package/dist/src/rpc/index.d.ts
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
import { type Segment } from '@orpc/shared';
|
2
|
+
export type RPCJsonSerializedMeta = [
|
3
|
+
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7,
|
4
|
+
Segment[]
|
5
|
+
][];
|
6
|
+
export type RPCJsonSerialized = [json: unknown, meta: RPCJsonSerializedMeta, maps: Segment[][], blobs: Blob[]];
|
7
|
+
export declare class RPCJsonSerializer {
|
8
|
+
serialize(data: unknown, segments?: Segment[], meta?: RPCJsonSerializedMeta, maps?: Segment[][], blobs?: Blob[]): RPCJsonSerialized;
|
9
|
+
deserialize(json: unknown, meta: RPCJsonSerializedMeta): unknown;
|
10
|
+
deserialize(json: unknown, meta: RPCJsonSerializedMeta, maps: Segment[][], getBlob: (index: number) => Blob): unknown;
|
11
|
+
}
|
12
|
+
//# sourceMappingURL=json-serializer.d.ts.map
|
@@ -1,22 +1,9 @@
|
|
1
|
-
import
|
2
|
-
export type RPCSerializedJsonMeta = ['bigint' | 'date' | 'nan' | 'undefined' | 'set' | 'map' | 'regexp' | 'url', Segment[]][];
|
3
|
-
export type RPCSerialized = {
|
4
|
-
json: unknown;
|
5
|
-
meta: RPCSerializedJsonMeta;
|
6
|
-
} | FormData | AsyncIteratorObject<{
|
7
|
-
json: unknown;
|
8
|
-
meta: RPCSerializedJsonMeta;
|
9
|
-
}, {
|
10
|
-
json: unknown;
|
11
|
-
meta: RPCSerializedJsonMeta;
|
12
|
-
}, void>;
|
13
|
-
export type RPCSerializedFormDataMaps = Segment[][];
|
1
|
+
import { RPCJsonSerializer } from './json-serializer';
|
14
2
|
export declare class RPCSerializer {
|
15
|
-
|
16
|
-
|
3
|
+
#private;
|
4
|
+
private readonly jsonSerializer;
|
5
|
+
constructor(jsonSerializer?: RPCJsonSerializer);
|
6
|
+
serialize(data: unknown): unknown;
|
7
|
+
deserialize(data: unknown): unknown;
|
17
8
|
}
|
18
|
-
export declare function serializeRPCJson(value: unknown, segments?: Segment[], meta?: RPCSerializedJsonMeta): {
|
19
|
-
json: unknown;
|
20
|
-
meta: RPCSerializedJsonMeta;
|
21
|
-
};
|
22
9
|
//# sourceMappingURL=serializer.d.ts.map
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@orpc/client",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.
|
4
|
+
"version": "0.42.0",
|
5
5
|
"license": "MIT",
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
7
7
|
"repository": {
|
@@ -46,7 +46,7 @@
|
|
46
46
|
"dependencies": {
|
47
47
|
"@orpc/server-standard": "^0.4.0",
|
48
48
|
"@orpc/server-standard-fetch": "^0.4.0",
|
49
|
-
"@orpc/shared": "0.
|
49
|
+
"@orpc/shared": "0.42.0"
|
50
50
|
},
|
51
51
|
"devDependencies": {
|
52
52
|
"zod": "^3.24.1"
|
package/dist/chunk-TPEMQB7D.js
DELETED
@@ -1,178 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
ORPCError,
|
3
|
-
mapEventIterator,
|
4
|
-
toORPCError
|
5
|
-
} from "./chunk-2UPNYYFF.js";
|
6
|
-
|
7
|
-
// src/rpc/serializer.ts
|
8
|
-
import { ErrorEvent, isAsyncIteratorObject } from "@orpc/server-standard";
|
9
|
-
import { findDeepMatches, isObject, set } from "@orpc/shared";
|
10
|
-
var RPCSerializer = class {
|
11
|
-
serialize(data) {
|
12
|
-
if (isAsyncIteratorObject(data)) {
|
13
|
-
return mapEventIterator(data, {
|
14
|
-
value: async (value) => serializeRPCJson(value),
|
15
|
-
error: async (e) => {
|
16
|
-
if (e instanceof ErrorEvent) {
|
17
|
-
return new ErrorEvent({
|
18
|
-
data: serializeRPCJson(e.data),
|
19
|
-
cause: e
|
20
|
-
});
|
21
|
-
}
|
22
|
-
return new ErrorEvent({
|
23
|
-
data: serializeRPCJson(toORPCError(e).toJSON()),
|
24
|
-
cause: e
|
25
|
-
});
|
26
|
-
}
|
27
|
-
});
|
28
|
-
}
|
29
|
-
const serializedJSON = serializeRPCJson(data);
|
30
|
-
const { maps, values: blobs } = findDeepMatches((v) => v instanceof Blob, serializedJSON.json);
|
31
|
-
if (blobs.length === 0) {
|
32
|
-
return serializedJSON;
|
33
|
-
}
|
34
|
-
const form = new FormData();
|
35
|
-
form.set("data", JSON.stringify(serializedJSON));
|
36
|
-
form.set("maps", JSON.stringify(maps));
|
37
|
-
for (const i in blobs) {
|
38
|
-
form.set(i, blobs[i]);
|
39
|
-
}
|
40
|
-
return form;
|
41
|
-
}
|
42
|
-
deserialize(serialized) {
|
43
|
-
if (isAsyncIteratorObject(serialized)) {
|
44
|
-
return mapEventIterator(serialized, {
|
45
|
-
value: async (value) => deserializeRPCJson(value),
|
46
|
-
error: async (e) => {
|
47
|
-
if (!(e instanceof ErrorEvent)) {
|
48
|
-
return e;
|
49
|
-
}
|
50
|
-
const deserialized = deserializeRPCJson(e.data);
|
51
|
-
if (ORPCError.isValidJSON(deserialized)) {
|
52
|
-
return ORPCError.fromJSON(deserialized, { cause: e });
|
53
|
-
}
|
54
|
-
return new ErrorEvent({
|
55
|
-
data: deserialized,
|
56
|
-
cause: e
|
57
|
-
});
|
58
|
-
}
|
59
|
-
});
|
60
|
-
}
|
61
|
-
if (!(serialized instanceof FormData)) {
|
62
|
-
return deserializeRPCJson(serialized);
|
63
|
-
}
|
64
|
-
const data = JSON.parse(serialized.get("data"));
|
65
|
-
const maps = JSON.parse(serialized.get("maps"));
|
66
|
-
for (const i in maps) {
|
67
|
-
data.json = set(data.json, maps[i], serialized.get(i));
|
68
|
-
}
|
69
|
-
return deserializeRPCJson(data);
|
70
|
-
}
|
71
|
-
};
|
72
|
-
function serializeRPCJson(value, segments = [], meta = []) {
|
73
|
-
if (typeof value === "bigint") {
|
74
|
-
meta.push(["bigint", segments]);
|
75
|
-
return { json: value.toString(), meta };
|
76
|
-
}
|
77
|
-
if (value instanceof Date) {
|
78
|
-
meta.push(["date", segments]);
|
79
|
-
const data = Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
80
|
-
return { json: data, meta };
|
81
|
-
}
|
82
|
-
if (Number.isNaN(value)) {
|
83
|
-
meta.push(["nan", segments]);
|
84
|
-
return { json: "NaN", meta };
|
85
|
-
}
|
86
|
-
if (value instanceof RegExp) {
|
87
|
-
meta.push(["regexp", segments]);
|
88
|
-
return { json: value.toString(), meta };
|
89
|
-
}
|
90
|
-
if (value instanceof URL) {
|
91
|
-
meta.push(["url", segments]);
|
92
|
-
return { json: value.toString(), meta };
|
93
|
-
}
|
94
|
-
if (isObject(value)) {
|
95
|
-
const json = {};
|
96
|
-
for (const k in value) {
|
97
|
-
json[k] = serializeRPCJson(value[k], [...segments, k], meta).json;
|
98
|
-
}
|
99
|
-
return { json, meta };
|
100
|
-
}
|
101
|
-
if (Array.isArray(value)) {
|
102
|
-
const json = value.map((v, i) => {
|
103
|
-
if (v === void 0) {
|
104
|
-
meta.push(["undefined", [...segments, i]]);
|
105
|
-
return null;
|
106
|
-
}
|
107
|
-
return serializeRPCJson(v, [...segments, i], meta).json;
|
108
|
-
});
|
109
|
-
return { json, meta };
|
110
|
-
}
|
111
|
-
if (value instanceof Set) {
|
112
|
-
const result = serializeRPCJson(Array.from(value), segments, meta);
|
113
|
-
meta.push(["set", segments]);
|
114
|
-
return result;
|
115
|
-
}
|
116
|
-
if (value instanceof Map) {
|
117
|
-
const result = serializeRPCJson(Array.from(value.entries()), segments, meta);
|
118
|
-
meta.push(["map", segments]);
|
119
|
-
return result;
|
120
|
-
}
|
121
|
-
return { json: value, meta };
|
122
|
-
}
|
123
|
-
function deserializeRPCJson({
|
124
|
-
json,
|
125
|
-
meta
|
126
|
-
}) {
|
127
|
-
if (meta.length === 0) {
|
128
|
-
return json;
|
129
|
-
}
|
130
|
-
const ref = { data: json };
|
131
|
-
for (const [type, segments] of meta) {
|
132
|
-
let currentRef = ref;
|
133
|
-
let preSegment = "data";
|
134
|
-
for (let i = 0; i < segments.length; i++) {
|
135
|
-
currentRef = currentRef[preSegment];
|
136
|
-
preSegment = segments[i];
|
137
|
-
}
|
138
|
-
switch (type) {
|
139
|
-
case "nan":
|
140
|
-
currentRef[preSegment] = Number.NaN;
|
141
|
-
break;
|
142
|
-
case "bigint":
|
143
|
-
currentRef[preSegment] = BigInt(currentRef[preSegment]);
|
144
|
-
break;
|
145
|
-
case "date":
|
146
|
-
currentRef[preSegment] = new Date(currentRef[preSegment]);
|
147
|
-
break;
|
148
|
-
case "regexp": {
|
149
|
-
const [, pattern, flags] = currentRef[preSegment].match(/^\/(.*)\/([a-z]*)$/);
|
150
|
-
currentRef[preSegment] = new RegExp(pattern, flags);
|
151
|
-
break;
|
152
|
-
}
|
153
|
-
case "url":
|
154
|
-
currentRef[preSegment] = new URL(currentRef[preSegment]);
|
155
|
-
break;
|
156
|
-
case "undefined":
|
157
|
-
currentRef[preSegment] = void 0;
|
158
|
-
break;
|
159
|
-
case "map":
|
160
|
-
currentRef[preSegment] = new Map(currentRef[preSegment]);
|
161
|
-
break;
|
162
|
-
case "set":
|
163
|
-
currentRef[preSegment] = new Set(currentRef[preSegment]);
|
164
|
-
break;
|
165
|
-
/* v8 ignore next 3 */
|
166
|
-
default: {
|
167
|
-
const _expected = type;
|
168
|
-
}
|
169
|
-
}
|
170
|
-
}
|
171
|
-
return ref.data;
|
172
|
-
}
|
173
|
-
|
174
|
-
export {
|
175
|
-
RPCSerializer,
|
176
|
-
serializeRPCJson
|
177
|
-
};
|
178
|
-
//# sourceMappingURL=chunk-TPEMQB7D.js.map
|