🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@orpc/client

Package Overview
Dependencies
Maintainers
1
Versions
1130
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@orpc/client - npm Package Compare versions

Comparing version
2.0.0-beta.21
to
2.0.0-beta.22
+174
dist/shared/client.Bl4junIW.mjs
import { sortPlugins, runWithSpan, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, intercept, getOpenTelemetryConfig, value, pathToHttpPath, stringifyJSON } from '@orpc/shared';
import { mergeStandardHeaders, parseStandardUrl } from '@standardserver/core';
import { toStandardHeaders } from '@standardserver/fetch';
import { O as ORPCError } from './client.Dnfj8jnT.mjs';
import { R as RPCSerializer, i as isORPCErrorJson, c as createORPCErrorFromJson } from './client.DQpq_Sdn.mjs';
class CompositeStandardLinkPlugin {
name = "~composite";
plugins;
constructor(plugins = []) {
this.plugins = sortPlugins(plugins);
}
init(options) {
for (const plugin of this.plugins) {
if (plugin.init) {
options = plugin.init(options);
}
}
return options;
}
}
class StandardLink {
constructor(codec, transport, options = {}) {
this.codec = codec;
this.transport = transport;
options = new CompositeStandardLinkPlugin(options.plugins).init(options);
this.interceptors = options.interceptors;
this.transportInterceptors = options.transportInterceptors;
}
interceptors;
transportInterceptors;
/**
* @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
*/
call(path, input, options) {
return runWithSpan(`${ORPC_NAME}.${path.join("/")}`, (span) => {
span?.setAttribute("rpc.system", ORPC_NAME);
span?.setAttribute("rpc.method", path.join("."));
if (isAsyncIteratorObject(input)) {
input = override(input, traceAsyncIterator("consume_async_iterator_object_input", input));
}
return intercept(this.interceptors, { ...options, path, input }, async ({ path: path2, input: input2, ...options2 }) => {
const otel = getOpenTelemetryConfig();
let activeContext;
const activeSpan = otel?.trace.getActiveSpan() ?? span;
if (activeSpan && otel) {
activeContext = otel.trace.setSpan(otel.context.active(), activeSpan);
}
let request = await runWithSpan(
{ name: "encode_input", context: activeContext },
() => this.codec.encodeInput(input2, path2, options2)
);
if (activeContext && otel?.propagation) {
const headers = { ...request.headers };
otel.propagation.inject(activeContext, headers);
request = { ...request, headers };
}
const response = await intercept(
this.transportInterceptors,
{ ...options2, path: path2, request },
({ path: path3, request: request2, ...options3 }) => {
let activeTransportContext;
const activeTransportSpan = otel?.trace.getActiveSpan() ?? activeSpan;
if (activeTransportSpan && otel) {
activeTransportContext = otel.trace.setSpan(otel.context.active(), activeTransportSpan);
}
return runWithSpan(
{ name: "send_request", context: activeTransportContext },
() => this.transport.send(request2, path3, options3)
);
}
);
const decodedResult = await runWithSpan(
{ name: "decode_response", context: activeContext },
() => this.codec.decodeResponse(response, path2, options2)
);
if (decodedResult.kind === "error") {
throw decodedResult.error;
}
const output = decodedResult.output;
if (isAsyncIteratorObject(output)) {
return override(output, traceAsyncIterator("consume_async_iterator_object_output", output));
}
return output;
});
});
}
}
const END_SLASH_REGEX = /\/$/;
class RPCLinkCodec {
baseUrl;
maxUrlLength;
fallbackMethod;
expectedMethod;
headers;
serializer;
constructor(options) {
this.baseUrl = options.url ?? "/";
this.maxUrlLength = options.maxUrlLength ?? 2083;
this.fallbackMethod = options.fallbackMethod ?? "POST";
this.expectedMethod = options.method ?? this.fallbackMethod;
this.headers = options.headers ?? {};
this.serializer = options.serializer ?? new RPCSerializer();
}
async encodeInput(input, path, options) {
let headers = toResolvedStandardHeaders(await value(this.headers, options, path, input));
if (options.lastEventId !== void 0) {
headers = mergeStandardHeaders(headers, { "last-event-id": options.lastEventId });
}
const expectedMethod = await value(this.expectedMethod, options, path, input);
const baseUrl = await value(this.baseUrl, options, path, input);
const [pathname, search, hash] = parseStandardUrl(baseUrl);
const newPathname = `${pathname.replace(END_SLASH_REGEX, "")}${pathToHttpPath(path)}`;
const serialized = this.serializer.serialize(input);
if (expectedMethod === "GET" && !(serialized instanceof Blob) && !(serialized instanceof ReadableStream) && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
const maxUrlLength = await value(this.maxUrlLength, options, path, input);
const mergedSearch = new URLSearchParams(search);
mergedSearch.append("data", stringifyJSON(serialized) ?? "");
const url2 = `${newPathname}?${mergedSearch}${hash ?? ""}`;
if (url2.length <= maxUrlLength) {
return {
body: void 0,
method: expectedMethod,
headers,
url: url2,
signal: options.signal
};
}
}
const url = `${newPathname}${search ?? ""}${hash ?? ""}`;
return {
url,
method: expectedMethod === "GET" ? this.fallbackMethod : expectedMethod,
headers,
body: serialized,
signal: options.signal
};
}
async decodeResponse(response) {
const isOk = response.status < 400;
const body = await response.resolveBody();
const deserialized = await (async () => {
try {
return this.serializer.deserialize(body);
} catch (cause) {
throw new Error("Invalid RPC response format.", {
cause
});
}
})();
if (!isOk) {
if (isORPCErrorJson(deserialized)) {
return { kind: "error", error: createORPCErrorFromJson(deserialized) };
}
return {
kind: "error",
error: new ORPCError("MALFORMED_ORPC_ERROR_RESPONSE", {
data: { headers: response.headers, status: response.status, body: deserialized }
})
};
}
return { kind: "output", output: deserialized };
}
}
function toResolvedStandardHeaders(headers) {
if (typeof headers.forEach === "function") {
return toStandardHeaders(headers);
}
return headers;
}
export { CompositeStandardLinkPlugin as C, RPCLinkCodec as R, StandardLink as S };
import { StandardBody } from '@standardserver/core';
import { Segment } from '@orpc/shared';
type RPCJsonSerializationMeta = [type: string, ...path: Segment[]];
type RPCJsonSerialization = {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps?: undefined;
blobs?: undefined;
} | {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps: Segment[][];
blobs: Blob[];
};
interface RPCJsonSerializerHandler {
condition(value: unknown): boolean;
serialize(value: any): unknown;
deserialize(serialized: any): unknown;
/**
* If false, the result of this serializer will not be further processed by other serializers,
* even if it matches their conditions and treat it as final serialized value.
* This can be useful for serializers that return primitive values, which should not be further processed.
* to improve performance and avoid potential issues with other serializers.
*
* @default false
*/
isTerminal?: boolean;
}
interface RPCJsonSerializerOptions {
/**
* Extend or override the built-in type handlers used during serialization and deserialization.
*
* Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler
* that defines how to detect, serialize, and deserialize values of that type.
*
* **Extending:** Add new keys to support custom types:
* ```ts
* handlers: {
* buffer: {
* condition: (v) => v instanceof Buffer,
* serialize: (v: Buffer) => v.toString('base64'),
* deserialize: (s: string) => Buffer.from(s, 'base64'),
* isTerminal: true,
* }
* }
* ```
*
* **Overriding:** Use an existing key to replace a built-in handler:
* ```ts
* handlers: {
* date: {
* condition: (v) => v instanceof Date,
* serialize: (v: Date) => v.getTime(),
* deserialize: (n: number) => new Date(n),
* isTerminal: true,
* }
* }
* ```
*
* **Disabling:** Set a key to `undefined` to remove a built-in handler:
* ```ts
* handlers: { regexp: undefined }
* ```
*
* Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
*/
handlers?: Record<string, undefined | RPCJsonSerializerHandler> | undefined;
/**
* If true, properties with undefined values will be omitted during serialization.
*
* @default true
*/
omitUndefinedProperties?: boolean | undefined;
}
declare class RPCJsonSerializer {
private readonly handlers;
private readonly inlineBuiltInHandlers;
private readonly handlerEntries;
private readonly omitUndefinedProperties;
constructor(options?: RPCJsonSerializerOptions);
serialize(data: unknown): RPCJsonSerialization;
/**
* `segments` is a shared mutable stack (push/pop while walking),
* so it must be copied before being stored in `meta` or `maps`.
*/
private serializeValue;
deserialize(serialized: RPCJsonSerialization): unknown;
}
interface RPCSerializerSerializeOptions {
/**
* Use FormData for serialization when nested blobs are present.
* Does not apply to root-level Blob values.
*
* @default true
*/
useFormDataForBlobFields?: boolean;
}
interface RPCSerializerOptions extends RPCJsonSerializerOptions {
/**
* Default options for serialize method
*/
serialize?: RPCSerializerSerializeOptions | undefined;
}
declare class RPCSerializer {
private readonly jsonSerializer;
private readonly defaultSerializeOptions;
constructor(options?: RPCSerializerOptions);
serialize(data: unknown, options?: RPCSerializerSerializeOptions): StandardBody;
private serializeValue;
deserialize(data: StandardBody): unknown;
private deserializeValue;
}
export { RPCJsonSerializer as b, RPCSerializer as e };
export type { RPCJsonSerialization as R, RPCJsonSerializationMeta as a, RPCJsonSerializerHandler as c, RPCJsonSerializerOptions as d, RPCSerializerOptions as f, RPCSerializerSerializeOptions as g };
import { StandardBody } from '@standardserver/core';
import { Segment } from '@orpc/shared';
type RPCJsonSerializationMeta = [type: string, ...path: Segment[]];
type RPCJsonSerialization = {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps?: undefined;
blobs?: undefined;
} | {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps: Segment[][];
blobs: Blob[];
};
interface RPCJsonSerializerHandler {
condition(value: unknown): boolean;
serialize(value: any): unknown;
deserialize(serialized: any): unknown;
/**
* If false, the result of this serializer will not be further processed by other serializers,
* even if it matches their conditions and treat it as final serialized value.
* This can be useful for serializers that return primitive values, which should not be further processed.
* to improve performance and avoid potential issues with other serializers.
*
* @default false
*/
isTerminal?: boolean;
}
interface RPCJsonSerializerOptions {
/**
* Extend or override the built-in type handlers used during serialization and deserialization.
*
* Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler
* that defines how to detect, serialize, and deserialize values of that type.
*
* **Extending:** Add new keys to support custom types:
* ```ts
* handlers: {
* buffer: {
* condition: (v) => v instanceof Buffer,
* serialize: (v: Buffer) => v.toString('base64'),
* deserialize: (s: string) => Buffer.from(s, 'base64'),
* isTerminal: true,
* }
* }
* ```
*
* **Overriding:** Use an existing key to replace a built-in handler:
* ```ts
* handlers: {
* date: {
* condition: (v) => v instanceof Date,
* serialize: (v: Date) => v.getTime(),
* deserialize: (n: number) => new Date(n),
* isTerminal: true,
* }
* }
* ```
*
* **Disabling:** Set a key to `undefined` to remove a built-in handler:
* ```ts
* handlers: { regexp: undefined }
* ```
*
* Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
*/
handlers?: Record<string, undefined | RPCJsonSerializerHandler> | undefined;
/**
* If true, properties with undefined values will be omitted during serialization.
*
* @default true
*/
omitUndefinedProperties?: boolean | undefined;
}
declare class RPCJsonSerializer {
private readonly handlers;
private readonly inlineBuiltInHandlers;
private readonly handlerEntries;
private readonly omitUndefinedProperties;
constructor(options?: RPCJsonSerializerOptions);
serialize(data: unknown): RPCJsonSerialization;
/**
* `segments` is a shared mutable stack (push/pop while walking),
* so it must be copied before being stored in `meta` or `maps`.
*/
private serializeValue;
deserialize(serialized: RPCJsonSerialization): unknown;
}
interface RPCSerializerSerializeOptions {
/**
* Use FormData for serialization when nested blobs are present.
* Does not apply to root-level Blob values.
*
* @default true
*/
useFormDataForBlobFields?: boolean;
}
interface RPCSerializerOptions extends RPCJsonSerializerOptions {
/**
* Default options for serialize method
*/
serialize?: RPCSerializerSerializeOptions | undefined;
}
declare class RPCSerializer {
private readonly jsonSerializer;
private readonly defaultSerializeOptions;
constructor(options?: RPCSerializerOptions);
serialize(data: unknown, options?: RPCSerializerSerializeOptions): StandardBody;
private serializeValue;
deserialize(data: StandardBody): unknown;
private deserializeValue;
}
export { RPCJsonSerializer as b, RPCSerializer as e };
export type { RPCJsonSerialization as R, RPCJsonSerializationMeta as a, RPCJsonSerializerHandler as c, RPCJsonSerializerOptions as d, RPCSerializerOptions as f, RPCSerializerSerializeOptions as g };
import { isPlainObject, wrapAsyncIterator, isTypescriptObject, NullProtoObj, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
import { getEventMeta, withEventMeta, ErrorEvent } from '@standardserver/core';
import { O as ORPCError } from './client.Dnfj8jnT.mjs';
function isInferableError(error) {
return error instanceof ORPCError && error.inferable;
}
function toORPCError(error) {
return error instanceof ORPCError ? error : new ORPCError("INTERNAL_SERVER_ERROR", { cause: error });
}
function isORPCErrorJson(json) {
if (!isPlainObject(json)) {
return false;
}
const validKeys = ["defined", "inferable", "code", "message", "data"];
if (Object.keys(json).some((k) => !validKeys.includes(k))) {
return false;
}
return "defined" in json && typeof json.defined === "boolean" && "inferable" in json && typeof json.inferable === "boolean" && "code" in json && typeof json.code === "string" && "message" in json && typeof json.message === "string";
}
function createORPCErrorFromJson(json, options = {}) {
const error = new ORPCError(json.code, {
...json,
...options
});
error.defined = json.defined;
error.inferable = json.inferable;
return error;
}
function cloneORPCError(error) {
const cloned = new ORPCError(error.code, {
...error,
message: error.message,
data: error.data,
cause: error.cause
});
cloned.stack = error.stack;
cloned.defined = error.defined;
cloned.inferable = error.inferable;
return cloned;
}
function wrapAsyncIteratorPreservingEventMeta(iterator, { mapResult, mapError, ...rest }) {
return wrapAsyncIterator(iterator, {
...rest,
mapResult: mapResult && (async (result) => {
const mapped = await mapResult(result);
if (mapped.value !== result.value) {
const meta = getEventMeta(result.value);
if (meta && isTypescriptObject(mapped.value)) {
return { done: mapped.done, value: withEventMeta(mapped.value, meta) };
}
}
return mapped;
}),
mapError: mapError && (async (error) => {
const mapped = await mapError(error);
if (mapped !== error) {
const meta = getEventMeta(error);
if (meta && isTypescriptObject(mapped)) {
return withEventMeta(mapped, meta);
}
}
return mapped;
})
});
}
const REGEX_STRING_PATTERN = /^\/([\s\S]*)\/([a-z]*)$/;
const DEFAULT_RPC_JSON_SERIALIZER_HANDLERS = {
undefined: {
condition(data) {
return data === void 0;
},
serialize() {
return null;
},
deserialize() {
return void 0;
},
isTerminal: true
},
bigint: {
condition(data) {
return typeof data === "bigint";
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
return BigInt(serialized);
},
isTerminal: true
},
date: {
condition(data) {
return data instanceof Date;
},
serialize(data) {
if (Number.isNaN(data.getTime())) {
return null;
}
return data.toISOString();
},
deserialize(serialized) {
return new Date(serialized ?? "Invalid Date");
},
isTerminal: true
},
nan: {
condition(data) {
return typeof data === "number" && Number.isNaN(data);
},
serialize() {
return null;
},
deserialize() {
return Number.NaN;
},
isTerminal: true
},
url: {
condition(data) {
return data instanceof URL;
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
return new URL(serialized);
},
isTerminal: true
},
regexp: {
condition(data) {
return data instanceof RegExp;
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
const [, pattern, flags] = serialized.match(REGEX_STRING_PATTERN);
return new RegExp(pattern, flags);
},
isTerminal: true
},
set: {
condition(data) {
return data instanceof Set;
},
serialize(data) {
return Array.from(data);
},
deserialize(serialized) {
return new Set(serialized);
}
},
map: {
condition(data) {
return data instanceof Map;
},
serialize(data) {
return Array.from(data.entries());
},
deserialize(serialized) {
return new Map(serialized);
}
}
};
class RPCJsonSerializer {
handlers;
inlineBuiltInHandlers;
handlerEntries;
omitUndefinedProperties;
constructor(options = {}) {
this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
this.handlers = Object.assign(new NullProtoObj(), DEFAULT_RPC_JSON_SERIALIZER_HANDLERS);
const customHandlers = options.handlers;
if (customHandlers === void 0) {
this.inlineBuiltInHandlers = true;
return;
}
let inlineBuiltInHandlers = true;
let handlerEntries = [];
for (const key in customHandlers) {
const handler = customHandlers[key];
this.handlers[key] = handler;
if (inlineBuiltInHandlers && key in DEFAULT_RPC_JSON_SERIALIZER_HANDLERS) {
inlineBuiltInHandlers = false;
}
if (inlineBuiltInHandlers && handler !== void 0) {
handlerEntries.push([key, handler]);
}
}
if (!inlineBuiltInHandlers) {
handlerEntries = [];
for (const key in this.handlers) {
const handler = this.handlers[key];
if (handler !== void 0) {
handlerEntries.push([key, handler]);
}
}
}
this.inlineBuiltInHandlers = inlineBuiltInHandlers;
this.handlerEntries = handlerEntries;
}
serialize(data) {
let meta = [];
const maps = [];
const blobs = [];
const json = this.serializeValue(data, [], meta, maps, blobs);
meta = meta.length === 0 ? void 0 : meta;
if (maps.length === 0) {
return { json, meta };
}
return { json, meta, maps, blobs };
}
/**
* `segments` is a shared mutable stack (push/pop while walking),
* so it must be copied before being stored in `meta` or `maps`.
*/
serializeValue(data, segments, meta, maps, blobs) {
if (this.inlineBuiltInHandlers) {
switch (typeof data) {
case "string":
case "boolean":
return data;
case "number":
if (Number.isNaN(data)) {
meta.push(["nan", ...segments]);
return null;
}
return data;
case "undefined":
meta.push(["undefined", ...segments]);
return null;
case "bigint":
meta.push(["bigint", ...segments]);
return data.toString();
case "object": {
if (data === null) {
return data;
}
if (data instanceof Date) {
meta.push(["date", ...segments]);
return Number.isNaN(data.getTime()) ? null : data.toISOString();
}
if (data instanceof URL) {
meta.push(["url", ...segments]);
return data.toString();
}
if (data instanceof RegExp) {
meta.push(["regexp", ...segments]);
return data.toString();
}
if (data instanceof Set) {
const result = this.serializeValue(Array.from(data), segments, meta, maps, blobs);
meta.push(["set", ...segments]);
return result;
}
if (data instanceof Map) {
const result = this.serializeValue(Array.from(data.entries()), segments, meta, maps, blobs);
meta.push(["map", ...segments]);
return result;
}
}
}
}
const handlerEntries = this.handlerEntries;
if (handlerEntries) {
for (let i = 0; i < handlerEntries.length; i++) {
const entry = handlerEntries[i];
const handler = entry[1];
if (handler.condition(data)) {
const serialized = handler.serialize(data);
if (handler.isTerminal) {
meta.push([entry[0], ...segments]);
if (serialized instanceof Blob) {
maps.push(segments.slice());
blobs.push(serialized);
}
return serialized;
}
const result = this.serializeValue(serialized, segments, meta, maps, blobs);
meta.push([entry[0], ...segments]);
return result;
}
}
}
if (data instanceof Blob) {
maps.push(segments.slice());
blobs.push(data);
return data;
}
if (Array.isArray(data)) {
const json = [];
for (let i = 0; i < data.length; i++) {
segments.push(i);
json.push(this.serializeValue(data[i], segments, meta, maps, blobs));
segments.pop();
}
return json;
}
if (isPlainObject(data)) {
const json = new NullProtoObj();
for (const k in data) {
const v = data[k];
if (k === "toJSON" && typeof v === "function") {
continue;
}
if (v === void 0 && this.omitUndefinedProperties) {
continue;
}
segments.push(k);
json[k] = this.serializeValue(v, segments, meta, maps, blobs);
segments.pop();
}
return json;
}
return data;
}
deserialize(serialized) {
const ref = { data: serialized.json };
if (serialized.blobs?.length) {
for (let i = 0; i < serialized.maps.length; i++) {
const segments = serialized.maps[i];
let currentRef = ref;
let preSegment = "data";
for (let j = 0; j < segments.length; j++) {
currentRef = currentRef[preSegment];
preSegment = segments[j];
if (!Object.hasOwn(currentRef, preSegment)) {
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
}
}
currentRef[preSegment] = serialized.blobs[i];
}
}
if (serialized.meta) {
for (const item of serialized.meta) {
const type = item[0];
let currentRef = ref;
let preSegment = "data";
for (let i = 1; i < item.length; i++) {
currentRef = currentRef[preSegment];
preSegment = item[i];
if (!Object.hasOwn(currentRef, preSegment)) {
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
}
}
currentRef[preSegment] = this.handlers[type].deserialize(currentRef[preSegment]);
}
}
return ref.data;
}
}
class RPCSerializer {
jsonSerializer;
defaultSerializeOptions;
constructor(options = {}) {
this.jsonSerializer = new RPCJsonSerializer(options);
this.defaultSerializeOptions = options.serialize;
}
serialize(data, options = {}) {
if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
return data;
}
if (isAsyncIteratorObject(data)) {
return wrapAsyncIteratorPreservingEventMeta(data, {
mapResult: (result) => {
if (result.value === void 0) {
return result;
}
return { done: result.done, value: this.serializeValue(result.value, false) };
},
mapError: (e) => new ErrorEvent(
this.serializeValue(toORPCError(e).toJSON(), false),
{ cause: e }
)
});
}
const useFormDataForBlobs = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
return this.serializeValue(data, useFormDataForBlobs);
}
serializeValue(data, useFormDataForBlobs) {
const { json, meta, maps, blobs } = this.jsonSerializer.serialize(data);
if (!useFormDataForBlobs || !blobs?.length) {
return { json, meta };
}
const form = new FormData();
form.set("data", stringifyJSON({ json, meta, maps }));
blobs.forEach((blob, i) => {
form.set(i.toString(), blob);
});
return form;
}
deserialize(data) {
if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
return data;
}
if (isAsyncIteratorObject(data)) {
return wrapAsyncIteratorPreservingEventMeta(data, {
mapResult: (result) => {
if (result.value === void 0) {
return result;
}
return { done: result.done, value: this.deserializeValue(result.value) };
},
mapError: (e) => {
if (!(e instanceof ErrorEvent)) {
return e;
}
const deserialized = this.deserializeValue(e.data);
if (isORPCErrorJson(deserialized)) {
return createORPCErrorFromJson(deserialized, { cause: e });
}
return new ErrorEvent(deserialized, { cause: e });
}
});
}
return this.deserializeValue(data);
}
deserializeValue(data) {
if (!(data instanceof FormData)) {
return this.jsonSerializer.deserialize(data);
}
const serialized = JSON.parse(data.get("data"));
const blobs = [];
for (const [key, value] of data) {
if (value instanceof Blob) {
blobs[Number(key)] = value;
}
}
return this.jsonSerializer.deserialize({ ...serialized, blobs });
}
}
export { RPCSerializer as R, isInferableError as a, RPCJsonSerializer as b, createORPCErrorFromJson as c, cloneORPCError as d, isORPCErrorJson as i, toORPCError as t, wrapAsyncIteratorPreservingEventMeta as w };
+1
-1

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.mjs';

import { RPCLinkCodecOptions } from '../standard/index.mjs';
import '../../shared/client.BdItY5DT.mjs';
import '../../shared/client.Dlxz9Qw5.mjs';

@@ -10,0 +10,0 @@ interface FetchLinkTransportFetchInterceptorOptions<T extends ClientContext> extends ClientOptions<T> {

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.js';

import { RPCLinkCodecOptions } from '../standard/index.js';
import '../../shared/client.BdItY5DT.js';
import '../../shared/client.Dlxz9Qw5.js';

@@ -10,0 +10,0 @@ interface FetchLinkTransportFetchInterceptorOptions<T extends ClientContext> extends ClientOptions<T> {

import { sortPlugins, value, intercept, once } from '@orpc/shared';
import { toFetchBody, toFetchHeaders, toStandardLazyResponse } from '@standardserver/fetch';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.BRJnOJ0R.mjs';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bl4junIW.mjs';
import '@standardserver/core';
import '../../shared/client.Dnfj8jnT.mjs';
import '../../shared/client.DqYwRDUO.mjs';
import '../../shared/client.DQpq_Sdn.mjs';

@@ -8,0 +8,0 @@ class CompositeFetchLinkTransportPlugin {

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.mjs';

import { RPCLinkCodecOptions } from '../standard/index.mjs';
import '../../shared/client.BdItY5DT.mjs';
import '../../shared/client.Dlxz9Qw5.mjs';

@@ -10,0 +10,0 @@ /**

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.js';

import { RPCLinkCodecOptions } from '../standard/index.js';
import '../../shared/client.BdItY5DT.js';
import '../../shared/client.Dlxz9Qw5.js';

@@ -10,0 +10,0 @@ /**

import { value } from '@orpc/shared';
import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage, isPeerMessage } from '@standardserver/peer';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.BRJnOJ0R.mjs';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bl4junIW.mjs';
import '@standardserver/core';
import '@standardserver/fetch';
import '../../shared/client.Dnfj8jnT.mjs';
import '../../shared/client.DqYwRDUO.mjs';
import '../../shared/client.DQpq_Sdn.mjs';

@@ -9,0 +9,0 @@ function postMessagePortMessage(port, data, transfer) {

@@ -7,3 +7,3 @@ import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.8f4DNmdE.mjs';

import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.mjs';
import { e as RPCSerializer } from '../../shared/client.BdItY5DT.mjs';
import { e as RPCSerializer } from '../../shared/client.Dlxz9Qw5.mjs';

@@ -10,0 +10,0 @@ interface RPCLinkCodecOptions<T extends ClientContext> {

@@ -7,3 +7,3 @@ import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.BMKYqpdy.js';

import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.js';
import { e as RPCSerializer } from '../../shared/client.BdItY5DT.js';
import { e as RPCSerializer } from '../../shared/client.Dlxz9Qw5.js';

@@ -10,0 +10,0 @@ interface RPCLinkCodecOptions<T extends ClientContext> {

@@ -1,2 +0,2 @@

export { C as CompositeStandardLinkPlugin, R as RPCLinkCodec, S as StandardLink } from '../../shared/client.BRJnOJ0R.mjs';
export { C as CompositeStandardLinkPlugin, R as RPCLinkCodec, S as StandardLink } from '../../shared/client.Bl4junIW.mjs';
import '@orpc/shared';

@@ -6,2 +6,2 @@ import '@standardserver/core';

import '../../shared/client.Dnfj8jnT.mjs';
import '../../shared/client.DqYwRDUO.mjs';
import '../../shared/client.DQpq_Sdn.mjs';

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.mjs';

import { RPCLinkCodecOptions } from '../standard/index.mjs';
import '../../shared/client.BdItY5DT.mjs';
import '../../shared/client.Dlxz9Qw5.mjs';

@@ -10,0 +10,0 @@ type WebSocketLike = Pick<WebSocket, 'addEventListener' | 'removeEventListener' | 'send' | 'readyState'>;

@@ -7,3 +7,3 @@ import { C as ClientContext, a as ClientOptions } from '../../shared/client.BBZBQID8.js';

import { RPCLinkCodecOptions } from '../standard/index.js';
import '../../shared/client.BdItY5DT.js';
import '../../shared/client.Dlxz9Qw5.js';

@@ -10,0 +10,0 @@ type WebSocketLike = Pick<WebSocket, 'addEventListener' | 'removeEventListener' | 'send' | 'readyState'>;

import { runWithSignal, AbortError, sleep, promiseWithResolvers, sequential, loadBytes, toStringOrBytes } from '@orpc/shared';
import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage } from '@standardserver/peer';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.BRJnOJ0R.mjs';
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bl4junIW.mjs';
import '@standardserver/core';
import '@standardserver/fetch';
import '../../shared/client.Dnfj8jnT.mjs';
import '../../shared/client.DqYwRDUO.mjs';
import '../../shared/client.DQpq_Sdn.mjs';

@@ -9,0 +9,0 @@ const WEBSOCKET_CONNECTING = 0;

@@ -5,3 +5,3 @@ import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';

export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, N as NestedClient, p as ORPCErrorOptions } from './shared/client.BBZBQID8.mjs';
export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.BdItY5DT.mjs';
export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.Dlxz9Qw5.mjs';
export { ErrorEvent, EventMeta, getEventMeta, unwrapEvent, withEventMeta } from '@standardserver/core';

@@ -8,0 +8,0 @@

@@ -5,3 +5,3 @@ import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';

export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, N as NestedClient, p as ORPCErrorOptions } from './shared/client.BBZBQID8.js';
export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.BdItY5DT.js';
export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.Dlxz9Qw5.js';
export { ErrorEvent, EventMeta, getEventMeta, unwrapEvent, withEventMeta } from '@standardserver/core';

@@ -8,0 +8,0 @@

@@ -1,3 +0,3 @@

import { a as isInferableError } from './shared/client.DqYwRDUO.mjs';
export { b as RPCJsonSerializer, R as RPCSerializer, d as cloneORPCError, c as createORPCErrorFromJson, i as isORPCErrorJson, t as toORPCError, w as wrapAsyncIteratorPreservingEventMeta } from './shared/client.DqYwRDUO.mjs';
import { a as isInferableError } from './shared/client.DQpq_Sdn.mjs';
export { b as RPCJsonSerializer, R as RPCSerializer, d as cloneORPCError, c as createORPCErrorFromJson, i as isORPCErrorJson, t as toORPCError, w as wrapAsyncIteratorPreservingEventMeta } from './shared/client.DQpq_Sdn.mjs';
import { getOrBind, toArray, intercept, isTypescriptObject } from '@orpc/shared';

@@ -4,0 +4,0 @@ export { AsyncIteratorClass, asyncIteratorToStream, asyncIteratorToUnproxiedDataStream, consumeAsyncIterator, consumeAsyncIterator as consumeEventIterator, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onAsyncIteratorObjectError, onError, onFinish, onReadableStreamError, onStart, onSuccess, streamToAsyncIteratorObject, streamToAsyncIteratorObject as streamToEventIterator } from '@orpc/shared';

{
"name": "@orpc/client",
"type": "module",
"version": "2.0.0-beta.21",
"version": "2.0.0-beta.22",
"license": "MIT",

@@ -53,6 +53,6 @@ "homepage": "https://orpc.dev",

"dependencies": {
"@standardserver/core": "^0.5.0",
"@standardserver/fetch": "^0.5.0",
"@standardserver/peer": "^0.5.0",
"@orpc/shared": "2.0.0-beta.21"
"@standardserver/core": "^0.6.0",
"@standardserver/fetch": "^0.6.0",
"@standardserver/peer": "^0.6.0",
"@orpc/shared": "2.0.0-beta.22"
},

@@ -59,0 +59,0 @@ "devDependencies": {

@@ -112,7 +112,6 @@ <h1 align="center">oRPC - Typesafe APIs Made Simple 🪄</h1>

<td align="center"><a href="https://github.com/K-Mistele?ref=orpc" target="_blank" rel="noopener" title="Kyle Mistele"><img src="https://avatars.githubusercontent.com/u/18430555?u=3afebeb81de666e35aaac3ed46f14159d7603ffb&amp;v=4" width="139" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
<td align="center"><a href="https://github.com/R44VC0RP?ref=orpc" target="_blank" rel="noopener" title="Ryan Vogel"><img src="https://avatars.githubusercontent.com/u/89211796?u=1857347b9787d8d8a7ea5bfc333f96be92d5a683&amp;v=4" width="139" alt="Ryan Vogel"/><br />Ryan Vogel</a></td>
<td align="center"><a href="https://github.com/christ12938?ref=orpc" target="_blank" rel="noopener" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="139" alt="christ12938"/><br />christ12938</a></td>
<td align="center"><a href="https://github.com/Ryanjso?ref=orpc" target="_blank" rel="noopener" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&amp;v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Ryanjso?ref=orpc" target="_blank" rel="noopener" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&amp;v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
<td align="center"><a href="https://github.com/itigoore01?ref=orpc" target="_blank" rel="noopener" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&amp;v=4" width="139" alt="shota"/><br />shota</a></td>

@@ -127,3 +126,2 @@ </tr>

<td align="center"><a href="https://github.com/rhinodavid?ref=orpc" target="_blank" rel="noopener" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&amp;v=4" width="119" alt="David Walsh"/><br />David Walsh</a></td>
<td align="center"><a href="https://github.com/Nic13Gamer?ref=orpc" target="_blank" rel="noopener" title="Nicholas"><img src="https://avatars.githubusercontent.com/u/54724556?u=56a7ab430ce7a80d648ab6eba051d454a818ed0b&amp;v=4" width="119" alt="Nicholas"/><br />Nicholas</a></td>
<td align="center"><a href="https://github.com/Robbe95?ref=orpc" target="_blank" rel="noopener" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&amp;v=4" width="119" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>

@@ -134,5 +132,5 @@ <td align="center"><a href="https://github.com/aidansunbury?ref=orpc" target="_blank" rel="noopener" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="119" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>

<td align="center"><a href="https://github.com/pumpkinlink?ref=orpc" target="_blank" rel="noopener" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&amp;v=4" width="119" alt="Denis"/><br />Denis</a></td>
<td align="center"><a href="https://github.com/christopher-kapic?ref=orpc" target="_blank" rel="noopener" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&amp;v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/christopher-kapic?ref=orpc" target="_blank" rel="noopener" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&amp;v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
<td align="center"><a href="https://github.com/thomasballinger?ref=orpc" target="_blank" rel="noopener" title="Tom Ballinger"><img src="https://avatars.githubusercontent.com/u/458879?u=4b045ac75d721b6ac2b42a74d7d37f61f0414031&amp;v=4" width="119" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>

@@ -144,5 +142,5 @@ <td align="center"><a href="https://github.com/SSam0419?ref=orpc" target="_blank" rel="noopener" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&amp;v=4" width="119" alt="Sam"/><br />Sam</a></td>

<td align="center"><a href="https://github.com/ldub?ref=orpc" target="_blank" rel="noopener" title="Lev Dubinets"><img src="https://avatars.githubusercontent.com/u/3114081?u=f547f5d5012cab54851f1b1ad72d10e537f78fc2&amp;v=4" width="119" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
<td align="center"><a href="https://github.com/mr-kelly?ref=orpc" target="_blank" rel="noopener" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/mr-kelly?ref=orpc" target="_blank" rel="noopener" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
<td align="center"><a href="https://github.com/piscis?ref=orpc" target="_blank" rel="noopener" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&amp;v=4" width="119" alt="Alex"/><br />Alex</a></td>

@@ -180,2 +178,3 @@ <td align="center"><a href="https://github.com/finom?ref=orpc" target="_blank" rel="noopener" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=29e91400dbd4a9c217048a8f59562c4f740498e6&amp;v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>

<a href="https://github.com/andrewpeters9?ref=orpc" target="_blank" rel="noopener" title="Andrew Peters"><img src="https://avatars.githubusercontent.com/u/36251325?v=4" width="32" height="32" alt="Andrew Peters" /></a>
<a href="https://github.com/R44VC0RP?ref=orpc" target="_blank" rel="noopener" title="Ryan Vogel"><img src="https://avatars.githubusercontent.com/u/89211796?u=1857347b9787d8d8a7ea5bfc333f96be92d5a683&amp;v=4" width="32" height="32" alt="Ryan Vogel" /></a>
<a href="https://github.com/SKostyukovich?ref=orpc" target="_blank" rel="noopener" title="SKostyukovich"><img src="https://avatars.githubusercontent.com/u/10700067?v=4" width="32" height="32" alt="SKostyukovich" /></a>

@@ -193,2 +192,3 @@ <a href="https://github.com/peter-adam-dy?ref=orpc" target="_blank" rel="noopener" title="Peter Adam"><img src="https://avatars.githubusercontent.com/u/132129459?u=4f3dbbb3b443990b56acb7d6a5d11ed2c555f6db&amp;v=4" width="32" height="32" alt="Peter Adam" /></a>

<a href="https://github.com/plancraft?ref=orpc" target="_blank" rel="noopener" title="plancraft"><img src="https://avatars.githubusercontent.com/u/46482287?v=4" width="32" height="32" alt="plancraft" /></a>
<a href="https://github.com/Nic13Gamer?ref=orpc" target="_blank" rel="noopener" title="Nicholas"><img src="https://avatars.githubusercontent.com/u/54724556?u=56a7ab430ce7a80d648ab6eba051d454a818ed0b&amp;v=4" width="32" height="32" alt="Nicholas" /></a>
</p>

@@ -195,0 +195,0 @@

import { StandardBody } from '@standardserver/core';
import { Segment } from '@orpc/shared';
type RPCJsonSerializationMeta = [type: string, ...path: Segment[]];
type RPCJsonSerialization = {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps?: undefined;
blobs?: undefined;
} | {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps: Segment[][];
blobs: Blob[];
};
interface RPCJsonSerializerHandler {
condition(value: unknown): boolean;
serialize(value: any): unknown;
deserialize(serialized: any): unknown;
/**
* If false, the result of this serializer will not be further processed by other serializers,
* even if it matches their conditions and treat it as final serialized value.
* This can be useful for serializers that return primitive values, which should not be further processed.
* to improve performance and avoid potential issues with other serializers.
*
* @default false
*/
isTerminal?: boolean;
}
interface RPCJsonSerializerOptions {
/**
* Extend or override the built-in type handlers used during serialization and deserialization.
*
* Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler
* that defines how to detect, serialize, and deserialize values of that type.
*
* **Extending:** Add new keys to support custom types:
* ```ts
* handlers: {
* buffer: {
* condition: (v) => v instanceof Buffer,
* serialize: (v: Buffer) => v.toString('base64'),
* deserialize: (s: string) => Buffer.from(s, 'base64'),
* isTerminal: true,
* }
* }
* ```
*
* **Overriding:** Use an existing key to replace a built-in handler:
* ```ts
* handlers: {
* date: {
* condition: (v) => v instanceof Date,
* serialize: (v: Date) => v.getTime(),
* deserialize: (n: number) => new Date(n),
* isTerminal: true,
* }
* }
* ```
*
* **Disabling:** Set a key to `undefined` to remove a built-in handler:
* ```ts
* handlers: { regexp: undefined }
* ```
*
* Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
*/
handlers?: Record<string, undefined | RPCJsonSerializerHandler> | undefined;
/**
* If true, properties with undefined values will be omitted during serialization.
*
* @default true
*/
omitUndefinedProperties?: boolean | undefined;
}
declare class RPCJsonSerializer {
private readonly handlers;
private readonly omitUndefinedProperties;
constructor(options?: RPCJsonSerializerOptions);
serialize(data: unknown): RPCJsonSerialization;
private serializeValue;
deserialize(serialized: RPCJsonSerialization): unknown;
}
interface RPCSerializerSerializeOptions {
/**
* Use FormData for serialization when nested blobs are present.
* Does not apply to root-level Blob values.
*
* @default true
*/
useFormDataForBlobFields?: boolean;
}
interface RPCSerializerOptions extends RPCJsonSerializerOptions {
/**
* Default options for serialize method
*/
serialize?: RPCSerializerSerializeOptions | undefined;
}
declare class RPCSerializer {
private readonly jsonSerializer;
private readonly defaultSerializeOptions;
constructor(options?: RPCSerializerOptions);
serialize(data: unknown, options?: RPCSerializerSerializeOptions): StandardBody;
private serializeValue;
deserialize(data: StandardBody): unknown;
private deserializeValue;
}
export { RPCJsonSerializer as b, RPCSerializer as e };
export type { RPCJsonSerialization as R, RPCJsonSerializationMeta as a, RPCJsonSerializerHandler as c, RPCJsonSerializerOptions as d, RPCSerializerOptions as f, RPCSerializerSerializeOptions as g };
import { StandardBody } from '@standardserver/core';
import { Segment } from '@orpc/shared';
type RPCJsonSerializationMeta = [type: string, ...path: Segment[]];
type RPCJsonSerialization = {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps?: undefined;
blobs?: undefined;
} | {
json: unknown;
meta?: RPCJsonSerializationMeta[] | undefined;
maps: Segment[][];
blobs: Blob[];
};
interface RPCJsonSerializerHandler {
condition(value: unknown): boolean;
serialize(value: any): unknown;
deserialize(serialized: any): unknown;
/**
* If false, the result of this serializer will not be further processed by other serializers,
* even if it matches their conditions and treat it as final serialized value.
* This can be useful for serializers that return primitive values, which should not be further processed.
* to improve performance and avoid potential issues with other serializers.
*
* @default false
*/
isTerminal?: boolean;
}
interface RPCJsonSerializerOptions {
/**
* Extend or override the built-in type handlers used during serialization and deserialization.
*
* Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler
* that defines how to detect, serialize, and deserialize values of that type.
*
* **Extending:** Add new keys to support custom types:
* ```ts
* handlers: {
* buffer: {
* condition: (v) => v instanceof Buffer,
* serialize: (v: Buffer) => v.toString('base64'),
* deserialize: (s: string) => Buffer.from(s, 'base64'),
* isTerminal: true,
* }
* }
* ```
*
* **Overriding:** Use an existing key to replace a built-in handler:
* ```ts
* handlers: {
* date: {
* condition: (v) => v instanceof Date,
* serialize: (v: Date) => v.getTime(),
* deserialize: (n: number) => new Date(n),
* isTerminal: true,
* }
* }
* ```
*
* **Disabling:** Set a key to `undefined` to remove a built-in handler:
* ```ts
* handlers: { regexp: undefined }
* ```
*
* Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
*/
handlers?: Record<string, undefined | RPCJsonSerializerHandler> | undefined;
/**
* If true, properties with undefined values will be omitted during serialization.
*
* @default true
*/
omitUndefinedProperties?: boolean | undefined;
}
declare class RPCJsonSerializer {
private readonly handlers;
private readonly omitUndefinedProperties;
constructor(options?: RPCJsonSerializerOptions);
serialize(data: unknown): RPCJsonSerialization;
private serializeValue;
deserialize(serialized: RPCJsonSerialization): unknown;
}
interface RPCSerializerSerializeOptions {
/**
* Use FormData for serialization when nested blobs are present.
* Does not apply to root-level Blob values.
*
* @default true
*/
useFormDataForBlobFields?: boolean;
}
interface RPCSerializerOptions extends RPCJsonSerializerOptions {
/**
* Default options for serialize method
*/
serialize?: RPCSerializerSerializeOptions | undefined;
}
declare class RPCSerializer {
private readonly jsonSerializer;
private readonly defaultSerializeOptions;
constructor(options?: RPCSerializerOptions);
serialize(data: unknown, options?: RPCSerializerSerializeOptions): StandardBody;
private serializeValue;
deserialize(data: StandardBody): unknown;
private deserializeValue;
}
export { RPCJsonSerializer as b, RPCSerializer as e };
export type { RPCJsonSerialization as R, RPCJsonSerializationMeta as a, RPCJsonSerializerHandler as c, RPCJsonSerializerOptions as d, RPCSerializerOptions as f, RPCSerializerSerializeOptions as g };
import { sortPlugins, runWithSpan, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, intercept, getOpenTelemetryConfig, value, pathToHttpPath, stringifyJSON } from '@orpc/shared';
import { mergeStandardHeaders, parseStandardUrl } from '@standardserver/core';
import { toStandardHeaders } from '@standardserver/fetch';
import { O as ORPCError } from './client.Dnfj8jnT.mjs';
import { R as RPCSerializer, i as isORPCErrorJson, c as createORPCErrorFromJson } from './client.DqYwRDUO.mjs';
class CompositeStandardLinkPlugin {
name = "~composite";
plugins;
constructor(plugins = []) {
this.plugins = sortPlugins(plugins);
}
init(options) {
for (const plugin of this.plugins) {
if (plugin.init) {
options = plugin.init(options);
}
}
return options;
}
}
class StandardLink {
constructor(codec, transport, options = {}) {
this.codec = codec;
this.transport = transport;
options = new CompositeStandardLinkPlugin(options.plugins).init(options);
this.interceptors = options.interceptors;
this.transportInterceptors = options.transportInterceptors;
}
interceptors;
transportInterceptors;
/**
* @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
*/
call(path, input, options) {
return runWithSpan(`${ORPC_NAME}.${path.join("/")}`, (span) => {
span?.setAttribute("rpc.system", ORPC_NAME);
span?.setAttribute("rpc.method", path.join("."));
if (isAsyncIteratorObject(input)) {
input = override(input, traceAsyncIterator("consume_async_iterator_object_input", input));
}
return intercept(this.interceptors, { ...options, path, input }, async ({ path: path2, input: input2, ...options2 }) => {
const otel = getOpenTelemetryConfig();
let activeContext;
const activeSpan = otel?.trace.getActiveSpan() ?? span;
if (activeSpan && otel) {
activeContext = otel.trace.setSpan(otel.context.active(), activeSpan);
}
let request = await runWithSpan(
{ name: "encode_input", context: activeContext },
() => this.codec.encodeInput(input2, path2, options2)
);
if (activeContext && otel?.propagation) {
const headers = { ...request.headers };
otel.propagation.inject(activeContext, headers);
request = { ...request, headers };
}
const response = await intercept(
this.transportInterceptors,
{ ...options2, path: path2, request },
({ path: path3, request: request2, ...options3 }) => {
let activeTransportContext;
const activeTransportSpan = otel?.trace.getActiveSpan() ?? activeSpan;
if (activeTransportSpan && otel) {
activeTransportContext = otel.trace.setSpan(otel.context.active(), activeTransportSpan);
}
return runWithSpan(
{ name: "send_request", context: activeTransportContext },
() => this.transport.send(request2, path3, options3)
);
}
);
const decodedResult = await runWithSpan(
{ name: "decode_response", context: activeContext },
() => this.codec.decodeResponse(response, path2, options2)
);
if (decodedResult.kind === "error") {
throw decodedResult.error;
}
const output = decodedResult.output;
if (isAsyncIteratorObject(output)) {
return override(output, traceAsyncIterator("consume_async_iterator_object_output", output));
}
return output;
});
});
}
}
const END_SLASH_REGEX = /\/$/;
class RPCLinkCodec {
baseUrl;
maxUrlLength;
fallbackMethod;
expectedMethod;
headers;
serializer;
constructor(options) {
this.baseUrl = options.url ?? "/";
this.maxUrlLength = options.maxUrlLength ?? 2083;
this.fallbackMethod = options.fallbackMethod ?? "POST";
this.expectedMethod = options.method ?? this.fallbackMethod;
this.headers = options.headers ?? {};
this.serializer = options.serializer ?? new RPCSerializer();
}
async encodeInput(input, path, options) {
let headers = toResolvedStandardHeaders(await value(this.headers, options, path, input));
if (options.lastEventId !== void 0) {
headers = mergeStandardHeaders(headers, { "last-event-id": options.lastEventId });
}
const expectedMethod = await value(this.expectedMethod, options, path, input);
const baseUrl = await value(this.baseUrl, options, path, input);
const [pathname, search, hash] = parseStandardUrl(baseUrl);
const newPathname = `${pathname.replace(END_SLASH_REGEX, "")}${pathToHttpPath(path)}`;
const serialized = this.serializer.serialize(input);
if (expectedMethod === "GET" && !(serialized instanceof Blob) && !(serialized instanceof ReadableStream) && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
const maxUrlLength = await value(this.maxUrlLength, options, path, input);
const mergedSearch = new URLSearchParams(search);
mergedSearch.append("data", stringifyJSON(serialized) ?? "");
const url2 = `${newPathname}?${mergedSearch}${hash ?? ""}`;
if (url2.length <= maxUrlLength) {
return {
body: void 0,
method: expectedMethod,
headers,
url: url2,
signal: options.signal
};
}
}
const url = `${newPathname}${search ?? ""}${hash ?? ""}`;
return {
url,
method: expectedMethod === "GET" ? this.fallbackMethod : expectedMethod,
headers,
body: serialized,
signal: options.signal
};
}
async decodeResponse(response) {
const isOk = response.status < 400;
const body = await response.resolveBody();
const deserialized = await (async () => {
try {
return this.serializer.deserialize(body);
} catch (cause) {
throw new Error("Invalid RPC response format.", {
cause
});
}
})();
if (!isOk) {
if (isORPCErrorJson(deserialized)) {
return { kind: "error", error: createORPCErrorFromJson(deserialized) };
}
return {
kind: "error",
error: new ORPCError("MALFORMED_ORPC_ERROR_RESPONSE", {
data: { headers: response.headers, status: response.status, body: deserialized }
})
};
}
return { kind: "output", output: deserialized };
}
}
function toResolvedStandardHeaders(headers) {
if (typeof headers.forEach === "function") {
return toStandardHeaders(headers);
}
return headers;
}
export { CompositeStandardLinkPlugin as C, RPCLinkCodec as R, StandardLink as S };
import { isPlainObject, wrapAsyncIterator, isTypescriptObject, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
import { getEventMeta, withEventMeta, ErrorEvent } from '@standardserver/core';
import { O as ORPCError } from './client.Dnfj8jnT.mjs';
function isInferableError(error) {
return error instanceof ORPCError && error.inferable;
}
function toORPCError(error) {
return error instanceof ORPCError ? error : new ORPCError("INTERNAL_SERVER_ERROR", { cause: error });
}
function isORPCErrorJson(json) {
if (!isPlainObject(json)) {
return false;
}
const validKeys = ["defined", "inferable", "code", "message", "data"];
if (Object.keys(json).some((k) => !validKeys.includes(k))) {
return false;
}
return "defined" in json && typeof json.defined === "boolean" && "inferable" in json && typeof json.inferable === "boolean" && "code" in json && typeof json.code === "string" && "message" in json && typeof json.message === "string";
}
function createORPCErrorFromJson(json, options = {}) {
const error = new ORPCError(json.code, {
...json,
...options
});
error.defined = json.defined;
error.inferable = json.inferable;
return error;
}
function cloneORPCError(error) {
const cloned = new ORPCError(error.code, {
...error,
message: error.message,
data: error.data,
cause: error.cause
});
cloned.stack = error.stack;
cloned.defined = error.defined;
cloned.inferable = error.inferable;
return cloned;
}
function wrapAsyncIteratorPreservingEventMeta(iterator, { mapResult, mapError, ...rest }) {
return wrapAsyncIterator(iterator, {
...rest,
mapResult: mapResult && (async (result) => {
const mapped = await mapResult(result);
if (mapped.value !== result.value) {
const meta = getEventMeta(result.value);
if (meta && isTypescriptObject(mapped.value)) {
return { done: mapped.done, value: withEventMeta(mapped.value, meta) };
}
}
return mapped;
}),
mapError: mapError && (async (error) => {
const mapped = await mapError(error);
if (mapped !== error) {
const meta = getEventMeta(error);
if (meta && isTypescriptObject(mapped)) {
return withEventMeta(mapped, meta);
}
}
return mapped;
})
});
}
const REGEX_STRING_PATTERN = /^\/(.*)\/([a-z]*)$/;
const DEFAULT_RPC_JSON_SERIALIZER_HANDLERS = {
undefined: {
condition(data) {
return data === void 0;
},
serialize() {
return null;
},
deserialize() {
return void 0;
},
isTerminal: true
},
bigint: {
condition(data) {
return typeof data === "bigint";
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
return BigInt(serialized);
},
isTerminal: true
},
date: {
condition(data) {
return data instanceof Date;
},
serialize(data) {
if (Number.isNaN(data.getTime())) {
return null;
}
return data.toISOString();
},
deserialize(serialized) {
return new Date(serialized ?? "Invalid Date");
},
isTerminal: true
},
nan: {
condition(data) {
return typeof data === "number" && Number.isNaN(data);
},
serialize() {
return null;
},
deserialize() {
return Number.NaN;
},
isTerminal: true
},
url: {
condition(data) {
return data instanceof URL;
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
return new URL(serialized);
},
isTerminal: true
},
regexp: {
condition(data) {
return data instanceof RegExp;
},
serialize(data) {
return data.toString();
},
deserialize(serialized) {
const [, pattern, flags] = serialized.match(REGEX_STRING_PATTERN);
return new RegExp(pattern, flags);
},
isTerminal: true
},
set: {
condition(data) {
return data instanceof Set;
},
serialize(data) {
return Array.from(data);
},
deserialize(serialized) {
return new Set(serialized);
}
},
map: {
condition(data) {
return data instanceof Map;
},
serialize(data) {
return Array.from(data.entries());
},
deserialize(serialized) {
return new Map(serialized);
}
}
};
class RPCJsonSerializer {
handlers;
omitUndefinedProperties;
constructor(options = {}) {
this.handlers = {
...DEFAULT_RPC_JSON_SERIALIZER_HANDLERS,
...options.handlers
};
this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
}
serialize(data) {
const [json, meta_, maps, blobs] = this.serializeValue(data, [], [], [], []);
const meta = meta_.length === 0 ? void 0 : meta_;
if (maps.length === 0) {
return { json, meta };
}
return { json, meta, maps, blobs };
}
serializeValue(data, segments, meta, maps, blobs) {
for (const key in this.handlers) {
const handler = this.handlers[key];
if (handler && handler.condition(data)) {
const serialized = handler.serialize(data);
if (handler.isTerminal) {
meta.push([key, ...segments]);
return [serialized, meta, maps, blobs];
}
const result = this.serializeValue(serialized, segments, meta, maps, blobs);
meta.push([key, ...segments]);
return result;
}
}
if (data instanceof Blob) {
maps.push(segments);
blobs.push(data);
return [data, meta, maps, blobs];
}
if (Array.isArray(data)) {
const json = data.map((v, i) => {
return this.serializeValue(v, [...segments, i], meta, maps, blobs)[0];
});
return [json, meta, maps, blobs];
}
if (isPlainObject(data)) {
const json = {};
for (const k in data) {
const v = data[k];
if (k === "toJSON" && typeof v === "function") {
continue;
}
if (v === void 0 && this.omitUndefinedProperties) {
continue;
}
json[k] = this.serializeValue(v, [...segments, k], meta, maps, blobs)[0];
}
return [json, meta, maps, blobs];
}
return [data, meta, maps, blobs];
}
deserialize(serialized) {
const ref = { data: serialized.json };
if (serialized.blobs?.length) {
serialized.maps.forEach((segments, i) => {
let currentRef = ref;
let preSegment = "data";
segments.forEach((segment) => {
currentRef = currentRef[preSegment];
preSegment = segment;
if (!Object.hasOwn(currentRef, preSegment)) {
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
}
});
currentRef[preSegment] = serialized.blobs[i];
});
}
serialized.meta?.forEach((item) => {
const type = item[0];
let currentRef = ref;
let preSegment = "data";
for (let i = 1; i < item.length; i++) {
currentRef = currentRef[preSegment];
preSegment = item[i];
if (!Object.hasOwn(currentRef, preSegment)) {
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
}
}
currentRef[preSegment] = this.handlers[type].deserialize(currentRef[preSegment]);
});
return ref.data;
}
}
class RPCSerializer {
jsonSerializer;
defaultSerializeOptions;
constructor(options = {}) {
this.jsonSerializer = new RPCJsonSerializer(options);
this.defaultSerializeOptions = options.serialize;
}
serialize(data, options = {}) {
if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
return data;
}
if (isAsyncIteratorObject(data)) {
return wrapAsyncIteratorPreservingEventMeta(data, {
mapResult: (result) => {
if (result.value === void 0) {
return result;
}
return { done: result.done, value: this.serializeValue(result.value, options) };
},
mapError: (e) => new ErrorEvent(
this.serializeValue(toORPCError(e).toJSON(), { ...options, useFormDataForBlobFields: false }),
{ cause: e }
)
});
}
return this.serializeValue(data, options);
}
serializeValue(data, options) {
const useFormDataForBlobs = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
const { json, meta, maps, blobs } = this.jsonSerializer.serialize(data);
if (!useFormDataForBlobs || !blobs?.length) {
return { json, meta };
}
const form = new FormData();
form.set("data", stringifyJSON({ json, meta, maps }));
blobs.forEach((blob, i) => {
form.set(i.toString(), blob);
});
return form;
}
deserialize(data) {
if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
return data;
}
if (isAsyncIteratorObject(data)) {
return wrapAsyncIteratorPreservingEventMeta(data, {
mapResult: (result) => {
if (result.value === void 0) {
return result;
}
return { done: result.done, value: this.deserializeValue(result.value) };
},
mapError: (e) => {
if (!(e instanceof ErrorEvent)) {
return e;
}
const deserialized = this.deserializeValue(e.data);
if (isORPCErrorJson(deserialized)) {
return createORPCErrorFromJson(deserialized, { cause: e });
}
return new ErrorEvent(deserialized, { cause: e });
}
});
}
return this.deserializeValue(data);
}
deserializeValue(data) {
if (!(data instanceof FormData)) {
return this.jsonSerializer.deserialize(data);
}
const serialized = JSON.parse(data.get("data"));
const blobs = [];
for (const [key, value] of data) {
if (value instanceof Blob) {
blobs[Number(key)] = value;
}
}
return this.jsonSerializer.deserialize({ ...serialized, blobs });
}
}
export { RPCSerializer as R, isInferableError as a, RPCJsonSerializer as b, createORPCErrorFromJson as c, cloneORPCError as d, isORPCErrorJson as i, toORPCError as t, wrapAsyncIteratorPreservingEventMeta as w };