@forinda/kickjs 5.6.0 → 5.7.0

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.
Files changed (90) hide show
  1. package/dist/{adapter-0r2uRCD3.d.mts → adapter-CoJp35rz.d.mts} +2 -2
  2. package/dist/{adapter-0r2uRCD3.d.mts.map → adapter-CoJp35rz.d.mts.map} +1 -1
  3. package/dist/{app-module-CzlIIjO3.d.mts → app-module-BE7hAASB.d.mts} +2 -2
  4. package/dist/{app-module-CzlIIjO3.d.mts.map → app-module-BE7hAASB.d.mts.map} +1 -1
  5. package/dist/{application-YJZ2frWX.mjs → application-Bg_-CIPK.mjs} +3 -3
  6. package/dist/{application-YJZ2frWX.mjs.map → application-Bg_-CIPK.mjs.map} +1 -1
  7. package/dist/{application-CaEYca9E.d.mts → application-DmekGKp7.d.mts} +5 -5
  8. package/dist/{application-CaEYca9E.d.mts.map → application-DmekGKp7.d.mts.map} +1 -1
  9. package/dist/{bootstrap-Db8k2-21.d.mts → bootstrap-CwP2GGu0.d.mts} +2 -2
  10. package/dist/{bootstrap-Db8k2-21.d.mts.map → bootstrap-CwP2GGu0.d.mts.map} +1 -1
  11. package/dist/{bootstrap-UCZoqbbW.mjs → bootstrap-D86s_Aac.mjs} +3 -3
  12. package/dist/{bootstrap-UCZoqbbW.mjs.map → bootstrap-D86s_Aac.mjs.map} +1 -1
  13. package/dist/config/index.d.mts +1 -1
  14. package/dist/config/index.mjs +2 -2
  15. package/dist/{config-D6VaNpwo.mjs → config-BVvCHSX2.mjs} +3 -3
  16. package/dist/{config-D6VaNpwo.mjs.map → config-BVvCHSX2.mjs.map} +1 -1
  17. package/dist/{container-D0v17gF8.mjs → container-COmj1vM3.mjs} +3 -3
  18. package/dist/{container-D0v17gF8.mjs.map → container-COmj1vM3.mjs.map} +1 -1
  19. package/dist/{context-CbX_T0XC.mjs → context-CvJQzbBF.mjs} +3 -3
  20. package/dist/{context-CbX_T0XC.mjs.map → context-CvJQzbBF.mjs.map} +1 -1
  21. package/dist/{context-decorator-BgdDd-6X.d.mts → context-decorator-BYf8HdMl.d.mts} +2 -2
  22. package/dist/{context-decorator-BgdDd-6X.d.mts.map → context-decorator-BYf8HdMl.d.mts.map} +1 -1
  23. package/dist/core/adapter.d.mts +1 -1
  24. package/dist/core/adapter.mjs +1 -1
  25. package/dist/core/app-module.d.mts +1 -1
  26. package/dist/core/app-module.mjs +1 -1
  27. package/dist/core/cache.mjs +1 -1
  28. package/dist/core/container.mjs +2 -2
  29. package/dist/core/cron.mjs +2 -2
  30. package/dist/core/decorators.d.mts +2 -2
  31. package/dist/core/decorators.mjs +2 -2
  32. package/dist/core/decorators.mjs.map +1 -1
  33. package/dist/core/errors.mjs +1 -1
  34. package/dist/core/interfaces.mjs +1 -1
  35. package/dist/core/logger.mjs +1 -1
  36. package/dist/core/path.mjs +1 -1
  37. package/dist/core/plugin.d.mts +1 -1
  38. package/dist/core/plugin.mjs +1 -1
  39. package/dist/core/reactivity.mjs +1 -1
  40. package/dist/{core-DvTHNOay.mjs → core-CJKmg8QR.mjs} +3 -3
  41. package/dist/{core-DvTHNOay.mjs.map → core-CJKmg8QR.mjs.map} +1 -1
  42. package/dist/{decorators-J5mC7D-6.d.mts → decorators-ZcjsV1O0.d.mts} +40 -13
  43. package/dist/decorators-ZcjsV1O0.d.mts.map +1 -0
  44. package/dist/{env-yTMEMpV6.mjs → env-DfB1WNRf.mjs} +3 -3
  45. package/dist/{env-yTMEMpV6.mjs.map → env-DfB1WNRf.mjs.map} +1 -1
  46. package/dist/http/application.d.mts +1 -1
  47. package/dist/http/application.mjs +2 -2
  48. package/dist/http/bootstrap.d.mts +1 -1
  49. package/dist/http/bootstrap.mjs +2 -2
  50. package/dist/http/context.mjs +2 -2
  51. package/dist/http/middleware/cors.mjs +1 -1
  52. package/dist/http/middleware/csrf.mjs +1 -1
  53. package/dist/http/middleware/error-handler.mjs +2 -2
  54. package/dist/http/middleware/helmet.mjs +1 -1
  55. package/dist/http/middleware/rate-limit.mjs +1 -1
  56. package/dist/http/middleware/request-id.mjs +1 -1
  57. package/dist/http/middleware/request-logger.mjs +2 -2
  58. package/dist/http/middleware/session.mjs +1 -1
  59. package/dist/http/middleware/spa.d.mts +1 -1
  60. package/dist/http/middleware/spa.mjs +2 -2
  61. package/dist/http/middleware/upload.d.mts +1 -1
  62. package/dist/http/middleware/upload.mjs +1 -1
  63. package/dist/http/middleware/validate.mjs +2 -2
  64. package/dist/http/middleware/views.d.mts +1 -1
  65. package/dist/http/middleware/views.mjs +2 -2
  66. package/dist/http/query/index.mjs +2 -2
  67. package/dist/http/router-builder.d.mts +1 -1
  68. package/dist/http/router-builder.mjs +2 -2
  69. package/dist/{index-D-Wb23e6.d.mts → index-CkKLXZHg.d.mts} +5 -5
  70. package/dist/{index-D-Wb23e6.d.mts.map → index-CkKLXZHg.d.mts.map} +1 -1
  71. package/dist/{index-BbtF8kIr.d.mts → index-oB1CDq5i.d.mts} +2 -2
  72. package/dist/{index-BbtF8kIr.d.mts.map → index-oB1CDq5i.d.mts.map} +1 -1
  73. package/dist/index.d.mts +14 -14
  74. package/dist/index.mjs +2 -2
  75. package/dist/{metadata-IHiynOCv.mjs → metadata-D9F5Lm-z.mjs} +2 -2
  76. package/dist/{metadata-IHiynOCv.mjs.map → metadata-D9F5Lm-z.mjs.map} +1 -1
  77. package/dist/{plugin-JMkG7soG.d.mts → plugin-NMHVmDRF.d.mts} +4 -4
  78. package/dist/{plugin-JMkG7soG.d.mts.map → plugin-NMHVmDRF.d.mts.map} +1 -1
  79. package/dist/{query-CQU-Hyiv.mjs → query-Di7R8qNX.mjs} +2 -2
  80. package/dist/{query-CQU-Hyiv.mjs.map → query-Di7R8qNX.mjs.map} +1 -1
  81. package/dist/{router-builder-CaQ629tw.d.mts → router-builder-BfCCeQB-.d.mts} +2 -2
  82. package/dist/{router-builder-CaQ629tw.d.mts.map → router-builder-BfCCeQB-.d.mts.map} +1 -1
  83. package/dist/{spa-CreyQc4N.d.mts → spa-DIXtRBj-.d.mts} +2 -2
  84. package/dist/{spa-CreyQc4N.d.mts.map → spa-DIXtRBj-.d.mts.map} +1 -1
  85. package/dist/{upload-tGMrlhEB.d.mts → upload-DqRwWhX0.d.mts} +2 -2
  86. package/dist/{upload-tGMrlhEB.d.mts.map → upload-DqRwWhX0.d.mts.map} +1 -1
  87. package/dist/{views-BMhrZsH9.d.mts → views-DDT9vghc.d.mts} +3 -3
  88. package/dist/{views-BMhrZsH9.d.mts.map → views-DDT9vghc.d.mts.map} +1 -1
  89. package/package.json +2 -2
  90. package/dist/decorators-J5mC7D-6.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-JMkG7soG.d.mts","names":[],"sources":["../src/core/module-registry.ts","../src/core/plugin.ts"],"mappings":";;;;;;;;;;;;AAiCA;;;;;;;;;AAuBA;;;;;;;;;;;;;;;;;UAvBiB,cAAA;;AC0BjB;;;;;;;;;EDfE,KAAA,CAAM,MAAA,EAAQ,cAAA;AAAA;;;;;;;;;;cAYH,qBAAA,YAAiC,cAAA;EAAA,SACnC,OAAA,EAAS,cAAA;EAElB,KAAA,CAAM,MAAA,EAAQ,cAAA;AAAA;;;AA1BhB;;;;;;;;;AAuBA;;;;;;;;;;;;;;;;;;;ACGA;;;;;;;;;;;;;;;;;;;;;;;;AD1BA,UC0BiB,UAAA;EAsER;EApEP,IAAA;EA0Ea;;;;;;;;;;;;;;;;;;EAtDb,SAAA,YAAqB,gBAAA;;;;;EAMrB,QAAA,EAAU,SAAA,EAAW,SAAA;;;;;;;;;;;;;;EAerB,OAAA,KAAY,cAAA;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BZ,KAAA,EAAO,QAAA,EAAU,cAAA;;;;;EAMjB,QAAA,KAAa,UAAA;;;;;EAMb,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCA,YAAA,KAAiB,wBAAA;;;;;EAMjB,OAAA,EAAS,SAAA,EAAW,SAAA,UAAmB,OAAA;;;;;EAMvC,QAAA,YAAoB,OAAA;;;;;;;;;;;;;EAcpB,UAAA,eAAyB,OAAA;;;;;;EAOzB,YAAA;AAAA"}
1
+ {"version":3,"file":"plugin-NMHVmDRF.d.mts","names":[],"sources":["../src/core/module-registry.ts","../src/core/plugin.ts"],"mappings":";;;;;;;;;;;;AAiCA;;;;;;;;;AAuBA;;;;;;;;;;;;;;;;;UAvBiB,cAAA;;AC0BjB;;;;;;;;;EDfE,KAAA,CAAM,MAAA,EAAQ,cAAA;AAAA;;;;;;;;;;cAYH,qBAAA,YAAiC,cAAA;EAAA,SACnC,OAAA,EAAS,cAAA;EAElB,KAAA,CAAM,MAAA,EAAQ,cAAA;AAAA;;;AA1BhB;;;;;;;;;AAuBA;;;;;;;;;;;;;;;;;;;ACGA;;;;;;;;;;;;;;;;;;;;;;;;AD1BA,UC0BiB,UAAA;EAsER;EApEP,IAAA;EA0Ea;;;;;;;;;;;;;;;;;;EAtDb,SAAA,YAAqB,gBAAA;;;;;EAMrB,QAAA,EAAU,SAAA,EAAW,SAAA;;;;;;;;;;;;;;EAerB,OAAA,KAAY,cAAA;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BZ,KAAA,EAAO,QAAA,EAAU,cAAA;;;;;EAMjB,QAAA,KAAa,UAAA;;;;;EAMb,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCA,YAAA,KAAiB,wBAAA;;;;;EAMjB,OAAA,EAAS,SAAA,EAAW,SAAA,UAAmB,OAAA;;;;;EAMvC,QAAA,YAAoB,OAAA;;;;;;;;;;;;;EAcpB,UAAA,eAAyB,OAAA;;;;;;EAOzB,YAAA;AAAA"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v5.6.0
2
+ * @forinda/kickjs v5.7.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -9,4 +9,4 @@
9
9
  * @license MIT
10
10
  */
11
11
  const FILTER_OPERATORS=new Set([`eq`,`neq`,`gt`,`gte`,`lt`,`lte`,`between`,`in`,`contains`,`starts`,`ends`]);function parseFilters(filterParam,allowedFields){if(!filterParam)return[];let items=Array.isArray(filterParam)?filterParam:[filterParam],results=[],allowed=allowedFields?new Set(allowedFields):null;for(let item of items){let firstColon=item.indexOf(`:`);if(firstColon===-1)continue;let secondColon=item.indexOf(`:`,firstColon+1);if(secondColon===-1)continue;let field=item.slice(0,firstColon),operator=item.slice(firstColon+1,secondColon),value=item.slice(secondColon+1);!field||!value||FILTER_OPERATORS.has(operator)&&(allowed&&!allowed.has(field)||results.push({field,operator,value}))}return results}function parseSort(sortParam,allowedFields){if(!sortParam)return[];let items=Array.isArray(sortParam)?sortParam:[sortParam],results=[],allowed=allowedFields?new Set(allowedFields):null;for(let item of items){let lastColon=item.lastIndexOf(`:`);if(lastColon===-1)continue;let field=item.slice(0,lastColon),dir=item.slice(lastColon+1).toLowerCase();field&&(dir!==`asc`&&dir!==`desc`||allowed&&!allowed.has(field)||results.push({field,direction:dir}))}return results}function parsePagination(params){let page=typeof params.page==`string`?Number.parseInt(params.page,10):params.page??1,limit=typeof params.limit==`string`?Number.parseInt(params.limit,10):params.limit??20;return(Number.isNaN(page)||page<1)&&(page=1),(Number.isNaN(limit)||limit<1)&&(limit=20),limit>100&&(limit=100),{page,limit,offset:(page-1)*limit}}function parseSearchQuery(q){return q?q.trim().slice(0,200):``}function normalizeFieldConfig(config){if(config)return`columns`in config&&config.columns&&typeof config.columns==`object`?{filterable:Object.keys(config.columns),sortable:config.sortable?Object.keys(config.sortable):void 0,searchable:void 0}:config}function parseQuery(query,fieldConfig){let normalized=normalizeFieldConfig(fieldConfig);return{filters:parseFilters(query.filter,normalized?.filterable),sort:parseSort(query.sort,normalized?.sortable),pagination:parsePagination({page:query.page,limit:query.limit}),search:parseSearchQuery(query.q)}}function buildQueryParams(parsed){let params={};return parsed.filters?.length&&(params.filter=parsed.filters.map(f=>`${f.field}:${f.operator}:${f.value}`)),parsed.sort?.length&&(params.sort=parsed.sort.map(s=>`${s.field}:${s.direction}`)),parsed.pagination&&(params.page=parsed.pagination.page,params.limit=parsed.pagination.limit),parsed.search&&(params.q=parsed.search),params}export{parseSearchQuery as a,parseQuery as i,parseFilters as n,parseSort as o,parsePagination as r,FILTER_OPERATORS as s,buildQueryParams as t};
12
- //# sourceMappingURL=query-CQU-Hyiv.mjs.map
12
+ //# sourceMappingURL=query-Di7R8qNX.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-CQU-Hyiv.mjs","names":[],"sources":["../src/http/query/types.ts","../src/http/query/parse-query.ts"],"sourcesContent":["/** Supported filter operators for query string parsing */\nexport type FilterOperator =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'between'\n | 'in'\n | 'contains'\n | 'starts'\n | 'ends'\n\nexport const FILTER_OPERATORS = new Set<string>([\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n 'in',\n 'contains',\n 'starts',\n 'ends',\n])\n\nexport interface FilterItem {\n field: string\n operator: FilterOperator\n value: string\n}\n\nexport interface SortItem {\n field: string\n direction: 'asc' | 'desc'\n}\n\nexport interface PaginationParams {\n page: number\n limit: number\n offset: number\n}\n\n/**\n * The result of parsing a query string. ORM-agnostic — pass this to\n * a query builder adapter (Drizzle, Prisma, Sequelize, etc.) to produce\n * database-specific query objects.\n */\nexport interface ParsedQuery {\n filters: FilterItem[]\n sort: SortItem[]\n pagination: PaginationParams\n search: string\n}\n\n/**\n * Helper that extracts the literal field union from a `QueryFieldConfig`\n * key. When the user passes `{ filterable: ['status', 'category'] } as const`,\n * `FieldsOf<typeof config, 'filterable'>` resolves to `'status' | 'category'`.\n *\n * Without `as const`, the arrays widen to `string[]` and the union falls\n * back to `string`. This is the documented escape hatch.\n */\nexport type FieldsOf<\n TConfig extends QueryFieldConfig | undefined,\n K extends 'filterable' | 'sortable' | 'searchable',\n> = TConfig extends { readonly [P in K]: readonly (infer F)[] }\n ? F extends string\n ? F\n : string\n : TConfig extends { columns: infer C }\n ? K extends 'filterable'\n ? keyof C & string\n : string\n : string\n\n/**\n * Narrowed `ParsedQuery` whose `filters[].field` and `sort[].field`\n * unions are constrained to the literal whitelist passed to\n * `ctx.qs()` / `parseQuery()`. Extends `ParsedQuery`, so any function\n * accepting `ParsedQuery` accepts a `TypedParsedQuery<X>` automatically\n * (subtype assignment, no codegen, backward compatible).\n *\n * @example\n * ```ts\n * const parsed = ctx.qs({\n * filterable: ['status', 'priority'],\n * sortable: ['createdAt'],\n * } as const)\n * parsed.filters[0]?.field // 'status' | 'priority'\n * parsed.sort[0]?.field // 'createdAt'\n * ```\n */\nexport interface TypedParsedQuery<\n TConfig extends QueryFieldConfig | undefined,\n> extends ParsedQuery {\n filters: Array<FilterItem & { field: FieldsOf<TConfig, 'filterable'> }>\n sort: Array<SortItem & { field: FieldsOf<TConfig, 'sortable'> }>\n}\n\n/**\n * Restrict which fields can be filtered, sorted, or searched.\n * Fields not in the allow-list are silently ignored.\n *\n * Accepts two forms:\n * 1. **String arrays** (standard): `{ filterable: ['name', 'status'], sortable: ['createdAt'] }`\n * 2. **Column-object maps** (Drizzle-style): `{ columns: { name: col, status: col }, sortable: { createdAt: col } }`\n *\n * When column-object maps are provided, `Object.keys()` is used to derive the field names.\n */\nexport type QueryFieldConfig = StringQueryFieldConfig | ColumnQueryFieldConfig\n\nexport interface StringQueryFieldConfig {\n filterable?: string[]\n sortable?: string[]\n searchable?: string[]\n}\n\n/**\n * Column-object-based field config (e.g., from DrizzleQueryParamsConfig).\n * Keys are the field names used in query strings; values are ORM column references.\n */\nexport interface ColumnQueryFieldConfig {\n columns: Record<string, any>\n sortable?: Record<string, any>\n searchColumns?: any[]\n [key: string]: any\n}\n\n/** Standardized paginated response shape */\nexport interface PaginatedResponse<T = any> {\n data: T[]\n meta: {\n page: number\n limit: number\n total: number\n totalPages: number\n hasNext: boolean\n hasPrev: boolean\n }\n}\n\n/**\n * Interface for ORM-specific query builder adapters.\n * Implement this to translate a `ParsedQuery` into your ORM's query format.\n *\n * @example\n * ```ts\n * // Drizzle adapter\n * class DrizzleQueryAdapter implements QueryBuilderAdapter<DrizzleQueryResult> {\n * build(parsed: ParsedQuery, config: DrizzleConfig): DrizzleQueryResult {\n * // Convert filters → Drizzle SQL conditions\n * // Convert sort → Drizzle orderBy\n * return { where, orderBy, limit, offset }\n * }\n * }\n *\n * // Prisma adapter\n * class PrismaQueryAdapter implements QueryBuilderAdapter<PrismaQueryResult> {\n * build(parsed: ParsedQuery, config: PrismaConfig): PrismaQueryResult {\n * return { where, orderBy, skip, take }\n * }\n * }\n * ```\n */\nexport interface QueryBuilderAdapter<TResult = any, TConfig = any> {\n /** Human-readable name for debugging */\n readonly name: string\n\n /**\n * Convert a ParsedQuery into an ORM-specific query object.\n * @param parsed - The ORM-agnostic parsed query\n * @param config - ORM-specific configuration (column maps, search columns, etc.)\n */\n build(parsed: ParsedQuery, config: TConfig): TResult\n}\n","import {\n FILTER_OPERATORS,\n type FilterItem,\n type FilterOperator,\n type SortItem,\n type PaginationParams,\n type ParsedQuery,\n type QueryFieldConfig,\n type StringQueryFieldConfig,\n type TypedParsedQuery,\n} from './types'\n\nconst MAX_SEARCH_LENGTH = 200\nconst DEFAULT_PAGE = 1\nconst DEFAULT_LIMIT = 20\nconst MAX_LIMIT = 100\n\n// ── Individual parsers ──────────────────────────────────────────────────\n\n/** Parse filter strings like \"status:eq:active\" into structured objects */\nexport function parseFilters(\n filterParam: string | string[] | undefined,\n allowedFields?: string[],\n): FilterItem[] {\n if (!filterParam) return []\n\n const items = Array.isArray(filterParam) ? filterParam : [filterParam]\n const results: FilterItem[] = []\n const allowed = allowedFields ? new Set(allowedFields) : null\n\n for (const item of items) {\n // Split on first two colons only — value may contain colons (e.g. timestamps)\n const firstColon = item.indexOf(':')\n if (firstColon === -1) continue\n\n const secondColon = item.indexOf(':', firstColon + 1)\n if (secondColon === -1) continue\n\n const field = item.slice(0, firstColon)\n const operator = item.slice(firstColon + 1, secondColon)\n const value = item.slice(secondColon + 1)\n\n if (!field || !value) continue\n if (!FILTER_OPERATORS.has(operator)) continue\n if (allowed && !allowed.has(field)) continue\n\n results.push({ field, operator: operator as FilterOperator, value })\n }\n\n return results\n}\n\n/** Parse sort strings like \"firstName:asc\" into structured objects */\nexport function parseSort(\n sortParam: string | string[] | undefined,\n allowedFields?: string[],\n): SortItem[] {\n if (!sortParam) return []\n\n const items = Array.isArray(sortParam) ? sortParam : [sortParam]\n const results: SortItem[] = []\n const allowed = allowedFields ? new Set(allowedFields) : null\n\n for (const item of items) {\n // Split on last colon so field names with colons work\n const lastColon = item.lastIndexOf(':')\n if (lastColon === -1) continue\n\n const field = item.slice(0, lastColon)\n const dir = item.slice(lastColon + 1).toLowerCase()\n\n if (!field) continue\n if (dir !== 'asc' && dir !== 'desc') continue\n if (allowed && !allowed.has(field)) continue\n\n results.push({ field, direction: dir })\n }\n\n return results\n}\n\n/** Parse page/limit into pagination with computed offset */\nexport function parsePagination(params: {\n page?: string | number\n limit?: string | number\n}): PaginationParams {\n let page =\n typeof params.page === 'string'\n ? Number.parseInt(params.page, 10)\n : (params.page ?? DEFAULT_PAGE)\n let limit =\n typeof params.limit === 'string'\n ? Number.parseInt(params.limit, 10)\n : (params.limit ?? DEFAULT_LIMIT)\n\n if (Number.isNaN(page) || page < 1) page = DEFAULT_PAGE\n if (Number.isNaN(limit) || limit < 1) limit = DEFAULT_LIMIT\n if (limit > MAX_LIMIT) limit = MAX_LIMIT\n\n return { page, limit, offset: (page - 1) * limit }\n}\n\n/** Sanitize and truncate search query */\nexport function parseSearchQuery(q: string | undefined): string {\n if (!q) return ''\n return q.trim().slice(0, MAX_SEARCH_LENGTH)\n}\n\n// ── Config normalizer ───────────────────────────────────────────────────\n\n/**\n * Normalize a QueryFieldConfig into the string-based form.\n * Detects column-object-based configs (DrizzleQueryParamsConfig) by checking\n * for a `columns` property and extracts `Object.keys()`.\n */\nfunction normalizeFieldConfig(config?: QueryFieldConfig): StringQueryFieldConfig | undefined {\n if (!config) return undefined\n\n // Column-object-based config (e.g., DrizzleQueryParamsConfig)\n if ('columns' in config && config.columns && typeof config.columns === 'object') {\n return {\n filterable: Object.keys(config.columns),\n sortable: config.sortable ? Object.keys(config.sortable) : undefined,\n searchable: undefined, // searchColumns are Column objects, not used for string filtering\n }\n }\n\n // Already string-based\n return config as StringQueryFieldConfig\n}\n\n// ── Combined parser ─────────────────────────────────────────────────────\n\n/**\n * Parse a raw Express query object into a structured, ORM-agnostic ParsedQuery.\n *\n * @param query - Raw query string object from `req.query` or Zod-validated object\n * @param fieldConfig - Optional field restrictions (whitelist filterable/sortable/searchable).\n * Accepts both string-based configs (`{ filterable, sortable, searchable }`) and\n * column-object configs (`{ columns, sortable, searchColumns }`).\n *\n * @example\n * ```ts\n * // String-based config\n * const parsed = parseQuery(ctx.query, {\n * filterable: ['status', 'priority'],\n * sortable: ['createdAt', 'title'],\n * })\n *\n * // Column-object config (DrizzleQueryParamsConfig)\n * const parsed = parseQuery(ctx.query, TASK_QUERY_CONFIG)\n * ```\n *\n * Query string format:\n * - Filters: `?filter=field:operator:value` (repeatable)\n * - Sort: `?sort=field:asc|desc` (repeatable)\n * - Pagination: `?page=1&limit=20`\n * - Search: `?q=search+term`\n *\n * Filter operators: eq, neq, gt, gte, lt, lte, between, in, contains, starts, ends\n */\nexport function parseQuery<TConfig extends QueryFieldConfig | undefined = undefined>(\n query: Record<string, any>,\n fieldConfig?: TConfig,\n): TypedParsedQuery<TConfig> {\n const normalized = normalizeFieldConfig(fieldConfig)\n return {\n filters: parseFilters(query.filter, normalized?.filterable),\n sort: parseSort(query.sort, normalized?.sortable),\n pagination: parsePagination({ page: query.page, limit: query.limit }),\n search: parseSearchQuery(query.q),\n } as TypedParsedQuery<TConfig>\n}\n\n// ── Query URL builder (for client-side or testing) ──────────────────────\n\n/** Convert ParsedQuery back into query string parameters */\nexport function buildQueryParams(\n parsed: Partial<ParsedQuery>,\n): Record<string, string | string[] | number> {\n const params: Record<string, string | string[] | number> = {}\n\n if (parsed.filters?.length) {\n params.filter = parsed.filters.map((f) => `${f.field}:${f.operator}:${f.value}`)\n }\n\n if (parsed.sort?.length) {\n params.sort = parsed.sort.map((s) => `${s.field}:${s.direction}`)\n }\n\n if (parsed.pagination) {\n params.page = parsed.pagination.page\n params.limit = parsed.pagination.limit\n }\n\n if (parsed.search) {\n params.q = parsed.search\n }\n\n return params\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"query-Di7R8qNX.mjs","names":[],"sources":["../src/http/query/types.ts","../src/http/query/parse-query.ts"],"sourcesContent":["/** Supported filter operators for query string parsing */\nexport type FilterOperator =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'between'\n | 'in'\n | 'contains'\n | 'starts'\n | 'ends'\n\nexport const FILTER_OPERATORS = new Set<string>([\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n 'in',\n 'contains',\n 'starts',\n 'ends',\n])\n\nexport interface FilterItem {\n field: string\n operator: FilterOperator\n value: string\n}\n\nexport interface SortItem {\n field: string\n direction: 'asc' | 'desc'\n}\n\nexport interface PaginationParams {\n page: number\n limit: number\n offset: number\n}\n\n/**\n * The result of parsing a query string. ORM-agnostic — pass this to\n * a query builder adapter (Drizzle, Prisma, Sequelize, etc.) to produce\n * database-specific query objects.\n */\nexport interface ParsedQuery {\n filters: FilterItem[]\n sort: SortItem[]\n pagination: PaginationParams\n search: string\n}\n\n/**\n * Helper that extracts the literal field union from a `QueryFieldConfig`\n * key. When the user passes `{ filterable: ['status', 'category'] } as const`,\n * `FieldsOf<typeof config, 'filterable'>` resolves to `'status' | 'category'`.\n *\n * Without `as const`, the arrays widen to `string[]` and the union falls\n * back to `string`. This is the documented escape hatch.\n */\nexport type FieldsOf<\n TConfig extends QueryFieldConfig | undefined,\n K extends 'filterable' | 'sortable' | 'searchable',\n> = TConfig extends { readonly [P in K]: readonly (infer F)[] }\n ? F extends string\n ? F\n : string\n : TConfig extends { columns: infer C }\n ? K extends 'filterable'\n ? keyof C & string\n : string\n : string\n\n/**\n * Narrowed `ParsedQuery` whose `filters[].field` and `sort[].field`\n * unions are constrained to the literal whitelist passed to\n * `ctx.qs()` / `parseQuery()`. Extends `ParsedQuery`, so any function\n * accepting `ParsedQuery` accepts a `TypedParsedQuery<X>` automatically\n * (subtype assignment, no codegen, backward compatible).\n *\n * @example\n * ```ts\n * const parsed = ctx.qs({\n * filterable: ['status', 'priority'],\n * sortable: ['createdAt'],\n * } as const)\n * parsed.filters[0]?.field // 'status' | 'priority'\n * parsed.sort[0]?.field // 'createdAt'\n * ```\n */\nexport interface TypedParsedQuery<\n TConfig extends QueryFieldConfig | undefined,\n> extends ParsedQuery {\n filters: Array<FilterItem & { field: FieldsOf<TConfig, 'filterable'> }>\n sort: Array<SortItem & { field: FieldsOf<TConfig, 'sortable'> }>\n}\n\n/**\n * Restrict which fields can be filtered, sorted, or searched.\n * Fields not in the allow-list are silently ignored.\n *\n * Accepts two forms:\n * 1. **String arrays** (standard): `{ filterable: ['name', 'status'], sortable: ['createdAt'] }`\n * 2. **Column-object maps** (Drizzle-style): `{ columns: { name: col, status: col }, sortable: { createdAt: col } }`\n *\n * When column-object maps are provided, `Object.keys()` is used to derive the field names.\n */\nexport type QueryFieldConfig = StringQueryFieldConfig | ColumnQueryFieldConfig\n\nexport interface StringQueryFieldConfig {\n filterable?: string[]\n sortable?: string[]\n searchable?: string[]\n}\n\n/**\n * Column-object-based field config (e.g., from DrizzleQueryParamsConfig).\n * Keys are the field names used in query strings; values are ORM column references.\n */\nexport interface ColumnQueryFieldConfig {\n columns: Record<string, any>\n sortable?: Record<string, any>\n searchColumns?: any[]\n [key: string]: any\n}\n\n/** Standardized paginated response shape */\nexport interface PaginatedResponse<T = any> {\n data: T[]\n meta: {\n page: number\n limit: number\n total: number\n totalPages: number\n hasNext: boolean\n hasPrev: boolean\n }\n}\n\n/**\n * Interface for ORM-specific query builder adapters.\n * Implement this to translate a `ParsedQuery` into your ORM's query format.\n *\n * @example\n * ```ts\n * // Drizzle adapter\n * class DrizzleQueryAdapter implements QueryBuilderAdapter<DrizzleQueryResult> {\n * build(parsed: ParsedQuery, config: DrizzleConfig): DrizzleQueryResult {\n * // Convert filters → Drizzle SQL conditions\n * // Convert sort → Drizzle orderBy\n * return { where, orderBy, limit, offset }\n * }\n * }\n *\n * // Prisma adapter\n * class PrismaQueryAdapter implements QueryBuilderAdapter<PrismaQueryResult> {\n * build(parsed: ParsedQuery, config: PrismaConfig): PrismaQueryResult {\n * return { where, orderBy, skip, take }\n * }\n * }\n * ```\n */\nexport interface QueryBuilderAdapter<TResult = any, TConfig = any> {\n /** Human-readable name for debugging */\n readonly name: string\n\n /**\n * Convert a ParsedQuery into an ORM-specific query object.\n * @param parsed - The ORM-agnostic parsed query\n * @param config - ORM-specific configuration (column maps, search columns, etc.)\n */\n build(parsed: ParsedQuery, config: TConfig): TResult\n}\n","import {\n FILTER_OPERATORS,\n type FilterItem,\n type FilterOperator,\n type SortItem,\n type PaginationParams,\n type ParsedQuery,\n type QueryFieldConfig,\n type StringQueryFieldConfig,\n type TypedParsedQuery,\n} from './types'\n\nconst MAX_SEARCH_LENGTH = 200\nconst DEFAULT_PAGE = 1\nconst DEFAULT_LIMIT = 20\nconst MAX_LIMIT = 100\n\n// ── Individual parsers ──────────────────────────────────────────────────\n\n/** Parse filter strings like \"status:eq:active\" into structured objects */\nexport function parseFilters(\n filterParam: string | string[] | undefined,\n allowedFields?: string[],\n): FilterItem[] {\n if (!filterParam) return []\n\n const items = Array.isArray(filterParam) ? filterParam : [filterParam]\n const results: FilterItem[] = []\n const allowed = allowedFields ? new Set(allowedFields) : null\n\n for (const item of items) {\n // Split on first two colons only — value may contain colons (e.g. timestamps)\n const firstColon = item.indexOf(':')\n if (firstColon === -1) continue\n\n const secondColon = item.indexOf(':', firstColon + 1)\n if (secondColon === -1) continue\n\n const field = item.slice(0, firstColon)\n const operator = item.slice(firstColon + 1, secondColon)\n const value = item.slice(secondColon + 1)\n\n if (!field || !value) continue\n if (!FILTER_OPERATORS.has(operator)) continue\n if (allowed && !allowed.has(field)) continue\n\n results.push({ field, operator: operator as FilterOperator, value })\n }\n\n return results\n}\n\n/** Parse sort strings like \"firstName:asc\" into structured objects */\nexport function parseSort(\n sortParam: string | string[] | undefined,\n allowedFields?: string[],\n): SortItem[] {\n if (!sortParam) return []\n\n const items = Array.isArray(sortParam) ? sortParam : [sortParam]\n const results: SortItem[] = []\n const allowed = allowedFields ? new Set(allowedFields) : null\n\n for (const item of items) {\n // Split on last colon so field names with colons work\n const lastColon = item.lastIndexOf(':')\n if (lastColon === -1) continue\n\n const field = item.slice(0, lastColon)\n const dir = item.slice(lastColon + 1).toLowerCase()\n\n if (!field) continue\n if (dir !== 'asc' && dir !== 'desc') continue\n if (allowed && !allowed.has(field)) continue\n\n results.push({ field, direction: dir })\n }\n\n return results\n}\n\n/** Parse page/limit into pagination with computed offset */\nexport function parsePagination(params: {\n page?: string | number\n limit?: string | number\n}): PaginationParams {\n let page =\n typeof params.page === 'string'\n ? Number.parseInt(params.page, 10)\n : (params.page ?? DEFAULT_PAGE)\n let limit =\n typeof params.limit === 'string'\n ? Number.parseInt(params.limit, 10)\n : (params.limit ?? DEFAULT_LIMIT)\n\n if (Number.isNaN(page) || page < 1) page = DEFAULT_PAGE\n if (Number.isNaN(limit) || limit < 1) limit = DEFAULT_LIMIT\n if (limit > MAX_LIMIT) limit = MAX_LIMIT\n\n return { page, limit, offset: (page - 1) * limit }\n}\n\n/** Sanitize and truncate search query */\nexport function parseSearchQuery(q: string | undefined): string {\n if (!q) return ''\n return q.trim().slice(0, MAX_SEARCH_LENGTH)\n}\n\n// ── Config normalizer ───────────────────────────────────────────────────\n\n/**\n * Normalize a QueryFieldConfig into the string-based form.\n * Detects column-object-based configs (DrizzleQueryParamsConfig) by checking\n * for a `columns` property and extracts `Object.keys()`.\n */\nfunction normalizeFieldConfig(config?: QueryFieldConfig): StringQueryFieldConfig | undefined {\n if (!config) return undefined\n\n // Column-object-based config (e.g., DrizzleQueryParamsConfig)\n if ('columns' in config && config.columns && typeof config.columns === 'object') {\n return {\n filterable: Object.keys(config.columns),\n sortable: config.sortable ? Object.keys(config.sortable) : undefined,\n searchable: undefined, // searchColumns are Column objects, not used for string filtering\n }\n }\n\n // Already string-based\n return config as StringQueryFieldConfig\n}\n\n// ── Combined parser ─────────────────────────────────────────────────────\n\n/**\n * Parse a raw Express query object into a structured, ORM-agnostic ParsedQuery.\n *\n * @param query - Raw query string object from `req.query` or Zod-validated object\n * @param fieldConfig - Optional field restrictions (whitelist filterable/sortable/searchable).\n * Accepts both string-based configs (`{ filterable, sortable, searchable }`) and\n * column-object configs (`{ columns, sortable, searchColumns }`).\n *\n * @example\n * ```ts\n * // String-based config\n * const parsed = parseQuery(ctx.query, {\n * filterable: ['status', 'priority'],\n * sortable: ['createdAt', 'title'],\n * })\n *\n * // Column-object config (DrizzleQueryParamsConfig)\n * const parsed = parseQuery(ctx.query, TASK_QUERY_CONFIG)\n * ```\n *\n * Query string format:\n * - Filters: `?filter=field:operator:value` (repeatable)\n * - Sort: `?sort=field:asc|desc` (repeatable)\n * - Pagination: `?page=1&limit=20`\n * - Search: `?q=search+term`\n *\n * Filter operators: eq, neq, gt, gte, lt, lte, between, in, contains, starts, ends\n */\nexport function parseQuery<TConfig extends QueryFieldConfig | undefined = undefined>(\n query: Record<string, any>,\n fieldConfig?: TConfig,\n): TypedParsedQuery<TConfig> {\n const normalized = normalizeFieldConfig(fieldConfig)\n return {\n filters: parseFilters(query.filter, normalized?.filterable),\n sort: parseSort(query.sort, normalized?.sortable),\n pagination: parsePagination({ page: query.page, limit: query.limit }),\n search: parseSearchQuery(query.q),\n } as TypedParsedQuery<TConfig>\n}\n\n// ── Query URL builder (for client-side or testing) ──────────────────────\n\n/** Convert ParsedQuery back into query string parameters */\nexport function buildQueryParams(\n parsed: Partial<ParsedQuery>,\n): Record<string, string | string[] | number> {\n const params: Record<string, string | string[] | number> = {}\n\n if (parsed.filters?.length) {\n params.filter = parsed.filters.map((f) => `${f.field}:${f.operator}:${f.value}`)\n }\n\n if (parsed.sort?.length) {\n params.sort = parsed.sort.map((s) => `${s.field}:${s.direction}`)\n }\n\n if (parsed.pagination) {\n params.page = parsed.pagination.page\n params.limit = parsed.pagination.limit\n }\n\n if (parsed.search) {\n params.q = parsed.search\n }\n\n return params\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
 
2
- import { S as SourcedRegistration } from "./index-D-Wb23e6.mjs";
2
+ import { S as SourcedRegistration } from "./index-CkKLXZHg.mjs";
3
3
  import { Router } from "express";
4
4
 
5
5
  //#region src/http/router-builder.d.ts
@@ -28,4 +28,4 @@ interface BuildRoutesOptions {
28
28
  declare function buildRoutes(controllerClass: any, options?: BuildRoutesOptions): Router;
29
29
  //#endregion
30
30
  export { _setExternalContributorSources as n, buildRoutes as r, BuildRoutesOptions as t };
31
- //# sourceMappingURL=router-builder-CaQ629tw.d.mts.map
31
+ //# sourceMappingURL=router-builder-BfCCeQB-.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router-builder-CaQ629tw.d.mts","names":[],"sources":["../src/http/router-builder.ts"],"mappings":";;;;;;iBAoCgB,8BAAA,CAA+B,OAAA,WAAkB,mBAAA;AAAA,UAIhD,kBAAA;EAJ6B;;;;AAI9C;;EAOE,eAAA,YAA2B,mBAAA;AAAA;;AAc7B;;;;;;;;;;iBAAgB,WAAA,CAAY,eAAA,OAAsB,OAAA,GAAS,kBAAA,GAA0B,MAAA"}
1
+ {"version":3,"file":"router-builder-BfCCeQB-.d.mts","names":[],"sources":["../src/http/router-builder.ts"],"mappings":";;;;;;iBAoCgB,8BAAA,CAA+B,OAAA,WAAkB,mBAAA;AAAA,UAIhD,kBAAA;EAJ6B;;;;AAI9C;;EAOE,eAAA,YAA2B,mBAAA;AAAA;;AAc7B;;;;;;;;;;iBAAgB,WAAA,CAAY,eAAA,OAAsB,OAAA,GAAS,kBAAA,GAA0B,MAAA"}
@@ -1,5 +1,5 @@
1
1
 
2
- import { r as AppAdapter, t as AdapterContext } from "./adapter-0r2uRCD3.mjs";
2
+ import { r as AppAdapter, t as AdapterContext } from "./adapter-CoJp35rz.mjs";
3
3
  //#region src/http/middleware/spa.d.ts
4
4
  interface SpaAdapterOptions {
5
5
  /**
@@ -98,4 +98,4 @@ declare class SpaAdapter implements AppAdapter {
98
98
  }
99
99
  //#endregion
100
100
  export { SpaAdapterOptions as n, SpaAdapter as t };
101
- //# sourceMappingURL=spa-CreyQc4N.d.mts.map
101
+ //# sourceMappingURL=spa-DIXtRBj-.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spa-CreyQc4N.d.mts","names":[],"sources":["../src/http/middleware/spa.ts"],"mappings":";;;UAMiB,iBAAA;;;AAAjB;;;;;;;;;;;EAcE,SAAA;EAqEsB;;;;;;;;;;EAzDtB,SAAA;EAkEoB;;;;;;;;;EAvDpB,OAAA;EAuDoB;;;;EAjDpB,YAAA;EAoGA;;;;EA9FA,iBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkCW,UAAA,YAAsB,UAAA;EAAA,QASb,OAAA;EARpB,IAAA;EAAA,QACQ,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,YAAA;EAAA,QACA,iBAAA;EAAA,QACA,SAAA;cAEY,OAAA,GAAS,iBAAA;EAU7B,WAAA,CAAA;IAAc;EAAA,GAAO,cAAA;EAyCrB,WAAA,CAAA;IAAc;EAAA,GAAO,cAAA;AAAA"}
1
+ {"version":3,"file":"spa-DIXtRBj-.d.mts","names":[],"sources":["../src/http/middleware/spa.ts"],"mappings":";;;UAMiB,iBAAA;;;AAAjB;;;;;;;;;;;EAcE,SAAA;EAqEsB;;;;;;;;;;EAzDtB,SAAA;EAkEoB;;;;;;;;;EAvDpB,OAAA;EAuDoB;;;;EAjDpB,YAAA;EAoGA;;;;EA9FA,iBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkCW,UAAA,YAAsB,UAAA;EAAA,QASb,OAAA;EARpB,IAAA;EAAA,QACQ,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,YAAA;EAAA,QACA,iBAAA;EAAA,QACA,SAAA;cAEY,OAAA,GAAS,iBAAA;EAU7B,WAAA,CAAA;IAAc;EAAA,GAAO,cAAA;EAyCrB,WAAA,CAAA;IAAc;EAAA,GAAO,cAAA;AAAA"}
@@ -1,5 +1,5 @@
1
1
 
2
- import { g as FileUploadConfig, o as BaseUploadOptions } from "./decorators-J5mC7D-6.mjs";
2
+ import { g as FileUploadConfig, o as BaseUploadOptions } from "./decorators-ZcjsV1O0.mjs";
3
3
  import { NextFunction, Request, RequestHandler, Response } from "express";
4
4
  import { Options } from "multer";
5
5
 
@@ -76,4 +76,4 @@ declare const upload: {
76
76
  };
77
77
  //#endregion
78
78
  export { upload as a, resolveMimeTypes as i, buildUploadMiddleware as n, cleanupFiles as r, UploadOptions as t };
79
- //# sourceMappingURL=upload-tGMrlhEB.d.mts.map
79
+ //# sourceMappingURL=upload-DqRwWhX0.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload-tGMrlhEB.d.mts","names":[],"sources":["../src/http/middleware/upload.ts"],"mappings":";;;;;;;;;AAsEA;;;;;AAYA;;iBAZgB,gBAAA,CAAiB,KAAA;;;;;;UAYhB,aAAA,SAAsB,iBAAA;EAIjC;EAFJ,OAAA,GAAU,OAAA;EAmEG;EAjEb,IAAA;AAAA;;;;;;;AAiE6E;;;;;;iBAAtE,MAAA,CAAO,SAAA,UAAmB,OAAA,GAAS,aAAA,GAAqB,cAAA;;;;iBAQxD,KAAA,CAAM,SAAA,UAAmB,QAAA,WAAe,OAAA,GAAS,aAAA,GAAqB,cAAA;AAAc;;;AAAA,iBAQpF,IAAA,CAAK,OAAA,GAAS,aAAA,GAAqB,cAAA;;;;;;AAmB5C;;;;;;;;;iBAAgB,YAAA,CAAA,IACN,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;;;;iBA+B7B,qBAAA,CAAsB,MAAA,EAAQ,gBAAA,GAAmB,cAAA;AAAjE;AAAA,cAmBa,MAAA"}
1
+ {"version":3,"file":"upload-DqRwWhX0.d.mts","names":[],"sources":["../src/http/middleware/upload.ts"],"mappings":";;;;;;;;;AAsEA;;;;;AAYA;;iBAZgB,gBAAA,CAAiB,KAAA;;;;;;UAYhB,aAAA,SAAsB,iBAAA;EAIjC;EAFJ,OAAA,GAAU,OAAA;EAmEG;EAjEb,IAAA;AAAA;;;;;;;AAiE6E;;;;;;iBAAtE,MAAA,CAAO,SAAA,UAAmB,OAAA,GAAS,aAAA,GAAqB,cAAA;;;;iBAQxD,KAAA,CAAM,SAAA,UAAmB,QAAA,WAAe,OAAA,GAAS,aAAA,GAAqB,cAAA;AAAc;;;AAAA,iBAQpF,IAAA,CAAK,OAAA,GAAS,aAAA,GAAqB,cAAA;;;;;;AAmB5C;;;;;;;;;iBAAgB,YAAA,CAAA,IACN,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;;;;iBA+B7B,qBAAA,CAAsB,MAAA,EAAQ,gBAAA,GAAmB,cAAA;AAAjE;AAAA,cAmBa,MAAA"}
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { r as MetaValue } from "./execution-context-DKnt61pY.mjs";
3
- import { n as ContextDecorator, r as ContextDecoratorSpec, s as DepValue } from "./context-decorator-BgdDd-6X.mjs";
4
- import { c as AdapterFactory } from "./index-D-Wb23e6.mjs";
3
+ import { c as DepValue, n as ContextDecorator, r as ContextDecoratorSpec } from "./context-decorator-BYf8HdMl.mjs";
4
+ import { c as AdapterFactory } from "./index-CkKLXZHg.mjs";
5
5
  import { r as RequestContext } from "./context-aocg9gO-.mjs";
6
6
  import { NextFunction, Request, Response } from "express";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -214,4 +214,4 @@ interface ViewAdapterOptions {
214
214
  declare const ViewAdapter: AdapterFactory<ViewAdapterOptions, unknown>;
215
215
  //#endregion
216
216
  export { TraceContextOptions as a, requestScopeMiddleware as c, getRequestValue as d, requestStore as f, isClusterPrimary as h, TraceContext as i, RequestStore as l, ClusterOptions as m, ViewAdapterOptions as n, parseTraceparent as o, defineHttpContextDecorator as p, TRACEPARENT_HEADER as r, traceContext as s, ViewAdapter as t, getRequestStore as u };
217
- //# sourceMappingURL=views-BMhrZsH9.d.mts.map
217
+ //# sourceMappingURL=views-DDT9vghc.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"views-BMhrZsH9.d.mts","names":[],"sources":["../src/http/cluster.ts","../src/http/define-http-context-decorator.ts","../src/http/request-store.ts","../src/http/middleware/request-scope.ts","../src/http/middleware/trace-context.ts","../src/http/middleware/views.ts"],"mappings":";;;;;;;;;UAOiB,cAAA;;EAEf,OAAA;;EAEA,uBAAA;;EAEA,YAAA;;EAEA,WAAA;;EAEA,aAAA;AAAA;;iBAIc,gBAAA,CAAA;;;iBCoCA,0BAAA,6BAEJ,MAAA,SAAe,QAAA,IAAY,MAAA,2BAC3B,MAAA,oBAA0B,MAAA,gBAAA,CACpC,IAAA,EAAM,oBAAA,CAAqB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA,IAAkB,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA;;;;UCzDjE,YAAA;;EAEf,SAAA;;;;;;EAMA,SAAA,EAAW,GAAA;;;;;;;;;;;;AFLb;;;;;;;;;EE0BE,MAAA,EAAQ,GAAA;AAAA;AFZV;AAAA,cEgBa,YAAA,EAAY,iBAAA,CAAA,YAAA;;;;;iBAMT,eAAA,CAAA,GAAmB,YAAA;;ADcnC;;;;;;;;;;;;;;;;;;;;;;;;;iBCsBgB,eAAA,kBAAA,CAAkC,GAAA,EAAK,CAAA,GAAI,SAAA,CAAU,CAAA;;;;;;;;;;;iBCrDrD,sBAAA,CAAA,IAAsB,GAAA,EACnB,OAAA,EAAO,IAAA,EAAQ,QAAA,EAAQ,IAAA,EAAQ,YAAA;;;;;;;cCnBrC,kBAAA;AAAA,UAKI,mBAAA;;;;;EAKf,iBAAA;AAAA;;;;UAMe,YAAA;;EAEf,OAAA;;EAEA,OAAA;;EAEA,YAAA;EJvBe;EIyBf,KAAA;AAAA;;;;;iBAqBc,gBAAA,CAAiB,MAAA,WAAiB,YAAA;;;;AJhClD;;;;;;;;ACoCA;;;;;;;;;;iBGsCgB,YAAA,CAAa,OAAA,GAAS,mBAAA,IAC5B,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;UC3F5B,kBAAA;;;;;;;;;;;;;;;EAef,MAAA;;EAGA,GAAA;;EAGA,QAAA;;EAGA,MAAA;AAAA;ALtBF;;;;;;;;;;;AAcA;;;;;;;;ACoCA;;;;;;;;;;ADlDA,cKsDa,WAAA,EAAW,cAAA,CAAA,kBAAA"}
1
+ {"version":3,"file":"views-DDT9vghc.d.mts","names":[],"sources":["../src/http/cluster.ts","../src/http/define-http-context-decorator.ts","../src/http/request-store.ts","../src/http/middleware/request-scope.ts","../src/http/middleware/trace-context.ts","../src/http/middleware/views.ts"],"mappings":";;;;;;;;;UAOiB,cAAA;;EAEf,OAAA;;EAEA,uBAAA;;EAEA,YAAA;;EAEA,WAAA;;EAEA,aAAA;AAAA;;iBAIc,gBAAA,CAAA;;;iBCoCA,0BAAA,6BAEJ,MAAA,SAAe,QAAA,IAAY,MAAA,2BAC3B,MAAA,oBAA0B,MAAA,gBAAA,CACpC,IAAA,EAAM,oBAAA,CAAqB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA,IAAkB,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA;;;;UCzDjE,YAAA;;EAEf,SAAA;;;;;;EAMA,SAAA,EAAW,GAAA;;;;;;;;;;;;AFLb;;;;;;;;;EE0BE,MAAA,EAAQ,GAAA;AAAA;AFZV;AAAA,cEgBa,YAAA,EAAY,iBAAA,CAAA,YAAA;;;;;iBAMT,eAAA,CAAA,GAAmB,YAAA;;ADcnC;;;;;;;;;;;;;;;;;;;;;;;;;iBCsBgB,eAAA,kBAAA,CAAkC,GAAA,EAAK,CAAA,GAAI,SAAA,CAAU,CAAA;;;;;;;;;;;iBCrDrD,sBAAA,CAAA,IAAsB,GAAA,EACnB,OAAA,EAAO,IAAA,EAAQ,QAAA,EAAQ,IAAA,EAAQ,YAAA;;;;;;;cCnBrC,kBAAA;AAAA,UAKI,mBAAA;;;;;EAKf,iBAAA;AAAA;;;;UAMe,YAAA;;EAEf,OAAA;;EAEA,OAAA;;EAEA,YAAA;EJvBe;EIyBf,KAAA;AAAA;;;;;iBAqBc,gBAAA,CAAiB,MAAA,WAAiB,YAAA;;;;AJhClD;;;;;;;;ACoCA;;;;;;;;;;iBGsCgB,YAAA,CAAa,OAAA,GAAS,mBAAA,IAC5B,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;UC3F5B,kBAAA;;;;;;;;;;;;;;;EAef,MAAA;;EAGA,GAAA;;EAGA,QAAA;;EAGA,MAAA;AAAA;ALtBF;;;;;;;;;;;AAcA;;;;;;;;ACoCA;;;;;;;;;;ADlDA,cKsDa,WAAA,EAAW,cAAA,CAAA,kBAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forinda/kickjs",
3
- "version": "5.6.0",
3
+ "version": "5.7.0",
4
4
  "description": "A production-grade, decorator-driven Node.js framework built on Express 5 and TypeScript.",
5
5
  "keywords": [
6
6
  "kickjs",
@@ -129,7 +129,7 @@
129
129
  "pino": "^10.3.1",
130
130
  "pino-pretty": "^13.1.3",
131
131
  "reflect-metadata": "^0.2.2",
132
- "zod": "^4.3.6"
132
+ "zod": "^4.4.3"
133
133
  },
134
134
  "peerDependencies": {
135
135
  "dotenv": "^17.0.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorators-J5mC7D-6.d.mts","names":[],"sources":["../src/core/assets.ts","../src/core/decorators.ts"],"mappings":"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"}