gemi 0.12.19 → 0.12.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  "export function isConstructor(value: any) {\n return typeof value === \"function\" && value.prototype !== undefined;\n}\n",
6
6
  "import { isConstructor } from \"../internal/isConstructor\";\nimport type { KeyAndValue, KeyAndValueToObject } from \"../internal/type-utils\";\nimport {\n Controller,\n ResourceController,\n type ControllerMethods,\n} from \"./Controller\";\nimport { HttpRequest } from \"./HttpRequest\";\nimport type { MiddlewareReturnType } from \"./Router\";\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\nexport type ApiRouterHandler<Input, Output, Params> = (\n req: HttpRequest<Input, Params>,\n) => Output;\n\ntype CallbackHandler<Input, Output, Params> = (\n req: HttpRequest<Input, Params>,\n) => Promise<Output> | Output;\n\ntype ParseRouteHandler<\n T extends new () => Controller,\n K extends ControllerMethods<T>,\n M extends HttpMethod,\n> = InstanceType<T>[K] extends (\n req: HttpRequest<infer Input, infer Params>,\n) => infer Output\n ? RouteHandler<M, Input, Output, Params>\n : never;\n\nfunction isController(\n candidate: CallbackHandler<any, any, any> | (new () => Controller),\n): candidate is new () => Controller {\n return isConstructor(candidate);\n}\n\nexport class RouteHandler<M extends HttpMethod, Input, Output, Params> {\n __internal_brand = \"RouteHandler\";\n middlewares: string[] = [];\n\n constructor(\n public method: M,\n private handler:\n | CallbackHandler<Input, Output, Params>\n | (new () => Controller),\n private methodName?: any,\n ) {\n this.handler = handler;\n this.methodName = methodName;\n this.method = method;\n }\n\n __internal_use() {\n return {\n run: this.run.bind(this),\n middlewares: this.middlewares,\n };\n }\n\n run(_req: HttpRequest<Input, Params>) {\n if (isController(this.handler)) {\n const controller = new this.handler();\n const handler = controller[this.methodName].bind(controller);\n return handler();\n } else {\n // @ts-ignore\n return this.handler();\n }\n }\n\n middleware(middlewareList: string[]) {\n this.middlewares = middlewareList;\n return this;\n }\n}\n\nexport class FileHandler {\n constructor(...args: ConstructorParameters<typeof RouteHandler>) {\n return new RouteHandler(...args) as any;\n }\n}\n\nexport type RouteHandlers = Partial<{\n post: RouteHandler<\"POST\", any, any, any>;\n get: RouteHandler<\"GET\", any, any, any>;\n delete: RouteHandler<\"DELETE\", any, any, any>;\n put: RouteHandler<\"PUT\", any, any, any>;\n}>;\n\nexport type ApiRoutes = Record<\n string,\n | RouteHandler<any, any, any, any>\n | FileHandler\n | RouteHandlers\n | typeof ApiRouter\n | ResourceRoutes<any>\n>;\n\nexport type ResourceRoutes<T extends new () => ResourceController> = {\n first: {\n get: ParseRouteHandler<T, TestControllerMethod<T, \"list\">, \"GET\">;\n post: ParseRouteHandler<T, TestControllerMethod<T, \"store\">, \"POST\">;\n };\n second: {\n get: ParseRouteHandler<T, TestControllerMethod<T, \"show\">, \"GET\">;\n put: ParseRouteHandler<T, TestControllerMethod<T, \"update\">, \"PUT\">;\n delete: ParseRouteHandler<T, TestControllerMethod<T, \"delete\">, \"DELETE\">;\n };\n};\n\nexport class ApiRouter {\n static __brand = \"ApiRouter\";\n public routes: ApiRoutes = {};\n public middlewares: string[] = [];\n public middleware(_req: HttpRequest<any, any>): MiddlewareReturnType {}\n\n public get<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): RouteHandler<\"GET\", Input, Output, Params>;\n public get<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): ParseRouteHandler<T, K, \"GET\">;\n public get<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new RouteHandler(\"GET\", handler, methodName);\n }\n\n public post<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): RouteHandler<\"POST\", Input, Output, Params>;\n public post<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): ParseRouteHandler<T, K, \"POST\">;\n public post<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new RouteHandler(\"POST\", handler, methodName);\n }\n\n public put<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): RouteHandler<\"PUT\", Input, Output, Params>;\n public put<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): ParseRouteHandler<T, K, \"PUT\">;\n public put<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new RouteHandler(\"PUT\", handler, methodName);\n }\n\n public patch<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): RouteHandler<\"PATCH\", Input, Output, Params>;\n public patch<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): ParseRouteHandler<T, K, \"PATCH\">;\n public patch<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new RouteHandler(\"PATCH\", handler, methodName);\n }\n\n public delete<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): RouteHandler<\"DELETE\", Input, Output, Params>;\n public delete<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): ParseRouteHandler<T, K, \"DELETE\">;\n public delete<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new RouteHandler(\"DELETE\", handler, methodName);\n }\n\n public resource<T extends new () => ResourceController>(Controller: T) {\n return {\n first: {\n get: new RouteHandler(\"GET\", Controller, \"list\"),\n post: new RouteHandler(\"POST\", Controller, \"store\"),\n },\n second: {\n get: new RouteHandler(\"GET\", Controller, \"show\"),\n put: new RouteHandler(\"PUT\", Controller, \"update\"),\n delete: new RouteHandler(\"DELETE\", Controller, \"delete\"),\n },\n } as ResourceRoutes<T>;\n }\n\n public file<Input, Output, Params>(\n handler: CallbackHandler<Input, Output, Params>,\n ): FileHandler;\n public file<T extends new () => Controller, K extends ControllerMethods<T>>(\n handler: T,\n methodName: K,\n ): FileHandler;\n public file<\n T extends CallbackHandler<any, any, any> | (new () => Controller),\n K extends ControllerMethods<any>,\n >(handler: T, methodName?: K) {\n return new FileHandler(\"GET\", handler, methodName);\n }\n}\n\ntype TestControllerMethod<T extends new () => Controller, K extends string> =\n K extends ControllerMethods<T> ? K : never;\n\ntype RouteHandlerParser<T, Prefix extends string = \"\"> =\n T extends RouteHandler<infer Method, infer Input, infer Output, infer Params>\n ? KeyAndValue<\n `${Method & string}:${Prefix & string}`,\n ApiRouterHandler<Input, Output, Params>\n >\n : never;\n\ntype RouteHandlersParser<\n T,\n Prefix extends string = \"\",\n> = T extends RouteHandlers\n ? {\n [K in keyof T]: T[K] extends RouteHandler<\n infer Method,\n infer Input,\n infer Output,\n infer Params\n >\n ? KeyAndValue<\n `${Method & string}:${Prefix & string}`,\n ApiRouterHandler<Input, Output, Params>\n >\n : never;\n }[keyof T]\n : never;\n\ntype RouterInstanceParser<\n T extends new () => ApiRouter,\n Prefix extends string,\n> = T extends new () => ApiRouter\n ? RouteParser<InstanceType<T>[\"routes\"], `${Prefix & string}`>\n : never;\n\ntype ParsePrefixAndKey<\n P extends PropertyKey,\n K extends PropertyKey,\n U = `${P & string}${K & string}`,\n> = U extends \"//\"\n ? \"/\"\n : U extends `${infer T1}//${infer T2}`\n ? `${T1}/${T2}`\n : U extends `${infer T1}/${infer T2}/`\n ? `${T1}/${T2}`\n : U;\n\ntype WithoutId<T> = T extends `${infer Base}/:${string}` ? Base : T;\n\ntype ResourceRoutesParser<\n T extends ResourceRoutes<new () => ResourceController>,\n U extends PropertyKey,\n> =\n | RouteHandlersParser<T[\"first\"], WithoutId<U & string>>\n | RouteHandlersParser<T[\"second\"], `${U & string}`>;\n\ntype RouteParser<\n T extends ApiRoutes,\n Prefix extends PropertyKey = \"\",\n K extends keyof T = keyof T,\n> = K extends any\n ? T[K] extends ResourceRoutes<any>\n ? ResourceRoutesParser<T[K], ParsePrefixAndKey<Prefix, K>>\n : T[K] extends RouteHandler<any, any, any, any>\n ? RouteHandlerParser<T[K], ParsePrefixAndKey<Prefix, K>>\n : T[K] extends new () => ApiRouter\n ? RouterInstanceParser<T[K], ParsePrefixAndKey<Prefix, K>>\n : T[K] extends RouteHandlers\n ? RouteHandlersParser<\n T[K],\n `${Prefix & string}${K extends \"/\" ? \"\" : K & string}`\n >\n : never\n : never;\n\nexport type CreateRPC<\n T extends ApiRouter,\n Prefix extends PropertyKey = \"\",\n> = KeyAndValueToObject<RouteParser<T[\"routes\"], Prefix>>;\n",
7
7
  "import { RequestBreakerError } from \"./Error\";\nimport type { HttpRequest } from \"./HttpRequest\";\n\ntype MiddlewareResult = Partial<{\n headers: Record<string, string>;\n cookies: Record<string, string>;\n}>;\n\nexport type MiddlewareReturnType =\n | void\n | Promise<MiddlewareResult>\n | MiddlewareResult;\n\nexport type RouterMiddleware = (\n req: HttpRequest,\n ctx: any,\n) => MiddlewareReturnType;\n\nexport class ValidationError extends RequestBreakerError {\n errors: Record<string, string[]> = {};\n constructor(errors: Record<string, string[]>) {\n super(\"Validation error\");\n this.name = \"ValidationError\";\n this.errors = errors;\n this.payload = {\n api: {\n status: 400,\n data: {\n error: {\n kind: \"validation_error\",\n messages: errors,\n },\n },\n headers: {\n \"Content-Type\": \"application/json\",\n },\n },\n view: {\n status: 400,\n },\n };\n }\n}\n",
8
- "import { ServiceContainer } from \"../services/ServiceContainer\";\nimport { ApiRouter } from \"./ApiRouter\";\nimport { HttpRequest } from \"./HttpRequest\";\nimport { I18nServiceProvider } from \"./I18nServiceProvider\";\n\nexport class I18nRouter extends ApiRouter {\n middlewares = [\"cache:private,0,no-store\"];\n routes = {\n \"/translations/:locale/:scope*\": this.get(async () => {\n const req = new HttpRequest<any, any>();\n\n const scope = `/${req.params.scope ?? \"\"}`;\n const forcedLocale = req.params.locale;\n\n const locale =\n forcedLocale ?? I18nServiceContainer.use().detectLocale(req);\n\n const translations = I18nServiceContainer.use().getPageTranslations(\n locale,\n scope,\n );\n\n req.ctx().setCookie(\"i18n-locale\", locale, {\n expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),\n });\n\n return {\n [locale]: translations,\n };\n }),\n };\n}\n\nexport class I18nServiceContainer extends ServiceContainer {\n static _name = \"I18nServiceContainer\";\n\n isEnabled = false;\n translations = new Map();\n supportedLocales: string[] = [];\n\n constructor(public service: I18nServiceProvider) {\n super();\n const tmpStore = new Map<string, Map<string, string>>();\n\n for (const [scope, translations] of Object.entries(\n this.service.dictionary,\n )) {\n for (const [key, translation] of Object.entries(translations)) {\n for (const [_locale, value] of Object.entries(translation)) {\n const locale =\n _locale === \"default\" ? this.service.defaultLocale : _locale;\n if (!tmpStore.has(`${locale}.${scope}`)) {\n tmpStore.set(`${locale}.${scope}`, new Map());\n }\n tmpStore.get(`${locale}.${scope}`)?.set(key, value);\n this.isEnabled = true;\n }\n }\n }\n\n const supportedLocales = new Set<string>(service.supportedLocales);\n for (const [key, value] of tmpStore.entries()) {\n this.translations.set(key, Object.fromEntries(value.entries()));\n const [locale] = key.split(\".\");\n if (!supportedLocales.has(locale)) {\n supportedLocales.add(locale);\n }\n }\n this.supportedLocales = Array.from(supportedLocales);\n }\n\n detectLocale(req: HttpRequest<any, any>) {\n const detectedLocale = this.service.detectLocale(req);\n if (this.supportedLocales.includes(detectedLocale)) {\n return detectedLocale;\n }\n\n const previousLocale = req.cookies.get(\"i18n-locale\");\n\n const locale =\n previousLocale ?? (req.headers.get(\"accept-language\") || \"en-US\");\n\n const [_locale] = locale.split(\",\");\n\n if (this.supportedLocales.includes(_locale)) {\n return _locale;\n }\n\n if (_locale.length === 2) {\n for (const supportedLocale of this.supportedLocales) {\n if (supportedLocale.startsWith(_locale)) {\n return supportedLocale;\n }\n }\n }\n\n const fallbackLocale =\n this.service.defaultLocale ?? this.supportedLocales[0];\n\n if (fallbackLocale) {\n return fallbackLocale;\n }\n\n return \"en-US\";\n }\n\n getPageTranslations(locale: string, scope: string) {\n if (!scope) {\n return {};\n }\n const viewTranslations =\n this.translations.get(`${locale}.view:${scope}`) ?? {};\n const out = {\n [`view:${scope}`]: viewTranslations,\n };\n\n for (const [key] of this.translations.entries()) {\n const layoutKey = key.split(\".\")[1];\n\n if (!layoutKey.startsWith(\"layout:\")) {\n continue;\n }\n const layoutScope = layoutKey.split(\":\")[1];\n\n if (scope?.startsWith(layoutScope)) {\n out[layoutKey] = this.translations.get(`${locale}.${layoutKey}`) ?? {};\n }\n }\n\n return out;\n }\n}\n",
8
+ "import { ServiceContainer } from \"../services/ServiceContainer\";\nimport { ApiRouter } from \"./ApiRouter\";\nimport { HttpRequest } from \"./HttpRequest\";\nimport type { I18nServiceProvider } from \"./I18nServiceProvider\";\n\nexport class I18nRouter extends ApiRouter {\n middlewares = [\"cache:private,0,no-store\"];\n routes = {\n \"/translations/:locale/:scope*\": this.get(async () => {\n const req = new HttpRequest<any, any>();\n\n const scope = `/${req.params.scope ?? \"\"}`;\n const forcedLocale = req.params.locale;\n\n const locale =\n forcedLocale ?? I18nServiceContainer.use().detectLocale(req);\n\n const translations = I18nServiceContainer.use().getPageTranslations(\n locale,\n scope,\n );\n\n req.ctx().setCookie(\"i18n-locale\", locale, {\n expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),\n });\n\n return {\n [locale]: translations,\n };\n }),\n };\n}\n\nexport class I18nServiceContainer extends ServiceContainer {\n static _name = \"I18nServiceContainer\";\n\n isEnabled = false;\n translations = new Map();\n supportedLocales: string[] = [];\n\n constructor(public service: I18nServiceProvider) {\n super();\n const tmpStore = new Map<string, Map<string, string>>();\n\n for (const [scope, translations] of Object.entries(\n this.service.dictionary,\n )) {\n for (const [key, translation] of Object.entries(translations)) {\n for (const [_locale, value] of Object.entries(translation)) {\n const locale =\n _locale === \"default\" ? this.service.defaultLocale : _locale;\n if (!tmpStore.has(`${locale}.${scope}`)) {\n tmpStore.set(`${locale}.${scope}`, new Map());\n }\n tmpStore.get(`${locale}.${scope}`)?.set(key, value);\n this.isEnabled = true;\n }\n }\n }\n\n const supportedLocales = new Set<string>(service.supportedLocales);\n for (const [key, value] of tmpStore.entries()) {\n this.translations.set(key, Object.fromEntries(value.entries()));\n const [locale] = key.split(\".\");\n if (!supportedLocales.has(locale)) {\n supportedLocales.add(locale);\n }\n }\n this.supportedLocales = Array.from(supportedLocales);\n }\n\n detectLocale(req: HttpRequest<any, any>) {\n const detectedLocale = this.service.detectLocale(req);\n if (this.supportedLocales.includes(detectedLocale)) {\n return detectedLocale;\n }\n\n const previousLocale = req.cookies.get(\"i18n-locale\");\n\n const locale =\n previousLocale ?? (req.headers.get(\"accept-language\") || \"en-US\");\n\n const [_locale] = locale.split(\",\");\n\n if (this.supportedLocales.includes(_locale)) {\n return _locale;\n }\n\n if (_locale.length === 2) {\n for (const supportedLocale of this.supportedLocales) {\n if (supportedLocale.startsWith(_locale)) {\n return supportedLocale;\n }\n }\n }\n\n const fallbackLocale =\n this.service.defaultLocale ?? this.supportedLocales[0];\n\n if (fallbackLocale) {\n return fallbackLocale;\n }\n\n return \"en-US\";\n }\n\n getPageTranslations(locale: string, scope: string) {\n if (!scope) {\n return {};\n }\n const viewTranslations =\n this.translations.get(`${locale}.view:${scope}`) ?? {};\n const out = {\n [`view:${scope}`]: viewTranslations,\n };\n\n for (const [key] of this.translations.entries()) {\n const layoutKey = key.split(\".\")[1];\n\n if (!layoutKey.startsWith(\"layout:\")) {\n continue;\n }\n const layoutScope = layoutKey.split(\":\")[1];\n\n if (scope?.startsWith(layoutScope)) {\n out[layoutKey] = this.translations.get(`${locale}.${layoutKey}`) ?? {};\n }\n }\n\n return out;\n }\n}\n",
9
9
  "import { AsyncLocalStorage } from \"async_hooks\";\nimport { Cookie, type CreateCookieOptions } from \"./Cookie\";\nimport { HttpRequest } from \"./HttpRequest\";\n\nconst requestContext = new AsyncLocalStorage<Store>();\n\nclass Store {\n cookies: Set<Cookie> = new Set();\n headers: Headers = new Headers();\n prefetchedResources = new Map<string, Record<string, any>>();\n prefetchPromiseQueue = new Set<() => Promise<any>>();\n user: any = null;\n csrfHmac: string | null = null;\n\n constructor(public req: HttpRequest) {}\n\n setCSRFHmac(hmac: string) {\n this.csrfHmac = hmac;\n }\n\n setCookie(name: string, value: string, options: CreateCookieOptions = {}) {\n this.cookies.add(new Cookie(name, value, options));\n }\n\n deleteCookie(name: string) {\n this.cookies.add(new Cookie(name, \"\", { maxAge: -1 }));\n }\n\n setHeaders(name: string, value: string) {\n this.headers.set(name, value);\n }\n\n setUser(user: any) {\n this.user = user;\n }\n\n setRequest(req: HttpRequest<any, any>) {\n this.req = req;\n }\n\n destroy() {\n delete this.cookies;\n delete this.headers;\n delete this.prefetchedResources;\n delete this.prefetchPromiseQueue;\n delete this.user;\n }\n}\n\nexport class RequestContext {\n static getStore() {\n return requestContext.getStore()!;\n }\n\n static setRequest(req: HttpRequest<any, any>) {\n requestContext.getStore().req = req;\n }\n\n static run<T>(httpRequest: HttpRequest, fn: () => T): T {\n return requestContext.run(new Store(httpRequest), fn);\n }\n}\n",
10
10
  "export interface CreateCookieOptions {\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"Strict\" | \"Lax\";\n path?: string;\n domain?: string;\n partitioned?: boolean;\n}\n\nexport class Cookie {\n constructor(\n private name: string,\n private value: string,\n private options: CreateCookieOptions = {},\n ) {}\n\n toString() {\n return [\n `${this.name}=${this.value}`,\n this.options.maxAge ? `Max-Age=${this.options.maxAge}` : \"\",\n this.options.httpOnly ? \"HttpOnly\" : \"\",\n this.options.secure ? \"Secure\" : \"\",\n this.options.sameSite\n ? `SameSite=${this.options.sameSite}`\n : \"SameSite=Strict\",\n this.options.path ? `Path=${this.options.path}` : \"Path=/\",\n this.options.domain ? `Domain=${this.options.domain}` : \"\",\n this.options.expires\n ? `Expires=${this.options.expires.toUTCString()}`\n : \"\",\n this.options.partitioned ? \"Partitioned\" : \"\",\n ]\n .filter((i) => i !== \"\")\n .join(\"; \");\n }\n}\n",
11
11
  "import { I18n } from \"../facades\";\nimport { I18nServiceContainer } from \"./I18nServiceContainer\";\nimport { RequestContext } from \"./requestContext\";\nimport { ValidationError } from \"./Router\";\n\nclass Input<T> {\n constructor(private data: T) {}\n\n public get<K extends keyof T>(key: K): T[K] {\n return this.data[key];\n }\n\n public has(key: keyof T) {\n return this.data[key] !== undefined;\n }\n\n public toJSON(): T {\n return this.data;\n }\n}\n\n// Formats B KB MB GB TB\n// e.g parseFileSizeString(\"1MB\") => 1024 * 1024\nfunction parseFileSizeString(size: string) {\n const [number, unit] = size.match(/\\d+|\\D+/g) ?? [];\n if (!number || !unit) {\n return 0;\n }\n const fileSize = parseInt(number);\n switch (unit) {\n case \"B\":\n return fileSize;\n case \"KB\":\n return fileSize * 1024;\n case \"MB\":\n return fileSize * 1024 * 1024;\n case \"GB\":\n return fileSize * 1024 * 1024 * 1024;\n case \"TB\":\n return fileSize * 1024 * 1024 * 1024 * 1024;\n default:\n return 0;\n }\n}\n\n// Formats png, jpg, ttf, excel, csv, word, pdf, json\n// Eg. png => image/png\nfunction parseFileTypeString(type: string) {\n switch (type) {\n case \"image\":\n return \"image\";\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n return \"image/jpeg\";\n case \"jpeg\":\n return \"image/jpeg\";\n case \"ttf\":\n return \"font/ttf\";\n case \"excel\":\n return \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n case \"csv\":\n return \"text/csv\";\n case \"word\":\n return \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\";\n case \"pdf\":\n return \"application/pdf\";\n case \"json\":\n return \"application/json\";\n default:\n return type;\n }\n}\n\nfunction validate(ruleName: string) {\n const [rule, param] = ruleName.split(\":\");\n switch (rule) {\n case \"required\":\n return (value: any) => {\n if (value instanceof Blob) {\n return value.size > 0;\n }\n return value !== null && value !== undefined && value?.length > 0;\n };\n case \"password\":\n return (value: any) => {\n // min 8 characters\n // at least one uppercase letter,\n // at least one lowercase letter and one number\n // at least one special character\n const passwordRegex =\n /^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;\n return passwordRegex.test(value);\n };\n\n case \"number\":\n return (value: any) => {\n if (typeof value !== \"number\") return false;\n\n return !isNaN(value);\n };\n case \"min\":\n return (value: any) => {\n return value?.length >= parseInt(param);\n };\n case \"max\":\n return (value: any) => {\n return value?.length <= parseInt(param);\n };\n case \"email\":\n return (value: any) => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(value);\n };\n case \"file\":\n return (value: any) => {\n return value instanceof Blob;\n };\n case \"fileType\":\n return (value: Blob) => {\n if (value instanceof Blob) {\n const parsedType = parseFileTypeString(param);\n return value.type.startsWith(parsedType);\n }\n };\n\n case \"fileSize\":\n return (value: Blob) => {\n if (value instanceof Blob) {\n const absoluteSize = parseFileSizeString(param);\n return value.size <= absoluteSize;\n }\n };\n default:\n return () => true;\n }\n}\n\ntype StringType = \"string\";\ntype NumberType = \"number\";\ntype BooleanType = \"boolean\";\ntype MinLengthType = `min:${number}`;\ntype MaxLengthType = `max:${number}`;\ntype RequiredType = \"required\";\ntype FileType = \"file\";\ntype FileTypeType = \"fileType:${string}\";\ntype FileSizeType = \"fileSize:${string}\";\ntype SchemaKey =\n | StringType\n | NumberType\n | BooleanType\n | MinLengthType\n | MaxLengthType\n | RequiredType\n | FileType\n | FileTypeType\n | FileSizeType;\n\nexport type Schema<T extends Body> = Record<\n keyof T,\n Partial<Record<SchemaKey, string>>\n>;\n\nexport type Body = Record<string, any>;\nexport type HttpRequestKind = \"view\" | \"api\";\n\nexport class HttpRequest<\n T extends Body = Record<string, never>,\n Params = Record<string, never>,\n> {\n kind: HttpRequestKind;\n rawRequest: Request;\n headers: Omit<Headers, \"set\" | \"delete\">;\n cookies: Omit<Map<string, string>, \"set\" | \"delete\">;\n search: Input<T>;\n schema: any = {};\n routePath: string;\n params: Params;\n\n constructor(\n req?: Request,\n params?: any,\n kind?: HttpRequestKind,\n routePath?: string,\n ) {\n if (!req) {\n const _req = RequestContext.getStore().req;\n this.params = _req.params as any;\n this.rawRequest = _req.rawRequest;\n this.kind = _req.kind;\n this.routePath = _req.routePath;\n } else {\n this.params = params;\n this.rawRequest = req;\n this.routePath = routePath;\n this.kind = kind ?? \"api\";\n }\n\n this.headers = this.rawRequest.headers;\n\n const cookie = this.rawRequest.headers.get(\"Cookie\");\n const cookies = new Map();\n if (cookie) {\n const cookieArray = cookie.split(\";\");\n for (const c of cookieArray) {\n const [key, value] = c.split(\"=\");\n cookies.set(key.trim(), value.trim());\n }\n }\n if (this.rawRequest.method === \"GET\") {\n const url = new URL(this.rawRequest.url);\n const map = new Map<string, string | string[]>();\n for (const [key, value] of url.searchParams) {\n if (map.has(key)) {\n const currentValue = map.get(key);\n if (Array.isArray(currentValue)) {\n currentValue.push(value);\n map.set(key, currentValue);\n } else {\n map.set(key, [currentValue, value]);\n }\n } else {\n map.set(key, value);\n }\n }\n const params = Object.fromEntries(map.entries());\n this.search = new Input<T>(params as T);\n }\n this.cookies = cookies;\n }\n\n locale() {\n return I18nServiceContainer.use().detectLocale(this);\n }\n\n ctx() {\n return RequestContext.getStore();\n }\n\n refine(_input: any): any {\n return {};\n }\n\n private async parseBody() {\n let inputMap = new Input<T>({} as T);\n if (this.rawRequest.headers.get(\"Content-Type\") === \"application/json\") {\n const body = await this.rawRequest.json();\n inputMap = new Input<T>(body as T);\n }\n if (\n this.rawRequest.headers.get(\"Content-Type\") ===\n \"application/x-www-form-urlencoded\"\n ) {\n const body = (await this.rawRequest.formData()) as any; // TODO: fix type\n inputMap = new Input<T>(body as T);\n }\n\n if (\n this.rawRequest.headers\n .get(\"Content-Type\")\n ?.startsWith(\"multipart/form-data\")\n ) {\n const body = (await this.rawRequest.formData()) as any; // TODO: fix type\n const _inputMap = new Map<string, any>();\n for (const [key, value] of body.entries()) {\n if (_inputMap.has(key)) {\n const currentValue = _inputMap.get(key);\n if (Array.isArray(currentValue)) {\n currentValue.push(value);\n _inputMap.set(key, currentValue);\n } else {\n _inputMap.set(key, [currentValue, value] as any);\n }\n } else {\n _inputMap.set(key, value as T[keyof T]);\n }\n }\n inputMap = new Input<T>(Object.fromEntries(_inputMap.entries()) as T);\n }\n return inputMap;\n }\n\n private validateInput(input: Input<T>) {\n const errors: Record<string, string[]> = {};\n for (const [key, rules] of Object.entries(this.schema)) {\n for (const [rule, message] of Object.entries(rules)) {\n const validator = validate(rule);\n\n let _message = message;\n let _isValid = false;\n if (typeof message === \"function\") {\n _message = message(input.get(key));\n _isValid = typeof _message === \"undefined\";\n } else {\n _isValid = validator(input.get(key));\n }\n\n if (_isValid) {\n continue;\n }\n\n if (!errors[key]) {\n errors[key] = [];\n }\n if (rule === \"required\") {\n errors[key] = [String(_message)];\n break;\n } else {\n errors[key].push(String(_message));\n }\n }\n }\n\n for (const [key, value] of Object.entries(\n this.refine(input.toJSON()) ?? {},\n )) {\n if (!errors[key]) {\n errors[key] = [];\n }\n errors[key] = [...(errors[key] ?? []), value as string];\n }\n\n if (Object.keys(errors).length > 0) {\n throw new ValidationError(errors);\n } else {\n return input;\n }\n }\n\n async input(): Promise<Input<T>> {\n return this.validateInput(await this.parseBody());\n }\n\n async safeInput(): Promise<{\n isValid: boolean;\n errors: Record<string, string[]>;\n input: Input<T>;\n }> {\n const input = await this.parseBody();\n try {\n this.validateInput(input);\n return {\n isValid: true,\n errors: {},\n input,\n };\n } catch (err) {\n if (!(err instanceof ValidationError)) {\n throw err;\n }\n return {\n isValid: false,\n errors: err.errors,\n input,\n };\n }\n }\n}\n"
@@ -1 +1 @@
1
- {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../client/ClientRouter.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAqB/E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;KACrC;CACF;AA6MD,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IACxD,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACpD,4CAuCA,CAAC"}
1
+ {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../client/ClientRouter.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAqB/E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;KACrC;CACF;AA+MD,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IACxD,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACpD,4CAuCA,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useLocale.d.ts","sourceRoot":"","sources":["../../../client/i18n/useLocale.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,+BAOU,MAAM,oBAMxC"}
1
+ {"version":3,"file":"useLocale.d.ts","sourceRoot":"","sources":["../../../client/i18n/useLocale.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,+BAKU,MAAM,oBAMxC"}
@@ -31327,12 +31327,12 @@ function restoreScroll(action = null, _pathname = "no path") {
31327
31327
  const key = [pathname, hash, search].join("");
31328
31328
  const sh = window.scrollHistory;
31329
31329
  const scrollPosition = sh == null ? void 0 : sh.get(key);
31330
- if (!scrollPosition) {
31331
- return;
31332
- }
31333
31330
  if (action !== Action.Pop) {
31334
31331
  window.scrollTo(0, 0);
31335
31332
  } else {
31333
+ if (!scrollPosition) {
31334
+ return;
31335
+ }
31336
31336
  window.scrollTo(0, scrollPosition ?? 0);
31337
31337
  }
31338
31338
  sh == null ? void 0 : sh.delete(key);
@@ -31728,7 +31728,6 @@ function useLocale() {
31728
31728
  const { changeLocale, locale, fetchTranslations } = useContext(I18nContext);
31729
31729
  const { getRoutePathnameFromHref } = useContext(ClientRouterContext);
31730
31730
  const { pathname } = useLocation();
31731
- console.log({ pathname });
31732
31731
  const setLocale = async (locale2) => {
31733
31732
  await fetchTranslations(getRoutePathnameFromHref(pathname), locale2);
31734
31733
  changeLocale(locale2);