@orpc/client 0.0.0-next.fe39bf3 → 0.0.0-next.fea68c1
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-2UPNYYFF.js → chunk-7F3XVLRJ.js} +5 -12
- package/dist/chunk-FF5VXXNP.js +213 -0
- package/dist/fetch.js +6 -7
- package/dist/index.js +13 -4
- package/dist/openapi.js +150 -247
- 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/dist/src/utils.d.ts +13 -1
- package/package.json +4 -4
- 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.
|
@@ -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 = {
|
@@ -171,8 +165,8 @@ function onEventIteratorStatusChange(iterator, callback, notifyImmediately = tru
|
|
171
165
|
}
|
172
166
|
|
173
167
|
// src/event-iterator.ts
|
174
|
-
import {
|
175
|
-
import {
|
168
|
+
import { isTypescriptObject, retry } from "@orpc/shared";
|
169
|
+
import { getEventMeta, withEventMeta } from "@orpc/standard-server";
|
176
170
|
function mapEventIterator(iterator, maps) {
|
177
171
|
return async function* () {
|
178
172
|
try {
|
@@ -181,7 +175,7 @@ function mapEventIterator(iterator, maps) {
|
|
181
175
|
let mappedValue = await maps.value(value, done);
|
182
176
|
if (mappedValue !== value) {
|
183
177
|
const meta = getEventMeta(value);
|
184
|
-
if (meta &&
|
178
|
+
if (meta && isTypescriptObject(mappedValue)) {
|
185
179
|
mappedValue = withEventMeta(mappedValue, meta);
|
186
180
|
}
|
187
181
|
}
|
@@ -194,7 +188,7 @@ function mapEventIterator(iterator, maps) {
|
|
194
188
|
let mappedError = await maps.error(error);
|
195
189
|
if (mappedError !== error) {
|
196
190
|
const meta = getEventMeta(error);
|
197
|
-
if (meta &&
|
191
|
+
if (meta && isTypescriptObject(mappedError)) {
|
198
192
|
mappedError = withEventMeta(mappedError, meta);
|
199
193
|
}
|
200
194
|
}
|
@@ -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-7F3XVLRJ.js.map
|
@@ -0,0 +1,213 @@
|
|
1
|
+
import {
|
2
|
+
ORPCError,
|
3
|
+
mapEventIterator,
|
4
|
+
toORPCError
|
5
|
+
} from "./chunk-7F3XVLRJ.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 { isAsyncIteratorObject, stringifyJSON } from "@orpc/shared";
|
127
|
+
import { ErrorEvent } from "@orpc/standard-server";
|
128
|
+
var RPCSerializer = class {
|
129
|
+
constructor(jsonSerializer = new RPCJsonSerializer()) {
|
130
|
+
this.jsonSerializer = jsonSerializer;
|
131
|
+
}
|
132
|
+
serialize(data) {
|
133
|
+
if (isAsyncIteratorObject(data)) {
|
134
|
+
return mapEventIterator(data, {
|
135
|
+
value: async (value) => this.#serialize(value, false),
|
136
|
+
error: async (e) => {
|
137
|
+
if (e instanceof ErrorEvent) {
|
138
|
+
return new ErrorEvent({
|
139
|
+
data: this.#serialize(e.data, false),
|
140
|
+
cause: e
|
141
|
+
});
|
142
|
+
}
|
143
|
+
return new ErrorEvent({
|
144
|
+
data: this.#serialize(toORPCError(e).toJSON(), false),
|
145
|
+
cause: e
|
146
|
+
});
|
147
|
+
}
|
148
|
+
});
|
149
|
+
}
|
150
|
+
return this.#serialize(data, true);
|
151
|
+
}
|
152
|
+
#serialize(data, enableFormData) {
|
153
|
+
if (data === void 0 || data instanceof Blob) {
|
154
|
+
return data;
|
155
|
+
}
|
156
|
+
const [json, meta_, maps, blobs] = this.jsonSerializer.serialize(data);
|
157
|
+
const meta = meta_.length === 0 ? void 0 : meta_;
|
158
|
+
if (!enableFormData || blobs.length === 0) {
|
159
|
+
return {
|
160
|
+
json,
|
161
|
+
meta
|
162
|
+
};
|
163
|
+
}
|
164
|
+
const form = new FormData();
|
165
|
+
form.set("data", stringifyJSON({ json, meta, maps }));
|
166
|
+
blobs.forEach((blob, i) => {
|
167
|
+
form.set(i.toString(), blob);
|
168
|
+
});
|
169
|
+
return form;
|
170
|
+
}
|
171
|
+
deserialize(data) {
|
172
|
+
if (isAsyncIteratorObject(data)) {
|
173
|
+
return mapEventIterator(data, {
|
174
|
+
value: async (value) => this.#deserialize(value),
|
175
|
+
error: async (e) => {
|
176
|
+
if (!(e instanceof ErrorEvent)) {
|
177
|
+
return e;
|
178
|
+
}
|
179
|
+
const deserialized = this.#deserialize(e.data);
|
180
|
+
if (ORPCError.isValidJSON(deserialized)) {
|
181
|
+
return ORPCError.fromJSON(deserialized, { cause: e });
|
182
|
+
}
|
183
|
+
return new ErrorEvent({
|
184
|
+
data: deserialized,
|
185
|
+
cause: e
|
186
|
+
});
|
187
|
+
}
|
188
|
+
});
|
189
|
+
}
|
190
|
+
return this.#deserialize(data);
|
191
|
+
}
|
192
|
+
#deserialize(data) {
|
193
|
+
if (data === void 0 || data instanceof Blob) {
|
194
|
+
return data;
|
195
|
+
}
|
196
|
+
if (!(data instanceof FormData)) {
|
197
|
+
return this.jsonSerializer.deserialize(data.json, data.meta ?? []);
|
198
|
+
}
|
199
|
+
const serialized = JSON.parse(data.get("data"));
|
200
|
+
return this.jsonSerializer.deserialize(
|
201
|
+
serialized.json,
|
202
|
+
serialized.meta ?? [],
|
203
|
+
serialized.maps,
|
204
|
+
(i) => data.get(i.toString())
|
205
|
+
);
|
206
|
+
}
|
207
|
+
};
|
208
|
+
|
209
|
+
export {
|
210
|
+
RPCJsonSerializer,
|
211
|
+
RPCSerializer
|
212
|
+
};
|
213
|
+
//# sourceMappingURL=chunk-FF5VXXNP.js.map
|
package/dist/fetch.js
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
import {
|
2
2
|
RPCSerializer
|
3
|
-
} from "./chunk-
|
3
|
+
} from "./chunk-FF5VXXNP.js";
|
4
4
|
import {
|
5
5
|
ORPCError,
|
6
6
|
createAutoRetryEventIterator
|
7
|
-
} from "./chunk-
|
7
|
+
} from "./chunk-7F3XVLRJ.js";
|
8
8
|
|
9
9
|
// src/adapters/fetch/rpc-link.ts
|
10
|
-
import { isAsyncIteratorObject } from "@orpc/
|
11
|
-
import { toFetchBody, toStandardBody } from "@orpc/server-
|
12
|
-
import { trim, value } from "@orpc/shared";
|
10
|
+
import { isAsyncIteratorObject, stringifyJSON, trim, value } from "@orpc/shared";
|
11
|
+
import { toFetchBody, toStandardBody } from "@orpc/standard-server-fetch";
|
13
12
|
var InvalidEventSourceRetryResponse = class extends Error {
|
14
13
|
};
|
15
14
|
var RPCLink = class {
|
@@ -101,9 +100,9 @@ var RPCLink = class {
|
|
101
100
|
const headers = new Headers(await value(this.headers, options, path, input));
|
102
101
|
const url = new URL(`${trim(this.url, "/")}/${path.map(encodeURIComponent).join("/")}`);
|
103
102
|
const serialized = this.rpcSerializer.serialize(input);
|
104
|
-
if (expectedMethod === "GET" && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
|
103
|
+
if (expectedMethod === "GET" && !(serialized instanceof FormData) && !(serialized instanceof Blob) && !isAsyncIteratorObject(serialized)) {
|
105
104
|
const getUrl = new URL(url);
|
106
|
-
getUrl.searchParams.append("data",
|
105
|
+
getUrl.searchParams.append("data", stringifyJSON(serialized) ?? "");
|
107
106
|
if (getUrl.toString().length <= this.maxUrlLength) {
|
108
107
|
return {
|
109
108
|
body: void 0,
|
package/dist/index.js
CHANGED
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
registerEventIteratorState,
|
11
11
|
toORPCError,
|
12
12
|
updateEventIteratorStatus
|
13
|
-
} from "./chunk-
|
13
|
+
} from "./chunk-7F3XVLRJ.js";
|
14
14
|
|
15
15
|
// src/client.ts
|
16
16
|
function createORPCClient(link, options) {
|
@@ -53,13 +53,22 @@ var DynamicLink = class {
|
|
53
53
|
async function safe(promise) {
|
54
54
|
try {
|
55
55
|
const output = await promise;
|
56
|
-
return
|
56
|
+
return Object.assign(
|
57
|
+
[null, output, false],
|
58
|
+
{ error: null, data: output, isDefined: false }
|
59
|
+
);
|
57
60
|
} catch (e) {
|
58
61
|
const error = e;
|
59
62
|
if (isDefinedError(error)) {
|
60
|
-
return
|
63
|
+
return Object.assign(
|
64
|
+
[error, void 0, true],
|
65
|
+
{ error, data: void 0, isDefined: true }
|
66
|
+
);
|
61
67
|
}
|
62
|
-
return
|
68
|
+
return Object.assign(
|
69
|
+
[error, void 0, false],
|
70
|
+
{ error, data: void 0, isDefined: false }
|
71
|
+
);
|
63
72
|
}
|
64
73
|
}
|
65
74
|
export {
|
package/dist/openapi.js
CHANGED
@@ -1,314 +1,217 @@
|
|
1
1
|
import {
|
2
2
|
ORPCError,
|
3
|
-
__export,
|
4
3
|
mapEventIterator,
|
5
4
|
toORPCError
|
6
|
-
} from "./chunk-
|
5
|
+
} from "./chunk-7F3XVLRJ.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
|
-
}
|
185
|
-
if (char === "[" && !inBracket) {
|
186
|
-
if (currentSegment !== "" || result.length === 0) {
|
187
|
-
result.push(currentSegment);
|
188
|
-
}
|
189
|
-
inBracket = true;
|
190
|
-
bracketContent = "";
|
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
67
|
}
|
68
|
+
return ref.value;
|
205
69
|
}
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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;
|
88
|
+
}
|
89
|
+
return `${result}[${segment}]`;
|
90
|
+
}, "");
|
213
91
|
}
|
214
|
-
|
215
|
-
|
216
|
-
|
92
|
+
parsePath(path) {
|
93
|
+
const segments = [];
|
94
|
+
let inBrackets = false;
|
95
|
+
let currentSegment = "";
|
96
|
+
let backslashCount = 0;
|
97
|
+
for (let i = 0; i < path.length; i++) {
|
98
|
+
const char = path[i];
|
99
|
+
const nextChar = path[i + 1];
|
100
|
+
if (inBrackets && char === "]" && (nextChar === void 0 || nextChar === "[") && backslashCount % 2 === 0) {
|
101
|
+
if (nextChar === void 0) {
|
102
|
+
inBrackets = false;
|
103
|
+
}
|
104
|
+
segments.push(currentSegment);
|
105
|
+
currentSegment = "";
|
106
|
+
i++;
|
107
|
+
} else if (segments.length === 0 && char === "[" && backslashCount % 2 === 0) {
|
108
|
+
inBrackets = true;
|
109
|
+
segments.push(currentSegment);
|
110
|
+
currentSegment = "";
|
111
|
+
} else if (char === "\\") {
|
112
|
+
backslashCount++;
|
113
|
+
} else {
|
114
|
+
currentSegment += "\\".repeat(backslashCount / 2) + char;
|
115
|
+
backslashCount = 0;
|
116
|
+
}
|
217
117
|
}
|
218
|
-
|
219
|
-
} else if (currentSegment !== "" || result.length === 0) {
|
220
|
-
result.push(currentSegment);
|
118
|
+
return inBrackets || segments.length === 0 ? [path] : 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);
|
135
|
+
}
|
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];
|
235
142
|
}
|
236
|
-
if (
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
return
|
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];
|
149
|
+
}
|
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];
|
242
158
|
}
|
243
|
-
|
244
|
-
return payload.toString();
|
245
|
-
if (payload instanceof URL)
|
246
|
-
return payload.toString();
|
247
|
-
if (!isObject2(payload))
|
248
|
-
return payload;
|
249
|
-
return Object.keys(payload).reduce(
|
250
|
-
(carry, key) => {
|
251
|
-
const val = payload[key];
|
252
|
-
carry[key] = this.serialize(val);
|
253
|
-
return carry;
|
254
|
-
},
|
255
|
-
{}
|
256
|
-
);
|
159
|
+
return [data, hasBlobRef.value];
|
257
160
|
}
|
258
161
|
};
|
259
162
|
|
260
163
|
// src/openapi/serializer.ts
|
261
|
-
import {
|
262
|
-
import {
|
164
|
+
import { isAsyncIteratorObject } from "@orpc/shared";
|
165
|
+
import { ErrorEvent } from "@orpc/standard-server";
|
263
166
|
var OpenAPISerializer = class {
|
264
|
-
jsonSerializer
|
265
|
-
|
266
|
-
this.
|
167
|
+
constructor(jsonSerializer = new OpenAPIJsonSerializer(), bracketNotation = new BracketNotationSerializer()) {
|
168
|
+
this.jsonSerializer = jsonSerializer;
|
169
|
+
this.bracketNotation = bracketNotation;
|
267
170
|
}
|
268
171
|
serialize(data) {
|
269
|
-
if (data instanceof Blob || data === void 0) {
|
270
|
-
return data;
|
271
|
-
}
|
272
172
|
if (isAsyncIteratorObject(data)) {
|
273
173
|
return mapEventIterator(data, {
|
274
|
-
value: async (value) => this
|
174
|
+
value: async (value) => this.#serialize(value, false),
|
275
175
|
error: async (e) => {
|
276
176
|
if (e instanceof ErrorEvent) {
|
277
177
|
return new ErrorEvent({
|
278
|
-
data: this
|
178
|
+
data: this.#serialize(e.data, false),
|
279
179
|
cause: e
|
280
180
|
});
|
281
181
|
}
|
282
182
|
return new ErrorEvent({
|
283
|
-
data: this
|
183
|
+
data: this.#serialize(toORPCError(e).toJSON(), false),
|
284
184
|
cause: e
|
285
185
|
});
|
286
186
|
}
|
287
187
|
});
|
288
188
|
}
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
189
|
+
return this.#serialize(data, true);
|
190
|
+
}
|
191
|
+
#serialize(data, enableFormData) {
|
192
|
+
if (data instanceof Blob || data === void 0) {
|
193
|
+
return data;
|
194
|
+
}
|
195
|
+
const [json, hasBlob] = this.jsonSerializer.serialize(data);
|
196
|
+
if (!enableFormData || !hasBlob) {
|
197
|
+
return json;
|
293
198
|
}
|
294
199
|
const form = new FormData();
|
295
|
-
for (const [path, value] of serialize(
|
200
|
+
for (const [path, value] of this.bracketNotation.serialize(json)) {
|
296
201
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
297
202
|
form.append(path, value.toString());
|
298
|
-
} else if (value instanceof Date) {
|
299
|
-
form.append(path, value.toISOString());
|
300
203
|
} else if (value instanceof Blob) {
|
301
204
|
form.append(path, value);
|
302
205
|
}
|
303
206
|
}
|
304
207
|
return form;
|
305
208
|
}
|
306
|
-
deserialize(
|
307
|
-
if (
|
308
|
-
return deserialize(
|
209
|
+
deserialize(data) {
|
210
|
+
if (data instanceof URLSearchParams || data instanceof FormData) {
|
211
|
+
return this.bracketNotation.deserialize(Array.from(data.entries()));
|
309
212
|
}
|
310
|
-
if (isAsyncIteratorObject(
|
311
|
-
return mapEventIterator(
|
213
|
+
if (isAsyncIteratorObject(data)) {
|
214
|
+
return mapEventIterator(data, {
|
312
215
|
value: async (value) => value,
|
313
216
|
error: async (e) => {
|
314
217
|
if (e instanceof ErrorEvent && ORPCError.isValidJSON(e.data)) {
|
@@ -318,11 +221,11 @@ var OpenAPISerializer = class {
|
|
318
221
|
}
|
319
222
|
});
|
320
223
|
}
|
321
|
-
return
|
224
|
+
return data;
|
322
225
|
}
|
323
226
|
};
|
324
227
|
export {
|
325
|
-
|
228
|
+
BracketNotationSerializer,
|
326
229
|
OpenAPIJsonSerializer,
|
327
230
|
OpenAPISerializer
|
328
231
|
};
|
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-FF5VXXNP.js";
|
5
|
+
import "./chunk-7F3XVLRJ.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/dist/src/utils.d.ts
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
import type { ORPCError } from './error';
|
2
2
|
import type { ClientPromiseResult } from './types';
|
3
|
-
export type SafeResult<TOutput, TError extends Error> = [
|
3
|
+
export type SafeResult<TOutput, TError extends Error> = [error: null, data: TOutput, isDefined: false] & {
|
4
|
+
error: null;
|
5
|
+
data: TOutput;
|
6
|
+
isDefined: false;
|
7
|
+
} | [error: Exclude<TError, ORPCError<any, any>>, data: undefined, isDefined: false] & {
|
8
|
+
error: Exclude<TError, ORPCError<any, any>>;
|
9
|
+
data: undefined;
|
10
|
+
isDefined: false;
|
11
|
+
} | [error: Extract<TError, ORPCError<any, any>>, data: undefined, isDefined: true] & {
|
12
|
+
error: Extract<TError, ORPCError<any, any>>;
|
13
|
+
data: undefined;
|
14
|
+
isDefined: true;
|
15
|
+
};
|
4
16
|
export declare function safe<TOutput, TError extends Error>(promise: ClientPromiseResult<TOutput, TError>): Promise<SafeResult<TOutput, TError>>;
|
5
17
|
//# sourceMappingURL=utils.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.0.0-next.
|
4
|
+
"version": "0.0.0-next.fea68c1",
|
5
5
|
"license": "MIT",
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
7
7
|
"repository": {
|
@@ -44,9 +44,9 @@
|
|
44
44
|
"dist"
|
45
45
|
],
|
46
46
|
"dependencies": {
|
47
|
-
"@orpc/
|
48
|
-
"@orpc/
|
49
|
-
"@orpc/
|
47
|
+
"@orpc/shared": "0.0.0-next.fea68c1",
|
48
|
+
"@orpc/standard-server": "0.0.0-next.fea68c1",
|
49
|
+
"@orpc/standard-server-fetch": "0.0.0-next.fea68c1"
|
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
|