@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 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 { getEventMeta, isEventMetaContainer, withEventMeta } from "@orpc/server-standard";
175
- import { retry } from "@orpc/shared";
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 && isEventMetaContainer(mappedValue)) {
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 && isEventMetaContainer(mappedError)) {
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-2UPNYYFF.js.map
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-TPEMQB7D.js";
3
+ } from "./chunk-FF5VXXNP.js";
4
4
  import {
5
5
  ORPCError,
6
6
  createAutoRetryEventIterator
7
- } from "./chunk-2UPNYYFF.js";
7
+ } from "./chunk-7F3XVLRJ.js";
8
8
 
9
9
  // src/adapters/fetch/rpc-link.ts
10
- import { isAsyncIteratorObject } from "@orpc/server-standard";
11
- import { toFetchBody, toStandardBody } from "@orpc/server-standard-fetch";
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", JSON.stringify(serialized));
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-2UPNYYFF.js";
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 [output, void 0, false];
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 [void 0, error, true];
63
+ return Object.assign(
64
+ [error, void 0, true],
65
+ { error, data: void 0, isDefined: true }
66
+ );
61
67
  }
62
- return [void 0, error, false];
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-2UPNYYFF.js";
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
- function serialize(payload, parentKey = "") {
19
- if (!Array.isArray(payload) && !isObject(payload))
20
- return [["", payload]];
21
- const result = [];
22
- function helper(value, path) {
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(value)) {
28
- for (const [key, val] of Object.entries(value)) {
29
- helper(val, [...path, key]);
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(path), value]);
20
+ result.push([this.stringifyPath(segments), data]);
33
21
  }
22
+ return result;
34
23
  }
35
- helper(payload, parentKey ? [parentKey] : []);
36
- return result;
37
- }
38
- function deserialize(entities) {
39
- if (entities.length === 0) {
40
- return void 0;
41
- }
42
- const isRootArray = entities.every(([path]) => path === "");
43
- const result = isRootArray ? [] : {};
44
- const arrayPushPaths = /* @__PURE__ */ new Set();
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
- if (!(first in objAsRecord)) {
81
- objAsRecord[first] = {};
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 (inBracket) {
151
- bracketContent += literalBackslashes;
152
- } else {
153
- currentSegment += literalBackslashes;
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
- currentSegment += char;
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
- } else {
175
- const allBackslashes = "\\".repeat(backslashCount);
176
- if (inBracket) {
177
- bracketContent += allBackslashes + char;
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
- currentSegment += allBackslashes + char;
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
- if (backslashCount > 0) {
207
- const remainingBackslashes = "\\".repeat(backslashCount);
208
- if (inBracket) {
209
- bracketContent += remainingBackslashes;
210
- } else {
211
- currentSegment += remainingBackslashes;
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
- if (inBracket) {
215
- if (currentSegment !== "" || result.length === 0) {
216
- result.push(currentSegment);
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
- result.push(`[${bracketContent}`);
219
- } else if (currentSegment !== "" || result.length === 0) {
220
- result.push(currentSegment);
118
+ return inBrackets || segments.length === 0 ? [path] : segments;
221
119
  }
222
- return result;
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(payload) {
229
- if (payload instanceof Set)
230
- return this.serialize([...payload]);
231
- if (payload instanceof Map)
232
- return this.serialize([...payload.entries()]);
233
- if (Array.isArray(payload)) {
234
- return payload.map((v) => v === void 0 ? "undefined" : this.serialize(v));
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 (Number.isNaN(payload))
237
- return "NaN";
238
- if (typeof payload === "bigint")
239
- return payload.toString();
240
- if (payload instanceof Date && Number.isNaN(payload.getTime())) {
241
- return "Invalid Date";
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
- if (payload instanceof RegExp)
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 { ErrorEvent, isAsyncIteratorObject } from "@orpc/server-standard";
262
- import { findDeepMatches } from "@orpc/shared";
164
+ import { isAsyncIteratorObject } from "@orpc/shared";
165
+ import { ErrorEvent } from "@orpc/standard-server";
263
166
  var OpenAPISerializer = class {
264
- jsonSerializer;
265
- constructor(options) {
266
- this.jsonSerializer = options?.jsonSerializer ?? new OpenAPIJsonSerializer();
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.jsonSerializer.serialize(value),
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.jsonSerializer.serialize(e.data),
178
+ data: this.#serialize(e.data, false),
279
179
  cause: e
280
180
  });
281
181
  }
282
182
  return new ErrorEvent({
283
- data: this.jsonSerializer.serialize(toORPCError(e).toJSON()),
183
+ data: this.#serialize(toORPCError(e).toJSON(), false),
284
184
  cause: e
285
185
  });
286
186
  }
287
187
  });
288
188
  }
289
- const serializedJSON = this.jsonSerializer.serialize(data);
290
- const { values: blobs } = findDeepMatches((v) => v instanceof Blob, serializedJSON);
291
- if (blobs.length === 0) {
292
- return serializedJSON;
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(serializedJSON)) {
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(serialized) {
307
- if (serialized instanceof URLSearchParams || serialized instanceof FormData) {
308
- return deserialize([...serialized.entries()]);
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(serialized)) {
311
- return mapEventIterator(serialized, {
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 serialized;
224
+ return data;
322
225
  }
323
226
  };
324
227
  export {
325
- bracket_notation_exports as BracketNotation,
228
+ BracketNotationSerializer,
326
229
  OpenAPIJsonSerializer,
327
230
  OpenAPISerializer
328
231
  };
package/dist/rpc.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
- RPCSerializer,
3
- serializeRPCJson
4
- } from "./chunk-TPEMQB7D.js";
5
- import "./chunk-2UPNYYFF.js";
2
+ RPCJsonSerializer,
3
+ RPCSerializer
4
+ } from "./chunk-FF5VXXNP.js";
5
+ import "./chunk-7F3XVLRJ.js";
6
6
  export {
7
- RPCSerializer,
8
- serializeRPCJson
7
+ RPCJsonSerializer,
8
+ RPCSerializer
9
9
  };
10
10
  //# sourceMappingURL=rpc.js.map
@@ -1,84 +1,9 @@
1
- /**
2
- * Serialize an object or array into a list of [key, value] pairs.
3
- * The key will express by using bracket-notation.
4
- *
5
- * Notice: This way cannot express the empty object or array.
6
- *
7
- * @example
8
- * ```ts
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,4 +1,4 @@
1
- export * as BracketNotation from './bracket-notation';
1
+ export * from './bracket-notation';
2
2
  export * from './json-serializer';
3
3
  export * from './serializer';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,7 @@
1
+ export type OpenAPIJsonSerialized = [json: unknown, hasBlob: boolean];
1
2
  export declare class OpenAPIJsonSerializer {
2
- serialize(payload: unknown): unknown;
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 type { PublicOpenAPIJsonSerializer } from './json-serializer';
2
- export interface OpenAPISerializerOptions {
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
- constructor(options?: OpenAPISerializerOptions);
6
+ private readonly bracketNotation;
7
+ constructor(jsonSerializer?: OpenAPIJsonSerializer, bracketNotation?: BracketNotationSerializer);
8
8
  serialize(data: unknown): unknown;
9
- deserialize(serialized: unknown): unknown;
9
+ deserialize(data: unknown): unknown;
10
10
  }
11
11
  //# sourceMappingURL=serializer.d.ts.map
@@ -1,2 +1,3 @@
1
+ export * from './json-serializer';
1
2
  export * from './serializer';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -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 type { Segment } from '@orpc/shared';
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
- serialize(data: unknown): RPCSerialized;
16
- deserialize(serialized: RPCSerialized): unknown;
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
@@ -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> = [output: TOutput, error: undefined, isDefinedError: false] | [output: undefined, error: TError, isDefinedError: false] | [output: undefined, error: Extract<TError, ORPCError<any, any>>, isDefinedError: true];
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.fe39bf3",
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/server-standard": "^0.4.0",
48
- "@orpc/server-standard-fetch": "^0.4.0",
49
- "@orpc/shared": "0.0.0-next.fe39bf3"
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"
@@ -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