diff --git a/@strpc/client_ky/package.json b/@strpc/client_ky/package.json new file mode 100644 index 0000000..edec5fa --- /dev/null +++ b/@strpc/client_ky/package.json @@ -0,0 +1,27 @@ +{ + "name": "@strpc/client_ky", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "dependencies": { + "@strpc/def": "workspace:^" + }, + "devDependencies": { + "ky": "^1.0.1", + "lodash-es": "^4.17.21" + }, + "scripts": { + "build": "tsc --build" + }, + "type": "module", + "author": "", + "license": "ISC", + "peerDependencies": { + "ky": "^1.0.1", + "lodash-es": "^4.17.21" + } +} diff --git a/@strpc/client_ky/src/callClientAPI.ts b/@strpc/client_ky/src/callClientAPI.ts new file mode 100644 index 0000000..400c877 --- /dev/null +++ b/@strpc/client_ky/src/callClientAPI.ts @@ -0,0 +1,158 @@ +import { isArray, isEmpty } from "lodash-es"; +import ky from "ky"; +import type { HttpMethod, InvalidResponse, RawArgType, ValidResponse, recoveryMethod } from "@strpc/def"; + + +export type globalRecoveryFunction = (method: HttpMethod, path: string, args: RawArgType, recovery: recoveryMethod, result: InvalidResponse) => Promise<{ + justRetryAPI?: boolean; +} | void>; + +export class APIFailed extends Error { + constructor(public readonly reason: string, public readonly detail: unknown, public readonly recovery?: recoveryMethod) { + super(reason); + } +} + +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: undefined +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: false +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: true +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError?: boolean +): Promise { + if (isArray(path)) { + path = [apiRoot, ...path].join("/"); + } + else if (path.startsWith("/")) { + path = `${apiRoot}${path}`; + } + else { + path = `${apiRoot}/${path}`; + } + + if (args && isEmpty(args)) { + args = undefined; + } + + try { + let trialRemain = 3; + let lastErr: ErrorType | undefined = undefined; + // eslint-disable-next-line no-constant-condition + while(trialRemain > 0){ + const result = (await (() => { + if (method == "get") { + //TODO: args가 복합 object일 경우의 처리 + return ky(path, { + searchParams: args === undefined ? undefined : { + ...(args as Record), + }, + method, + headers: { + "content-type": "application/json", + }, + timeout: 30000, + retry: 0, + }); + } + return ky(path, { + method, + json: args, + headers: { + "content-type": "application/json", + }, + timeout: 30000, + retry: 0, + }); + })().json()) as ErrorType | ResultType; + + if (!result.result) { + lastErr = result; + if(result.recovery && globalRecovery){ + const recoveryResult = await globalRecovery(method, path, args, result.recovery, result); + if(recoveryResult !== undefined && recoveryResult.justRetryAPI){ + trialRemain--; + continue; + } + } + + if (returnError) { + return result; + } + throw new APIFailed( + result.reason, + result.detail, + result.recovery + ); + } + return result; + } + + if(lastErr === undefined){ + throw new Error('lastErr is undefined'); + } + + if (returnError) { + return lastErr; + } + throw lastErr.reason; + + } + catch(err) { + if(!returnError){ + throw err; + } + + let infoText = '' + + if(err instanceof APIFailed){ + infoText = err.reason; + } + else if(err instanceof Error){ + infoText = err.toString(); + } + else if(typeof err == 'string'){ + infoText = err; + } + else{ + infoText = JSON.stringify(err); + } + + return { + result: false, + reason: `failed to fetch(${path}): ${err}`, + detail: err, + } as ErrorType; + } +} \ No newline at end of file diff --git a/@strpc/client_ky/src/index.ts b/@strpc/client_ky/src/index.ts new file mode 100644 index 0000000..b4ebd3c --- /dev/null +++ b/@strpc/client_ky/src/index.ts @@ -0,0 +1,15 @@ +import { clientAPIPathGen, type APITail, type DefAPINamespace, type RawArgType } from "@strpc/def"; +import { callClientAPI, type globalRecoveryFunction } from "./callClientAPI.js"; +export { callClientAPI, type globalRecoveryFunction } from "./callClientAPI.js"; + +export function buildClientAPI(structure: T, apiRoot = '/api', globalRecovery?: globalRecoveryFunction){ + return clientAPIPathGen(structure, (path: string[], tail: APITail) => { + const method = tail.reqType; + return (args?: RawArgType, returnError?: boolean) => { + if (returnError) { + return callClientAPI(method, apiRoot, path.join('/'), args, globalRecovery, returnError); + } + return callClientAPI(method, apiRoot, path.join('/'), args, globalRecovery); + }; + }); +} \ No newline at end of file diff --git a/@strpc/client_ky/tsconfig.json b/@strpc/client_ky/tsconfig.json new file mode 100644 index 0000000..ac5ecf2 --- /dev/null +++ b/@strpc/client_ky/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../def" + }, + ] +} diff --git a/@strpc/def/package.json b/@strpc/def/package.json new file mode 100644 index 0000000..d41e15e --- /dev/null +++ b/@strpc/def/package.json @@ -0,0 +1,17 @@ +{ + "name": "@strpc/def", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "devDependencies": {}, + "scripts": { + "build": "tsc --build" + }, + "type": "module", + "author": "", + "license": "ISC" +} diff --git a/@strpc/def/src/clientAPIPathGen.ts b/@strpc/def/src/clientAPIPathGen.ts new file mode 100644 index 0000000..c2549d3 --- /dev/null +++ b/@strpc/def/src/clientAPIPathGen.ts @@ -0,0 +1,38 @@ +export function clientAPIPathGen( + obj: T, + callback: (path: string[], tail: V) => unknown, + path: string[] = [], +): T { + const map = new Map(); + return new Proxy(obj, { + get(target, key) { + if(typeof key === 'symbol'){ + throw new Error('Symbol is not supported'); + } + + const cachedResult = map.get(key); + if(cachedResult !== undefined){ + return cachedResult; + } + + const nextPath = [...path, key]; + + let next; + if (key in target) { + next = target[key as keyof typeof target]; + } + else { + throw `${nextPath} is not exists`; + } + + if (typeof (next) === 'function') { + const result = callback(nextPath, next as V); + map.set(key, result); + return result; + } + const result = clientAPIPathGen(next as object, callback, nextPath); + map.set(key, result); + return result; + } + }) as T; +} \ No newline at end of file diff --git a/@strpc/def/src/index.ts b/@strpc/def/src/index.ts new file mode 100644 index 0000000..8819516 --- /dev/null +++ b/@strpc/def/src/index.ts @@ -0,0 +1,23 @@ +export type { + HttpMethod, + RawArgType, + DefAPINamespace, + APICompatType, + ValidResponse, + InvalidResponse, + recoveryMethod, + InferResponse, + InferError, + InferQuery, +} from './types.js'; + +export { + type APITail, + GET, + POST, + PUT, + DELETE, + PATCH, + HEAD, +} from './tail.js'; +export { clientAPIPathGen } from './clientAPIPathGen.js'; \ No newline at end of file diff --git a/@strpc/def/src/tail.ts b/@strpc/def/src/tail.ts new file mode 100644 index 0000000..46f72e3 --- /dev/null +++ b/@strpc/def/src/tail.ts @@ -0,0 +1,177 @@ +import type { ArgDeleteAPI, ArgGetAPI, ArgHeadAPI, ArgPatchAPI, ArgPostAPI, ArgPutAPI, EmptyDeleteAPI, EmptyGetAPI, EmptyHeadAPI, EmptyPatchAPI, EmptyPostAPI, EmptyPutAPI, InvalidResponse, RawArgType, ValidResponse } from "./types.js"; + +export type APITail = ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType; + +export function GET(): EmptyGetAPI; +export function GET< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyGetAPI; +export function GET< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgGetAPI; +export function GET< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgGetAPI | EmptyGetAPI { + return Object.assign( + fakeGET, + { reqType: 'get' } as const + ) +} + +export function POST(): EmptyPostAPI; +export function POST< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPostAPI; +export function POST< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPostAPI; +export function POST< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPostAPI | EmptyPostAPI { + return Object.assign( + fakePOST, + { reqType: 'post' } as const + ) +} + +export function PUT(): EmptyPutAPI; +export function PUT< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPutAPI; +export function PUT< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPutAPI; +export function PUT< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPutAPI | EmptyPutAPI { + return Object.assign( + fakePUT, + { reqType: 'put' } as const + ) +} + +export function DELETE(): EmptyDeleteAPI; +export function DELETE< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyDeleteAPI; +export function DELETE< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgDeleteAPI; +export function DELETE< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgDeleteAPI | EmptyDeleteAPI { + return Object.assign( + fakeDELETE, + { reqType: 'delete' } as const + ) +} + +export function PATCH(): EmptyPatchAPI; +export function PATCH< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPatchAPI; +export function PATCH< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPatchAPI; +export function PATCH< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPatchAPI | EmptyPatchAPI { + return Object.assign( + fakePATCH, + { reqType: 'patch' } as const + ) +} + +export function HEAD(): EmptyHeadAPI; +export function HEAD< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyHeadAPI; +export function HEAD< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgHeadAPI; +export function HEAD< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgHeadAPI | EmptyHeadAPI { + return Object.assign( + fakeHEAD, + { reqType: 'head' } as const + ) +} + +async function fakeGET< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends undefined = undefined +>(args?: ArgType, returnError = false): Promise { + throw `Can't directly call GET. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakePOST< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call POST. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakePUT< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call PUT. ${args}, ${returnError}. Use auto-generated path API.`; +} + +async function fakeDELETE< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call DELETE. ${args}, ${returnError}. Use auto-generated path API.`; +} + +async function fakePATCH< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call PATCH. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakeHEAD< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args?: ArgType, returnError = false): Promise { + throw `Can't directly call HEAD. ${args}, ${returnError}. Use auto-generated path API.`; +} diff --git a/@strpc/def/src/types.ts b/@strpc/def/src/types.ts new file mode 100644 index 0000000..708b423 --- /dev/null +++ b/@strpc/def/src/types.ts @@ -0,0 +1,191 @@ +export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head'; +export type RawArgType = { + [key: string]: unknown; +} | undefined; + + +export interface ArgAnyAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + Method extends HttpMethod +> { + (args: ArgType): Promise; + (args: ArgType, returnError: false): Promise; + (args: ArgType, returnError: true): Promise; + readonly reqType: Method; +} + +export type ArgGetAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPostAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPutAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgDeleteAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPatchAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgHeadAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export interface EmptyAnyAPI { + (): Promise; + (args?: undefined): Promise; + (args: undefined, returnError: false): Promise; + (args: undefined, returnError: true): Promise; + readonly reqType: Method; +} + +export type EmptyGetAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPostAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPutAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyDeleteAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPatchAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyHeadAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ArgTypeOf = T extends AnyAPI ? A : never; + + +export type AnyAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyAnyAPI : ArgAnyAPI; + +export type GetAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyGetAPI : ArgGetAPI; + +export type PostAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPostAPI : ArgPostAPI; + +export type PutAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPutAPI : ArgPutAPI; + +export type DeleteAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyDeleteAPI : ArgDeleteAPI; + +export type PatchAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPatchAPI : ArgPatchAPI; + +export type HeadAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyHeadAPI : ArgHeadAPI; + +export interface ValidResponse { + result: true; +} + +export type recoveryMethod = 'hardRefresh' | 'refreshEntireProcess' | 'retryAPI' | 'login'; +export interface InvalidResponse { + result: false; + reason: string; + recovery?: recoveryMethod; + detail?: string | string[] | Record; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type Callable = (...args: any) => any; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferQuery> = T extends EmptyAnyAPI ? undefined : T extends ArgAnyAPI ? Q : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferResponse> = T extends EmptyAnyAPI ? R : T extends ArgAnyAPI ? R : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferError> = T extends EmptyAnyAPI ? E : T extends ArgAnyAPI ? E : never; + + +export type DefAPINamespace = { + [key: string]: DefAPINamespace + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgGetAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPostAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPutAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgDeleteAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPatchAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgHeadAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyGetAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPostAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPutAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyDeleteAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPatchAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyHeadAPI + ; +} + +export type APICompatType = T extends AnyAPI ? AnyAPI : never; diff --git a/@strpc/def/tsconfig.json b/@strpc/def/tsconfig.json new file mode 100644 index 0000000..d6e53f3 --- /dev/null +++ b/@strpc/def/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + ] +} diff --git a/@strpc/express/package.json b/@strpc/express/package.json new file mode 100644 index 0000000..b0d690a --- /dev/null +++ b/@strpc/express/package.json @@ -0,0 +1,32 @@ +{ + "name": "@strpc/express", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "exports": { + ".": "./dist/index.js", + "./generator": "./dist/generator.js", + "./proc_decorator": "./dist/proc_decorator.js" + }, + "type": "module", + "author": "", + "license": "ISC", + "dependencies": { + "@strpc/def": "workspace:^" + }, + "devDependencies": { + "express": "^4.18.2", + "express-session": "^1.17.3", + "lodash-es": "^4.17.21", + "zod": "^3.22.2" + }, + "peerDependencies": { + "express": "^4.18.2", + "express-session": "^1.17.3", + "lodash-es": "^4.17.21", + "zod": "^3.22.2" + } +} diff --git a/@strpc/express/src/defs.ts b/@strpc/express/src/defs.ts new file mode 100644 index 0000000..9dd5a35 --- /dev/null +++ b/@strpc/express/src/defs.ts @@ -0,0 +1,213 @@ + +import type { Request, Response } from 'express'; +import type { AnyAPI, Callable, DefAPINamespace, DeleteAPI, GetAPI, HeadAPI, HttpMethod, InferError, InferQuery, InferResponse, InvalidResponse, PatchAPI, PostAPI, PutAPI, recoveryMethod } from '@strpc/def/types'; +import type { Empty, PostProcDecoratorRunner, ProcDecoratorRunner } from './proc_decorator.js'; +import type { ZodType } from 'zod'; + +export type APINamespace = { + [key: string]: APINamespace + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_GET + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_POST + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_PUT + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_DELETE + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_PATCH + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_HEAD + ; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type AnyAPIExecuter = APIExecuter; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyAnyAPI = AnyAPI; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +interface APIExecuter { + (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response): Promise | InferError | true>; + httpMethod: HttpMethod; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + argValidator?: ZodType>; + preDecorator: ProcDecoratorRunner; + postDecorator: PostProcDecoratorRunner; +} + +export interface iAPI_GET extends APIExecuter { + httpMethod: 'get'; +} + +export interface iAPI_POST extends APIExecuter { + httpMethod: 'post'; +} + +export interface iAPI_PUT extends APIExecuter { + httpMethod: 'put'; +} + +export interface iAPI_DELETE extends APIExecuter { + httpMethod: 'delete'; +} + +export interface iAPI_PATCH extends APIExecuter { + httpMethod: 'patch'; +} + +export interface iAPI_HEAD extends APIExecuter { + httpMethod: 'head'; +} + + +/** API의 반환형. ValidResponse | InvalidResponse | true */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type APIReturnType = Promise | InferError | true>; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function generateAPI(httpMethod: HttpMethod, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + argValidator: ZodType> | undefined, + preDecorator: ProcDecoratorRunner, + postDecorator: PostProcDecoratorRunner, + callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>, +): APIExecuter { + return Object.assign( + callback, + { + httpMethod, + argValidator, + preDecorator, + postDecorator, + } + ); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function GET>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'get', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_GET; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function POST>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'post', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_POST; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function PUT>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'put', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_PUT; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function DELETE, Z extends ZodType>>(argValidator?: Z) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'delete', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_DELETE; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function PATCH>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'patch', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_PATCH; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function HEAD>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'head', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_HEAD; + } + } +} + +export function raiseError(reason: string, recovery?: recoveryMethod): InvalidResponse { + if (recovery) { + return { + result: false, + reason, + recovery, + }; + } + return { + result: false, + reason, + }; +} + +export type APIServerType = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends GetAPI ? iAPI_GET, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PostAPI ? iAPI_POST, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PutAPI ? iAPI_PUT, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends DeleteAPI ? iAPI_DELETE, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PatchAPI ? iAPI_PATCH, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends HeadAPI ? iAPI_HEAD, any> : + + never; +export type APINamespaceType = { + [K in keyof T]: + T[K] extends Callable ? APIServerType : + T[K] extends DefAPINamespace ? APINamespaceType : + never; +}; \ No newline at end of file diff --git a/@strpc/express/src/generator.ts b/@strpc/express/src/generator.ts new file mode 100644 index 0000000..ca5dbba --- /dev/null +++ b/@strpc/express/src/generator.ts @@ -0,0 +1,161 @@ +import { Router, type Request, type Response } from 'express'; +import type { AnyAPIExecuter, APINamespace } from './defs.js'; +import type { RawArgType } from '@strpc/def'; +import type { SafeParseReturnType, ZodType, z } from 'zod'; +import { flatten } from 'lodash-es'; + +const PRINT_API_CALL = true; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function parseParam(req: Request, argValidator?: ZodType): Promise> { + if (!argValidator) { + return { + success: true, + data: req.query as Q + } + } + + const query = req.query; + return await argValidator.safeParseAsync(query); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function parseBody(req: Request, argValidator?: ZodType): Promise> { + if (!argValidator) { + return { + success: true, + data: req.body as Q + } + } + + const query = req.body; + return await argValidator.safeParseAsync(query); +} + +async function apiRun(query: Q, req: Request, res: Response, api: AnyAPIExecuter): Promise { + const [preResult, ctx] = await api.preDecorator({}, req, res); + if (!preResult.every((v) => v.result)) { + const lastErr = preResult.pop() as typeof preResult[0]; + + const [postResult,] = await api.postDecorator(ctx, preResult, req, res, false); + const postErrors = postResult.filter((obj) => !obj.result); + if (postErrors.length) { + //회수조차 불가능? + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'preDecorator', lastErr.type, lastErr.info])); + } + res.json({ + result: false, + path: req.path, + reason: lastErr.info, + recovery: lastErr.recovery, + detail: { + type: 'decorator', + preDecorator: [lastErr.type, lastErr.info], + postDecorator: flatten(postErrors.map((obj) => [obj.type, obj.info])), + }, + }); + return; + } + + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'preDecorator', lastErr.type, lastErr.info])); + } + res.json({ + result: false, + path: req.path, + reason: lastErr.info, + recovery: lastErr.recovery, + detail: { + type: 'decorator', + preDecorator: [lastErr.type, lastErr.info], + }, + }) + return; + } + const result = await api(query, ctx, req, res); + const [postResult,] = await api.postDecorator(ctx, preResult, req, res, true); + const postErrors = postResult.filter((obj) => !obj.result); + if (postErrors.length) { + const lastErr = postErrors.pop() as typeof postErrors[0]; + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'postDecorator', lastErr.type, lastErr.info])); + } + if (result === true) { + //NOTE: 이미 api에서 response를 보낸 특이 케이스. + return; + } + res.json({ + result: false, + path: req.path, + reason: lastErr?.info, + recovery: lastErr?.recovery, + detail: { + type: 'decorator', + preDecorator: flatten(postErrors.map((obj) => [obj.type, obj.info])), + }, + originalResult: result, + }); + return; + } + + if (PRINT_API_CALL) { + if(result === true){ + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, true, 'passThrough'])); + } + else{ + let tmp_result = true; + let tmp_reason = undefined; + if('result' in result){ + tmp_result = result.result; + } + if('reason' in result){ + tmp_reason = result.reason; + } + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, tmp_result, tmp_reason])); + } + + } + + if (result !== true) { + res.json(result); + } +} + +export function buildAPISystem(api: N | Q): Router { + const router = Router(); + + if (typeof api === 'function') { + throw 'root api cannot be function'; + } + + for (const [key, value] of Object.entries(api)) { + const rkey = `/${key}`; + if (typeof value !== 'function') { + router.use(rkey, buildAPISystem(value)); + + continue; + } + const executer = value; + + if (!executer.httpMethod) { + throw new Error('APIExecuter.reqType is not defined'); + } + + const parser = executer.httpMethod === 'get' ? parseParam : parseBody; + router[executer.httpMethod](rkey, async (req, res) => { + const queryResult = await parser(req, executer.argValidator); + if (!queryResult.success) { + res.json({ + result: false, + reason: `invalid parameter: ${queryResult.error.message}`, + error: queryResult.error + }); + return; + } + + await apiRun(queryResult.data, req, res, executer); + }); + } + return router; +} \ No newline at end of file diff --git a/@strpc/express/src/index.ts b/@strpc/express/src/index.ts new file mode 100644 index 0000000..0545755 --- /dev/null +++ b/@strpc/express/src/index.ts @@ -0,0 +1,3 @@ +export * from './defs.js'; +export * as generator from './generator.js'; +export * as proc_decorator from './proc_decorator.js'; \ No newline at end of file diff --git a/@strpc/express/src/proc_decorator.ts b/@strpc/express/src/proc_decorator.ts new file mode 100644 index 0000000..33d212b --- /dev/null +++ b/@strpc/express/src/proc_decorator.ts @@ -0,0 +1,187 @@ +import type { recoveryMethod } from "@strpc/def"; +import type { Request, Response } from "express"; + +type MayBePromise = T | Promise; + +export type Empty = Record; +export type DecoratorResultTrue = { + result: true; + type?: string; + info?: string; + recovery?: recoveryMethod; +}; +export type DecoratorResultFalse = { + result: false; + type: string; + info: string; + recovery?: recoveryMethod; +} +export type DecoratorResult = DecoratorResultTrue | DecoratorResultFalse; +export type DecoratorStack = DecoratorResult[]; + +export interface ProcDecorator { + (inCtx: In & Partial, req: Request, res: Response) + : MayBePromise<[DecoratorResultTrue, Out]> + | MayBePromise<[DecoratorResultFalse, In & Partial]>; +} + +export interface PostProcDecorator { + (ctx: T, preResult: DecoratorResult, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorResult, T]>; +} + +export interface ProcDecoratorRunner { + (inCtx: In & Partial, req: Request, res: Response): MayBePromise<[DecoratorStack, Out]>; +} + +export interface PostProcDecoratorRunner { + (ctx: T, preResult: DecoratorStack, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorStack, T]>; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PlainDecorator = ProcDecorator; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PlainPostDecorator = PostProcDecorator; + + +export type ProcDecoratorGenerator = ProcDecorator; +export type ProcDecoratorPrePostGenerator = [ProcDecorator, PostProcDecorator]; + +export type ProcDecoratorChain = readonly ((() => PlainDecorator) | (() => [PlainDecorator, PlainPostDecorator]))[]; + +export type ResolveChain = T extends undefined ? Empty : T extends ProcDecoratorChain ? Resolve> : never; + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ParseInType = T extends ProcDecorator ? object extends A ? A : never : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ParseOutType = T extends ProcDecorator ? B : never; + +export const EmptyProcDecorator: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ + async (ctx) => [[], ctx], async (ctx, stack) => [stack, ctx] +]; + +export function declProcDecorators(...decorators: T) { + type OutType = ParseOutType>; + + const preDecorator: PlainDecorator[] = []; + const postDecorator: (PlainPostDecorator | undefined)[] = []; + if (decorators) { + for (const procGen of decorators) { + const proc = procGen(); + if (Array.isArray(proc)) { + preDecorator.push(proc[0]); + postDecorator.push(proc[1]); + } + else { + preDecorator.push(proc); + postDecorator.push(undefined); + } + } + } + + const packedDecorators: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ + async (ctx, req, res) => { + let rctx = ctx as unknown as OutType; + const decoratorStack: DecoratorStack = []; + if (!preDecorator) { + return [decoratorStack, rctx]; + } + + for (const [idx, proc] of preDecorator.entries()) { + try { + const [stackResult, newCtx] = await proc(rctx, req, res); + decoratorStack.push(stackResult); + + if (stackResult.result) { + rctx = newCtx; + continue; + } + + return [decoratorStack, newCtx]; + } + catch (e) { + while (decoratorStack.length > idx) { + decoratorStack.pop(); + } + decoratorStack.push({ + result: false, + type: 'PreThrow', + info: `internal error: ${e}`, + }); + + return [decoratorStack, rctx]; + } + } + + return [decoratorStack, rctx]; + }, + async (ctx, stack, req, res) => { + if (!postDecorator.length) { + return [stack, ctx]; + } + let isValidRoute = stack.length === postDecorator.length && stack.every(v => v.result); + for (let idx = stack.length - 1; idx >= 0; idx--) { + const preStackResult = stack[idx] as DecoratorResult; + if (!preStackResult.result) { + continue; + } + + const proc = postDecorator[idx]; + + if (!proc) { + if (isValidRoute) { + stack.pop(); + } + continue; + } + + try { + const [postStackResult, nextCtx] = await proc(ctx, preStackResult, req, res, isValidRoute); + if (postStackResult.result) { + if (isValidRoute) { + stack.pop(); + } + ctx = nextCtx; + continue; + } + + isValidRoute = false; + stack[idx] = postStackResult; + + ctx = nextCtx; + } + catch (e) { + isValidRoute = false; + stack[idx] = { + result: false, + type: 'PostThrow', + info: `internal error: ${e}`, + }; + } + + } + return [stack, ctx]; + }, + ] as const; + + return packedDecorators; +} + +type Compose2 = B extends C ? ProcDecorator : never; + +type PD1 = () => ProcDecorator; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PD2 = () => [ProcDecorator, PostProcDecorator]; + +export type PackChain = + T extends readonly [] ? ProcDecorator : + T extends readonly [PD1] ? ProcDecorator : + T extends readonly [PD2] ? ProcDecorator : + T extends readonly [PD1, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD1, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + never; + +type Resolve = T extends ProcDecorator ? Empty extends A ? B : never : never; \ No newline at end of file diff --git a/@strpc/express/tsconfig.json b/@strpc/express/tsconfig.json new file mode 100644 index 0000000..0f5425e --- /dev/null +++ b/@strpc/express/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../def" + }, + ] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b7520d..b00e9db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,138 +4,174 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@esfx/async-readerwriterlock': - specifier: ^1.0.0 - version: 1.0.0 - '@popperjs/core': - specifier: ^2.11.8 - version: 2.11.8 - async-lock: - specifier: ^1.4.0 - version: 1.4.0 - bootstrap: - specifier: ^5.3.1 - version: 5.3.1(@popperjs/core@2.11.8) - bootstrap-vue-next: - specifier: ^0.9.26 - version: 0.9.26(vue@3.3.4) - bson: - specifier: ^5.4.0 - version: 5.4.0 - buffer: - specifier: ^6.0.3 - version: 6.0.3 - date-fns: - specifier: ^2.30.0 - version: 2.30.0 - dotenv: - specifier: ^16.3.1 - version: 16.3.1 - eventemitter3: - specifier: ^5.0.1 - version: 5.0.1 - express: - specifier: ^4.18.2 - version: 4.18.2 - express-session: - specifier: ^1.17.3 - version: 1.17.3 - ky: - specifier: ^0.33.3 - version: 0.33.3 - lodash-es: - specifier: ^4.17.21 - version: 4.17.21 - mongoose: - specifier: ^7.4.3 - version: 7.4.3 - pinia: - specifier: ^2.1.4 - version: 2.1.4(typescript@5.1.6)(vue@3.3.4) - reflect-metadata: - specifier: ^0.1.13 - version: 0.1.13 - tslib: - specifier: ^2.6.1 - version: 2.6.1 - vue: - specifier: ^3.3.4 - version: 3.3.4 - vue-router: - specifier: ^4.2.4 - version: 4.2.4(vue@3.3.4) - zod: - specifier: ^3.22.1 - version: 3.22.1 +importers: -devDependencies: - '@rushstack/eslint-patch': - specifier: ^1.3.2 - version: 1.3.2 - '@tsconfig/node18': - specifier: ^18.2.0 - version: 18.2.0 - '@types/async-lock': - specifier: ^1.4.0 - version: 1.4.0 - '@types/bootstrap': - specifier: ^5.2.6 - version: 5.2.6 - '@types/express': - specifier: ^4.17.17 - version: 4.17.17 - '@types/express-session': - specifier: ^1.17.7 - version: 1.17.7 - '@types/lodash-es': - specifier: ^4.17.8 - version: 4.17.8 - '@types/node': - specifier: ^18.17.0 - version: 18.17.0 - '@vitejs/plugin-vue': - specifier: ^4.2.3 - version: 4.2.3(vite@4.4.6)(vue@3.3.4) - '@vue/eslint-config-prettier': - specifier: ^8.0.0 - version: 8.0.0(eslint@8.45.0)(prettier@3.0.0) - '@vue/eslint-config-typescript': - specifier: ^11.0.3 - version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.1.6) - '@vue/tsconfig': - specifier: ^0.4.0 - version: 0.4.0 - concurrently: - specifier: ^8.2.0 - version: 8.2.0 - eslint: - specifier: ^8.45.0 - version: 8.45.0 - eslint-plugin-vue: - specifier: ^9.15.1 - version: 9.15.1(eslint@8.45.0) - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 - prettier: - specifier: ^3.0.0 - version: 3.0.0 - ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@18.17.0)(typescript@5.1.6) - tsc-watch: - specifier: ^6.0.4 - version: 6.0.4(typescript@5.1.6) - typescript: - specifier: ~5.1.6 - version: 5.1.6 - vite: - specifier: ^4.4.6 - version: 4.4.6(@types/node@18.17.0) - vue-tsc: - specifier: ^1.8.6 - version: 1.8.6(typescript@5.1.6) + .: + dependencies: + '@esfx/async-readerwriterlock': + specifier: ^1.0.0 + version: 1.0.0 + '@popperjs/core': + specifier: ^2.11.8 + version: 2.11.8 + async-lock: + specifier: ^1.4.0 + version: 1.4.0 + bootstrap: + specifier: ^5.3.1 + version: 5.3.1(@popperjs/core@2.11.8) + bootstrap-vue-next: + specifier: ^0.9.26 + version: 0.9.26(vue@3.3.4) + bson: + specifier: ^5.4.0 + version: 5.4.0 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 + eventemitter3: + specifier: ^5.0.1 + version: 5.0.1 + express: + specifier: ^4.18.2 + version: 4.18.2 + express-session: + specifier: ^1.17.3 + version: 1.17.3 + ky: + specifier: ^0.33.3 + version: 0.33.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + mongoose: + specifier: ^7.4.3 + version: 7.4.3 + pinia: + specifier: ^2.1.4 + version: 2.1.4(typescript@5.1.6)(vue@3.3.4) + reflect-metadata: + specifier: ^0.1.13 + version: 0.1.13 + tslib: + specifier: ^2.6.1 + version: 2.6.1 + vue: + specifier: ^3.3.4 + version: 3.3.4 + vue-router: + specifier: ^4.2.4 + version: 4.2.4(vue@3.3.4) + zod: + specifier: ^3.22.1 + version: 3.22.1 + devDependencies: + '@rushstack/eslint-patch': + specifier: ^1.3.2 + version: 1.3.2 + '@tsconfig/node18': + specifier: ^18.2.0 + version: 18.2.0 + '@types/async-lock': + specifier: ^1.4.0 + version: 1.4.0 + '@types/bootstrap': + specifier: ^5.2.6 + version: 5.2.6 + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 + '@types/express-session': + specifier: ^1.17.7 + version: 1.17.7 + '@types/lodash-es': + specifier: ^4.17.8 + version: 4.17.8 + '@types/node': + specifier: ^18.17.0 + version: 18.17.0 + '@vitejs/plugin-vue': + specifier: ^4.2.3 + version: 4.2.3(vite@4.4.6)(vue@3.3.4) + '@vue/eslint-config-prettier': + specifier: ^8.0.0 + version: 8.0.0(eslint@8.45.0)(prettier@3.0.0) + '@vue/eslint-config-typescript': + specifier: ^11.0.3 + version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.1.6) + '@vue/tsconfig': + specifier: ^0.4.0 + version: 0.4.0 + concurrently: + specifier: ^8.2.0 + version: 8.2.0 + eslint: + specifier: ^8.45.0 + version: 8.45.0 + eslint-plugin-vue: + specifier: ^9.15.1 + version: 9.15.1(eslint@8.45.0) + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + prettier: + specifier: ^3.0.0 + version: 3.0.0 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.17.0)(typescript@5.1.6) + tsc-watch: + specifier: ^6.0.4 + version: 6.0.4(typescript@5.1.6) + typescript: + specifier: ~5.1.6 + version: 5.1.6 + vite: + specifier: ^4.4.6 + version: 4.4.6(@types/node@18.17.0) + vue-tsc: + specifier: ^1.8.6 + version: 1.8.6(typescript@5.1.6) + + '@strpc/client_ky': + dependencies: + '@strpc/def': + specifier: workspace:^ + version: link:../def + devDependencies: + ky: + specifier: ^1.0.1 + version: 1.0.1 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + + '@strpc/def': {} + + '@strpc/express': + dependencies: + '@strpc/def': + specifier: workspace:^ + version: link:../def + devDependencies: + express: + specifier: ^4.18.2 + version: 4.18.2 + express-session: + specifier: ^1.17.3 + version: 1.17.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + zod: + specifier: ^3.22.2 + version: 3.22.2 packages: @@ -1021,7 +1057,6 @@ packages: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 - dev: false /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -1087,7 +1122,6 @@ packages: /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - dev: false /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} @@ -1146,7 +1180,6 @@ packages: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - dev: false /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1221,7 +1254,6 @@ packages: /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - dev: false /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} @@ -1306,26 +1338,21 @@ packages: engines: {node: '>= 0.6'} dependencies: safe-buffer: 5.2.1 - dev: false /content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - dev: false /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - dev: false /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} - dev: false /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - dev: false /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -1379,7 +1406,6 @@ packages: optional: true dependencies: ms: 2.0.0 - dev: false /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -1430,12 +1456,10 @@ packages: /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - dev: false /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dev: false /diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} @@ -1467,7 +1491,6 @@ packages: /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - dev: false /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1476,7 +1499,6 @@ packages: /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} - dev: false /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -1584,7 +1606,6 @@ packages: /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - dev: false /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -1755,7 +1776,6 @@ packages: /etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - dev: false /event-stream@3.3.4: resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} @@ -1817,7 +1837,6 @@ packages: uid-safe: 2.1.5 transitivePeerDependencies: - supports-color - dev: false /express@4.18.2: resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} @@ -1856,7 +1875,6 @@ packages: vary: 1.1.2 transitivePeerDependencies: - supports-color - dev: false /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1918,7 +1936,6 @@ packages: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - dev: false /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -1949,12 +1966,10 @@ packages: /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - dev: false /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - dev: false /from@0.1.7: resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} @@ -2139,7 +2154,6 @@ packages: setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 - dev: false /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} @@ -2156,7 +2170,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: false /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2206,7 +2219,6 @@ packages: /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - dev: false /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} @@ -2406,6 +2418,11 @@ packages: engines: {node: '>=14.16'} dev: false + /ky@1.0.1: + resolution: {integrity: sha512-UvcwpQO0LOuZwG0Ti3VDo6w57KYt+r4bWEYlNaMt82hgyFtse86QtOGum1RzsZni31FndXQl6NvtDArfunt2JQ==} + engines: {node: '>=18'} + dev: true + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -2433,7 +2450,6 @@ packages: /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: false /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2467,7 +2483,6 @@ packages: /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - dev: false /memory-pager@1.5.0: resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} @@ -2482,7 +2497,6 @@ packages: /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - dev: false /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2496,7 +2510,6 @@ packages: /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - dev: false /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} @@ -2509,20 +2522,17 @@ packages: /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: false /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 - dev: false /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true - dev: false /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -2618,14 +2628,12 @@ packages: /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: false /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: false /muggle-string@0.3.1: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} @@ -2647,7 +2655,6 @@ packages: /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - dev: false /nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} @@ -2725,12 +2732,10 @@ packages: engines: {node: '>= 0.8'} dependencies: ee-first: 1.1.1 - dev: false /on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} - dev: false /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2806,7 +2811,6 @@ packages: /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - dev: false /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -2839,7 +2843,6 @@ packages: /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - dev: false /path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} @@ -2936,7 +2939,6 @@ packages: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - dev: false /ps-tree@1.2.0: resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} @@ -2955,7 +2957,6 @@ packages: engines: {node: '>=0.6'} dependencies: side-channel: 1.0.4 - dev: false /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -2964,12 +2965,10 @@ packages: /random-bytes@1.0.0: resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} engines: {node: '>= 0.8'} - dev: false /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - dev: false /raw-body@2.5.1: resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} @@ -2979,7 +2978,6 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: false /read-pkg@3.0.0: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} @@ -3076,7 +3074,6 @@ packages: /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -3088,7 +3085,6 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: false /saslprep@1.0.3: resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==} @@ -3131,7 +3127,6 @@ packages: statuses: 2.0.1 transitivePeerDependencies: - supports-color - dev: false /serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} @@ -3143,11 +3138,9 @@ packages: send: 0.18.0 transitivePeerDependencies: - supports-color - dev: false /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: false /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} @@ -3257,7 +3250,6 @@ packages: /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - dev: false /stream-combiner@0.0.4: resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} @@ -3401,7 +3393,6 @@ packages: /toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - dev: false /tr46@3.0.0: resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} @@ -3495,7 +3486,6 @@ packages: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - dev: false /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} @@ -3545,7 +3535,6 @@ packages: engines: {node: '>= 0.8'} dependencies: random-bytes: 1.0.0 - dev: false /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -3559,7 +3548,6 @@ packages: /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - dev: false /untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} @@ -3579,7 +3567,6 @@ packages: /utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - dev: false /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -3595,7 +3582,6 @@ packages: /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - dev: false /vite@4.4.6(@types/node@18.17.0): resolution: {integrity: sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==} @@ -3810,3 +3796,7 @@ packages: /zod@3.22.1: resolution: {integrity: sha512-+qUhAMl414+Elh+fRNtpU+byrwjDFOS1N7NioLY+tSlcADTx4TkCUua/hxJvxwDXcV4397/nZ420jy4n4+3WUg==} dev: false + + /zod@3.22.2: + resolution: {integrity: sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==} + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..432bec2 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - '@sammo/*' + - '@strpc/*' + - '!**/test/**' \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..302dea6 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "node16", + "moduleResolution": "node16", + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "importHelpers": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "removeComments": false, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "incremental": true, + "sourceMap": true, + "composite": true + }, + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + }, + } + \ No newline at end of file