@orpc/client
Advanced tools
Comparing version 0.0.0-unsafe-pr-2-20241118033608 to 0.0.0-unsafe-pr-9-20241121090958
@@ -1,251 +0,9 @@ | ||
import { trim } from "radash"; | ||
import { ZodError } from "zod"; | ||
import "content-disposition"; | ||
import "wildcard-match"; | ||
import "fast-content-type-parse"; | ||
import { isPlainObject } from "is-what"; | ||
const ORPC_HEADER = "x-orpc-transformer"; | ||
const ORPC_HEADER_VALUE = "t"; | ||
function set(root, segments, value) { | ||
const ref = { root }; | ||
let currentRef = ref; | ||
let preSegment = "root"; | ||
for (const segment of segments) { | ||
currentRef = currentRef[preSegment]; | ||
preSegment = segment; | ||
} | ||
currentRef[preSegment] = value; | ||
return ref.root; | ||
} | ||
function findDeepMatches(check, payload, segments = [], maps = [], values = []) { | ||
if (check(payload)) { | ||
maps.push(segments); | ||
values.push(payload); | ||
} else if (Array.isArray(payload)) { | ||
payload.forEach((v, i) => { | ||
findDeepMatches(check, v, [...segments, i], maps, values); | ||
}); | ||
} else if (isPlainObject(payload)) { | ||
for (const key in payload) { | ||
findDeepMatches(check, payload[key], [...segments, key], maps, values); | ||
} | ||
} | ||
return { maps, values }; | ||
} | ||
const ORPC_ERROR_CODE_STATUSES = { | ||
BAD_REQUEST: 400, | ||
UNAUTHORIZED: 401, | ||
FORBIDDEN: 403, | ||
NOT_FOUND: 404, | ||
METHOD_NOT_SUPPORTED: 405, | ||
NOT_ACCEPTABLE: 406, | ||
TIMEOUT: 408, | ||
CONFLICT: 409, | ||
PRECONDITION_FAILED: 412, | ||
PAYLOAD_TOO_LARGE: 413, | ||
UNSUPPORTED_MEDIA_TYPE: 415, | ||
UNPROCESSABLE_CONTENT: 422, | ||
TOO_MANY_REQUESTS: 429, | ||
CLIENT_CLOSED_REQUEST: 499, | ||
INTERNAL_SERVER_ERROR: 500, | ||
NOT_IMPLEMENTED: 501, | ||
BAD_GATEWAY: 502, | ||
SERVICE_UNAVAILABLE: 503, | ||
GATEWAY_TIMEOUT: 504 | ||
}; | ||
class ORPCError extends Error { | ||
constructor(zz$oe) { | ||
if (zz$oe.status && (zz$oe.status < 400 || zz$oe.status >= 600)) { | ||
throw new Error("The ORPCError status code must be in the 400-599 range."); | ||
} | ||
super(zz$oe.message, { cause: zz$oe.cause }); | ||
this.zz$oe = zz$oe; | ||
} | ||
get code() { | ||
return this.zz$oe.code; | ||
} | ||
get status() { | ||
return this.zz$oe.status ?? ORPC_ERROR_CODE_STATUSES[this.code]; | ||
} | ||
get data() { | ||
return this.zz$oe.data; | ||
} | ||
get issues() { | ||
if (this.code === "BAD_REQUEST" && this.zz$oe.cause instanceof ZodError) { | ||
return this.zz$oe.cause.issues; | ||
} | ||
return void 0; | ||
} | ||
toJSON() { | ||
return { | ||
code: this.code, | ||
status: this.status, | ||
message: this.message, | ||
data: this.data, | ||
issues: this.issues | ||
}; | ||
} | ||
static fromJSON(json) { | ||
if (typeof json !== "object" || json === null || !("code" in json) || !Object.keys(ORPC_ERROR_CODE_STATUSES).find((key) => json.code === key) || !("status" in json) || typeof json.status !== "number" || "message" in json && json.message !== void 0 && typeof json.message !== "string" || "issues" in json && json.issues !== void 0 && !Array.isArray(json.issues)) { | ||
return void 0; | ||
} | ||
return new ORPCError({ | ||
code: json.code, | ||
status: json.status, | ||
message: Reflect.get(json, "message"), | ||
data: Reflect.get(json, "data"), | ||
cause: "issues" in json ? new ZodError(json.issues) : void 0 | ||
}); | ||
} | ||
} | ||
function serialize(value, segments = [], meta = []) { | ||
if (typeof value === "bigint") { | ||
meta.push(["bigint", segments]); | ||
return { data: value.toString(), meta }; | ||
} | ||
if (value instanceof Date) { | ||
meta.push(["date", segments]); | ||
const data = Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString(); | ||
return { data, meta }; | ||
} | ||
if (Number.isNaN(value)) { | ||
meta.push(["nan", segments]); | ||
return { data: "NaN", meta }; | ||
} | ||
if (value instanceof RegExp) { | ||
meta.push(["regexp", segments]); | ||
return { data: value.toString(), meta }; | ||
} | ||
if (value instanceof URL) { | ||
meta.push(["url", segments]); | ||
return { data: value.toString(), meta }; | ||
} | ||
if (isPlainObject(value)) { | ||
const data = {}; | ||
for (const k in value) { | ||
data[k] = serialize(value[k], [...segments, k], meta).data; | ||
} | ||
return { data, meta }; | ||
} | ||
if (Array.isArray(value)) { | ||
const data = value.map((v, i) => { | ||
if (v === void 0) { | ||
meta.push(["undefined", [...segments, i]]); | ||
return null; | ||
} | ||
return serialize(v, [...segments, i], meta).data; | ||
}); | ||
return { data, meta }; | ||
} | ||
if (value instanceof Set) { | ||
const result = serialize(Array.from(value), segments, meta); | ||
meta.push(["set", segments]); | ||
return result; | ||
} | ||
if (value instanceof Map) { | ||
const result = serialize(Array.from(value.entries()), segments, meta); | ||
meta.push(["map", segments]); | ||
return result; | ||
} | ||
return { data: value, meta }; | ||
} | ||
function deserialize({ | ||
data, | ||
meta | ||
}) { | ||
if (meta.length === 0) { | ||
return data; | ||
} | ||
const ref = { data }; | ||
for (const [type, segments] of meta) { | ||
let currentRef = ref; | ||
let preSegment = "data"; | ||
for (let i = 0; i < segments.length; i++) { | ||
currentRef = currentRef[preSegment]; | ||
preSegment = segments[i]; | ||
} | ||
switch (type) { | ||
case "nan": | ||
currentRef[preSegment] = Number.NaN; | ||
break; | ||
case "bigint": | ||
currentRef[preSegment] = BigInt(currentRef[preSegment]); | ||
break; | ||
case "date": | ||
currentRef[preSegment] = new Date(currentRef[preSegment]); | ||
break; | ||
case "regexp": { | ||
const match = currentRef[preSegment].match(/^\/(.*)\/([a-z]*)$/); | ||
if (match) { | ||
const [, pattern, flags] = match; | ||
currentRef[preSegment] = new RegExp(pattern, flags); | ||
} else { | ||
currentRef[preSegment] = new RegExp(currentRef[preSegment]); | ||
} | ||
break; | ||
} | ||
case "url": | ||
currentRef[preSegment] = new URL(currentRef[preSegment]); | ||
break; | ||
case "undefined": | ||
currentRef[preSegment] = void 0; | ||
break; | ||
case "map": | ||
currentRef[preSegment] = new Map(currentRef[preSegment]); | ||
break; | ||
case "set": | ||
currentRef[preSegment] = new Set(currentRef[preSegment]); | ||
break; | ||
} | ||
} | ||
return ref.data; | ||
} | ||
class ORPCDeserializer { | ||
async deserialize(re) { | ||
var _a; | ||
if ((_a = re.headers.get("Content-Type")) == null ? void 0 : _a.startsWith("multipart/form-data")) { | ||
const form = await re.formData(); | ||
const rawData = form.get("data"); | ||
const rawMeta = form.get("meta"); | ||
const rawMaps = form.get("maps"); | ||
let data = rawData === null ? void 0 : JSON.parse(rawData); | ||
const meta = JSON.parse(rawMeta); | ||
const maps = JSON.parse(rawMaps); | ||
for (const i in maps) { | ||
data = set(data, maps[i], form.get(i)); | ||
} | ||
return deserialize({ | ||
data, | ||
meta | ||
}); | ||
} | ||
const json = await re.json(); | ||
return deserialize(json); | ||
} | ||
} | ||
class ORPCSerializer { | ||
serialize(payload) { | ||
const { data, meta } = serialize(payload); | ||
const { maps, values } = findDeepMatches((v) => v instanceof Blob, data); | ||
if (values.length > 0) { | ||
const form = new FormData(); | ||
if (data !== void 0) { | ||
form.append("data", JSON.stringify(data)); | ||
} | ||
form.append("meta", JSON.stringify(meta)); | ||
form.append("maps", JSON.stringify(maps)); | ||
for (const i in values) { | ||
const value = values[i]; | ||
form.append(i, value); | ||
} | ||
return { body: form, headers: new Headers() }; | ||
} | ||
return { | ||
body: JSON.stringify({ data, meta }), | ||
headers: new Headers({ | ||
"Content-Type": "application/json" | ||
}) | ||
}; | ||
} | ||
} | ||
// src/procedure.ts | ||
import { | ||
ORPC_HEADER, | ||
ORPC_HEADER_VALUE | ||
} from "@orpc/contract"; | ||
import { trim } from "@orpc/shared"; | ||
import { ORPCError } from "@orpc/shared/error"; | ||
import { ORPCDeserializer, ORPCSerializer } from "@orpc/transformer"; | ||
function createProcedureClient(options) { | ||
@@ -255,6 +13,5 @@ const serializer = new ORPCSerializer(); | ||
const client = async (input) => { | ||
var _a; | ||
const fetch_ = options.fetch ?? fetch; | ||
const url = `${trim(options.baseURL, "/")}/${options.path.map(encodeURIComponent).join("/")}`; | ||
let headers = await ((_a = options.headers) == null ? void 0 : _a.call(options, input)); | ||
let headers = await options.headers?.(input); | ||
headers = headers instanceof Headers ? headers : new Headers(headers); | ||
@@ -293,4 +50,6 @@ const { body, headers: headers_ } = serializer.serialize(input); | ||
} | ||
// src/router.ts | ||
function createRouterClient(options) { | ||
const path = (options == null ? void 0 : options.path) ?? []; | ||
const path = options?.path ?? []; | ||
const client = new Proxy( | ||
@@ -317,6 +76,7 @@ createProcedureClient({ | ||
} | ||
const createORPCClient = createRouterClient; | ||
// src/index.ts | ||
export * from "@orpc/shared/error"; | ||
var createORPCClient = createRouterClient; | ||
export { | ||
ORPCError, | ||
ORPC_ERROR_CODE_STATUSES, | ||
createORPCClient, | ||
@@ -326,1 +86,2 @@ createProcedureClient, | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -0,3 +1,3 @@ | ||
import type { Promisable } from '@orpc/shared'; | ||
import { type Schema, type SchemaInput, type SchemaOutput } from '@orpc/contract'; | ||
import type { Promisable } from '@orpc/shared'; | ||
export interface ProcedureClient<TInputSchema extends Schema, TOutputSchema extends Schema, THandlerOutput extends SchemaOutput<TOutputSchema>> { | ||
@@ -4,0 +4,0 @@ (input: SchemaInput<TInputSchema>): Promise<SchemaOutput<TOutputSchema, THandlerOutput>>; |
{ | ||
"name": "@orpc/client", | ||
"type": "module", | ||
"version": "0.0.0-unsafe-pr-2-20241118033608", | ||
"version": "0.0.0-unsafe-pr-9-20241121090958", | ||
"author": { | ||
@@ -37,17 +37,18 @@ "name": "unnoq", | ||
], | ||
"devDependencies": { | ||
"zod": "^3.23.8" | ||
"peerDependencies": { | ||
"@orpc/contract": "0.0.4", | ||
"@orpc/server": "0.1.0" | ||
}, | ||
"dependencies": { | ||
"@orpc/shared": "0.0.0-unsafe-pr-2-20241118033608", | ||
"@orpc/transformer": "0.0.0-unsafe-pr-2-20241118033608" | ||
"@orpc/shared": "0.0.5", | ||
"@orpc/transformer": "0.0.4" | ||
}, | ||
"peerDependencies": { | ||
"@orpc/contract": "0.0.0-unsafe-pr-2-20241118033608", | ||
"@orpc/server": "0.0.0-unsafe-pr-2-20241118033608" | ||
"devDependencies": { | ||
"zod": "^3.23.8" | ||
}, | ||
"scripts": { | ||
"build": "UNPLUGIN_ON_SUCCESS='tsc -b --noCheck' vite build", | ||
"build": "tsup --clean --sourcemap --entry.index=src/index.ts --format=esm --onSuccess='tsc -b --noCheck'", | ||
"build:watch": "pnpm run build --watch", | ||
"type:check": "tsc -b" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { os, ORPCError } from '@orpc/server' | ||
import { ORPCError, os } from '@orpc/server' | ||
import { createFetchHandler } from '@orpc/server/fetch' | ||
@@ -114,3 +114,3 @@ import { z } from 'zod' | ||
.input(z.object({ value: z.date() })) | ||
.handler((input) => input.value), | ||
.handler(input => input.value), | ||
}) | ||
@@ -171,3 +171,4 @@ | ||
await client(undefined) | ||
} catch (e) { | ||
} | ||
catch (e) { | ||
error = e | ||
@@ -174,0 +175,0 @@ } |
/// <reference lib="dom" /> | ||
/// <reference lib="dom.iterable" /> | ||
import type { Promisable } from '@orpc/shared' | ||
import { | ||
@@ -11,3 +12,2 @@ ORPC_HEADER, | ||
} from '@orpc/contract' | ||
import type { Promisable } from '@orpc/shared' | ||
import { trim } from '@orpc/shared' | ||
@@ -84,3 +84,4 @@ import { ORPCError } from '@orpc/shared/error' | ||
return await deserializer.deserialize(response) | ||
} catch (e) { | ||
} | ||
catch (e) { | ||
throw new ORPCError({ | ||
@@ -96,4 +97,4 @@ code: 'INTERNAL_SERVER_ERROR', | ||
throw ( | ||
ORPCError.fromJSON(json) ?? | ||
new ORPCError({ | ||
ORPCError.fromJSON(json) | ||
?? new ORPCError({ | ||
status: response.status, | ||
@@ -100,0 +101,0 @@ code: 'INTERNAL_SERVER_ERROR', |
@@ -116,3 +116,3 @@ import { oc } from '@orpc/contract' | ||
// @ts-expect-error | ||
// @ts-expect-error - invalid input | ||
expect(client.ping({ value: {} })).rejects.toThrowError( | ||
@@ -127,3 +127,3 @@ 'Validation input failed', | ||
.input(z.object({ value: z.date() })) | ||
.handler((input) => input.value), | ||
.handler(input => input.value), | ||
}) | ||
@@ -130,0 +130,0 @@ |
@@ -9,3 +9,3 @@ /// <reference lib="dom" /> | ||
import type { Procedure, Promisable, Router } from '@orpc/server' | ||
import { type ProcedureClient, createProcedureClient } from './procedure' | ||
import { createProcedureClient, type ProcedureClient } from './procedure' | ||
@@ -68,6 +68,6 @@ export type RouterClientWithContractRouter<TRouter extends ContractRouter> = { | ||
): TRouter extends Router<any> | ||
? RouterClientWithRouter<TRouter> | ||
: TRouter extends ContractRouter | ||
? RouterClientWithContractRouter<TRouter> | ||
: never { | ||
? RouterClientWithRouter<TRouter> | ||
: TRouter extends ContractRouter | ||
? RouterClientWithContractRouter<TRouter> | ||
: never { | ||
const path = options?.path ?? [] | ||
@@ -74,0 +74,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
94647
16
1
663
+ Added@orpc/contract@0.0.4(transitive)
+ Added@orpc/server@0.1.0(transitive)
+ Added@orpc/shared@0.0.5(transitive)
+ Added@orpc/transformer@0.0.4(transitive)
+ Added@orpc/zod@0.0.1(transitive)
- Removed@orpc/contract@0.0.0-unsafe-pr-2-20241118033608(transitive)
- Removed@orpc/server@0.0.0-unsafe-pr-2-20241118033608(transitive)
- Removed@orpc/shared@0.0.0-unsafe-pr-2-20241118033608(transitive)
- Removed@orpc/transformer@0.0.0-unsafe-pr-2-20241118033608(transitive)
- Removed@orpc/zod@0.0.0(transitive)
Updated@orpc/shared@0.0.5
Updated@orpc/transformer@0.0.4