@gblikas/querykit 0.0.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.
- package/.cursor/BUGBOT.md +21 -0
- package/.cursor/rules/01-project-structure.mdc +77 -0
- package/.cursor/rules/02-typescript-standards.mdc +105 -0
- package/.cursor/rules/03-testing-standards.mdc +78 -0
- package/.cursor/rules/04-query-language.mdc +79 -0
- package/.cursor/rules/05-solid-principles.mdc +118 -0
- package/.cursor/rules/liqe-readme-docs.mdc +438 -0
- package/.devcontainer/devcontainer.json +25 -0
- package/.eslintignore +1 -0
- package/.eslintrc.js +39 -0
- package/.github/dependabot.yml +12 -0
- package/.github/workflows/ci.yml +114 -0
- package/.github/workflows/publish.yml +61 -0
- package/.husky/pre-commit +30 -0
- package/.prettierrc +10 -0
- package/CONTRIBUTING.md +187 -0
- package/LICENSE +674 -0
- package/README.md +237 -0
- package/dist/adapters/drizzle/index.d.ts +122 -0
- package/dist/adapters/drizzle/index.js +166 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.js +25 -0
- package/dist/adapters/types.d.ts +60 -0
- package/dist/adapters/types.js +8 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +118 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +18 -0
- package/dist/parser/parser.d.ts +51 -0
- package/dist/parser/parser.js +201 -0
- package/dist/parser/types.d.ts +68 -0
- package/dist/parser/types.js +5 -0
- package/dist/query/builder.d.ts +61 -0
- package/dist/query/builder.js +188 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +18 -0
- package/dist/query/types.d.ts +79 -0
- package/dist/query/types.js +2 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.js +18 -0
- package/dist/security/types.d.ts +181 -0
- package/dist/security/types.js +43 -0
- package/dist/security/validator.d.ts +191 -0
- package/dist/security/validator.js +344 -0
- package/dist/translators/drizzle/index.d.ts +73 -0
- package/dist/translators/drizzle/index.js +260 -0
- package/dist/translators/index.d.ts +8 -0
- package/dist/translators/index.js +27 -0
- package/dist/translators/sql/index.d.ts +108 -0
- package/dist/translators/sql/index.js +252 -0
- package/dist/translators/types.d.ts +39 -0
- package/dist/translators/types.js +8 -0
- package/examples/qk-next/README.md +35 -0
- package/examples/qk-next/app/favicon.ico +0 -0
- package/examples/qk-next/app/globals.css +122 -0
- package/examples/qk-next/app/layout.tsx +121 -0
- package/examples/qk-next/app/page.tsx +813 -0
- package/examples/qk-next/app/providers.tsx +80 -0
- package/examples/qk-next/components/aurora-background.tsx +12 -0
- package/examples/qk-next/components/github-stars.tsx +51 -0
- package/examples/qk-next/components/mode-toggle.tsx +27 -0
- package/examples/qk-next/components/reactbits/blocks/Backgrounds/Aurora/Aurora.tsx +217 -0
- package/examples/qk-next/components/reactbits/blocks/Backgrounds/LightRays/LightRays.tsx +474 -0
- package/examples/qk-next/components/theme-provider.tsx +11 -0
- package/examples/qk-next/components/ui/card.tsx +92 -0
- package/examples/qk-next/components/ui/command.tsx +184 -0
- package/examples/qk-next/components/ui/dialog.tsx +143 -0
- package/examples/qk-next/components/ui/drawer.tsx +135 -0
- package/examples/qk-next/components/ui/hover-card.tsx +44 -0
- package/examples/qk-next/components/ui/icons.tsx +148 -0
- package/examples/qk-next/components/ui/sonner.tsx +26 -0
- package/examples/qk-next/components/ui/table.tsx +117 -0
- package/examples/qk-next/components.json +21 -0
- package/examples/qk-next/eslint.config.mjs +21 -0
- package/examples/qk-next/jsrepo.json +13 -0
- package/examples/qk-next/lib/utils.ts +6 -0
- package/examples/qk-next/next.config.ts +8 -0
- package/examples/qk-next/package.json +48 -0
- package/examples/qk-next/pnpm-lock.yaml +5558 -0
- package/examples/qk-next/postcss.config.mjs +5 -0
- package/examples/qk-next/public/file.svg +1 -0
- package/examples/qk-next/public/globe.svg +1 -0
- package/examples/qk-next/public/next.svg +1 -0
- package/examples/qk-next/public/vercel.svg +1 -0
- package/examples/qk-next/public/window.svg +1 -0
- package/examples/qk-next/tsconfig.json +42 -0
- package/examples/qk-next/types/sonner.d.ts +3 -0
- package/jest.config.js +26 -0
- package/package.json +51 -0
- package/src/adapters/drizzle/drizzle-adapter.test.ts +115 -0
- package/src/adapters/drizzle/index.ts +299 -0
- package/src/adapters/index.ts +11 -0
- package/src/adapters/types.ts +72 -0
- package/src/index.ts +194 -0
- package/src/integration.test.ts +202 -0
- package/src/parser/index.ts +2 -0
- package/src/parser/parser.test.ts +1056 -0
- package/src/parser/parser.ts +268 -0
- package/src/parser/types.ts +97 -0
- package/src/query/builder.test.ts +272 -0
- package/src/query/builder.ts +274 -0
- package/src/query/index.ts +2 -0
- package/src/query/types.ts +107 -0
- package/src/security/index.ts +2 -0
- package/src/security/types.ts +210 -0
- package/src/security/validator.test.ts +459 -0
- package/src/security/validator.ts +395 -0
- package/src/security.test.ts +366 -0
- package/src/translators/drizzle/drizzle-translator.test.ts +128 -0
- package/src/translators/drizzle/index.test.ts +45 -0
- package/src/translators/drizzle/index.ts +346 -0
- package/src/translators/index.ts +14 -0
- package/src/translators/sql/index.test.ts +45 -0
- package/src/translators/sql/index.ts +331 -0
- package/src/translators/sql/sql-translator.test.ts +419 -0
- package/src/translators/types.ts +44 -0
- package/src/types/sonner.d.ts +3 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueryBuilder = void 0;
|
|
4
|
+
const parser_1 = require("../parser");
|
|
5
|
+
/**
|
|
6
|
+
* Implementation of the type-safe query builder
|
|
7
|
+
*/
|
|
8
|
+
class QueryBuilder {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.expression = '';
|
|
11
|
+
this.orderByClause = '';
|
|
12
|
+
this.limitClause = '';
|
|
13
|
+
this.offsetClause = '';
|
|
14
|
+
this.parser = new parser_1.QueryParser({
|
|
15
|
+
caseInsensitiveFields: options.caseInsensitiveFields,
|
|
16
|
+
fieldMappings: options.fieldMappings
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
where(fieldOrQueryString, operator, value) {
|
|
20
|
+
if (operator === undefined || value === undefined) {
|
|
21
|
+
// Handle direct query string format
|
|
22
|
+
this.expression = fieldOrQueryString;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Handle field, operator, value format
|
|
26
|
+
this.expression = this.buildComparison(fieldOrQueryString, operator, value);
|
|
27
|
+
}
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
andWhere(fieldOrQueryString, operator, value) {
|
|
31
|
+
if (!this.expression) {
|
|
32
|
+
if (typeof fieldOrQueryString === 'string' && (operator === undefined || value === undefined)) {
|
|
33
|
+
// Handle direct query string
|
|
34
|
+
return this.where(fieldOrQueryString);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Handle field, operator, value format
|
|
38
|
+
return this.where(fieldOrQueryString, operator, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (operator === undefined || value === undefined) {
|
|
42
|
+
// Handle direct query string format
|
|
43
|
+
this.expression = `(${this.expression}) AND ${fieldOrQueryString}`;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Handle field, operator, value format
|
|
47
|
+
this.expression = `(${this.expression}) AND ${this.buildComparison(fieldOrQueryString, operator, value)}`;
|
|
48
|
+
}
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
orWhere(fieldOrQueryString, operator, value) {
|
|
52
|
+
if (!this.expression) {
|
|
53
|
+
if (typeof fieldOrQueryString === 'string' && (operator === undefined || value === undefined)) {
|
|
54
|
+
// Handle direct query string
|
|
55
|
+
return this.where(fieldOrQueryString);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Handle field, operator, value format
|
|
59
|
+
return this.where(fieldOrQueryString, operator, value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (operator === undefined || value === undefined) {
|
|
63
|
+
// Handle direct query string format
|
|
64
|
+
this.expression = `(${this.expression}) OR ${fieldOrQueryString}`;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Handle field, operator, value format
|
|
68
|
+
this.expression = `(${this.expression}) OR ${this.buildComparison(fieldOrQueryString, operator, value)}`;
|
|
69
|
+
}
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
notWhere(fieldOrQueryString, operator, value) {
|
|
73
|
+
if (!this.expression) {
|
|
74
|
+
if (operator === undefined || value === undefined) {
|
|
75
|
+
// Handle direct query string format
|
|
76
|
+
this.expression = `NOT ${fieldOrQueryString}`;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Handle field, operator, value format
|
|
80
|
+
this.expression = `NOT ${this.buildComparison(fieldOrQueryString, operator, value)}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (operator === undefined || value === undefined) {
|
|
85
|
+
// Handle direct query string format
|
|
86
|
+
this.expression = `(${this.expression}) AND NOT ${fieldOrQueryString}`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// Handle field, operator, value format
|
|
90
|
+
this.expression = `(${this.expression}) AND NOT ${this.buildComparison(fieldOrQueryString, operator, value)}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Add an order by clause to the query
|
|
97
|
+
*/
|
|
98
|
+
orderBy(field, direction = 'asc') {
|
|
99
|
+
this.orderByClause = `ORDER BY ${field} ${direction.toUpperCase()}`;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Add a limit to the query
|
|
104
|
+
*/
|
|
105
|
+
limit(count) {
|
|
106
|
+
this.limitClause = `LIMIT ${count}`;
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Add an offset to the query
|
|
111
|
+
*/
|
|
112
|
+
offset(count) {
|
|
113
|
+
this.offsetClause = `OFFSET ${count}`;
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get the current query expression
|
|
118
|
+
*/
|
|
119
|
+
getExpression() {
|
|
120
|
+
return this.parser.parse(this.expression);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get the current query as a string
|
|
124
|
+
*/
|
|
125
|
+
toString() {
|
|
126
|
+
const clauses = [
|
|
127
|
+
this.expression,
|
|
128
|
+
this.orderByClause,
|
|
129
|
+
this.limitClause,
|
|
130
|
+
this.offsetClause
|
|
131
|
+
].filter(Boolean);
|
|
132
|
+
return clauses.join(' ');
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build a comparison expression
|
|
136
|
+
*/
|
|
137
|
+
buildComparison(field, operator, value) {
|
|
138
|
+
// Map QueryKit operators to Liqe operators
|
|
139
|
+
const operatorMap = {
|
|
140
|
+
'==': ':',
|
|
141
|
+
'!=': '!=',
|
|
142
|
+
'>': '>',
|
|
143
|
+
'>=': '>=',
|
|
144
|
+
'<': '<',
|
|
145
|
+
'<=': '<=',
|
|
146
|
+
'IN': 'in',
|
|
147
|
+
'NOT IN': 'not in',
|
|
148
|
+
'LIKE': ':'
|
|
149
|
+
};
|
|
150
|
+
const liqeOperator = operatorMap[operator];
|
|
151
|
+
const formattedValue = this.formatValue(value, operator);
|
|
152
|
+
// For equality and LIKE operators, use field:value format (simple colon)
|
|
153
|
+
if (operator === '==' || operator === 'LIKE') {
|
|
154
|
+
return `${field}${liqeOperator}${formattedValue}`;
|
|
155
|
+
}
|
|
156
|
+
// Based on Liqe docs, comparison operators are prefixed with colon
|
|
157
|
+
// e.g., 'height:>100', 'height:<100'
|
|
158
|
+
if (operator === '>' || operator === '>=' || operator === '<' || operator === '<=' || operator === '!=') {
|
|
159
|
+
return `${field}:${liqeOperator}${formattedValue}`;
|
|
160
|
+
}
|
|
161
|
+
// For array operators (IN, NOT IN), use the format field:operator[values]
|
|
162
|
+
if (operator === 'IN' || operator === 'NOT IN') {
|
|
163
|
+
return `${field}:${liqeOperator}${formattedValue}`;
|
|
164
|
+
}
|
|
165
|
+
// For other operators, use field:operator value format
|
|
166
|
+
return `${field}:${liqeOperator} ${formattedValue}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Format a value for use in a query
|
|
170
|
+
*/
|
|
171
|
+
formatValue(value, operator) {
|
|
172
|
+
if (value === null) {
|
|
173
|
+
return 'null';
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(value)) {
|
|
176
|
+
return `[${value.map(v => this.formatValue(v)).join(',')}]`;
|
|
177
|
+
}
|
|
178
|
+
if (typeof value === 'string') {
|
|
179
|
+
// For LIKE operator with wildcard patterns, don't add quotes to allow pattern matching
|
|
180
|
+
if (operator === 'LIKE' && (value.includes('*') || value.includes('?'))) {
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
return `"${value}"`;
|
|
184
|
+
}
|
|
185
|
+
return String(value);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
exports.QueryBuilder = QueryBuilder;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./builder"), exports);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { QueryExpression } from '../parser/types';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a field in a query
|
|
4
|
+
*/
|
|
5
|
+
export type QueryField<T> = keyof T & string;
|
|
6
|
+
/**
|
|
7
|
+
* Represents a value that can be used in a query
|
|
8
|
+
*/
|
|
9
|
+
export type QueryValue = string | number | boolean | null | Array<string | number | boolean | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Represents a comparison operator in a query
|
|
12
|
+
*/
|
|
13
|
+
export type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<=' | 'IN' | 'NOT IN' | 'LIKE';
|
|
14
|
+
/**
|
|
15
|
+
* Represents a logical operator in a query
|
|
16
|
+
*/
|
|
17
|
+
export type LogicalOperator = 'AND' | 'OR' | 'NOT';
|
|
18
|
+
/**
|
|
19
|
+
* Represents a sort direction
|
|
20
|
+
*/
|
|
21
|
+
export type SortDirection = 'asc' | 'desc';
|
|
22
|
+
/**
|
|
23
|
+
* Configuration options for the query builder
|
|
24
|
+
*/
|
|
25
|
+
export interface IQueryBuilderOptions<T> {
|
|
26
|
+
/**
|
|
27
|
+
* Whether to allow case-insensitive field names
|
|
28
|
+
*/
|
|
29
|
+
caseInsensitiveFields?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Custom field name mappings
|
|
32
|
+
*/
|
|
33
|
+
fieldMappings?: Partial<Record<QueryField<T>, string>>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Interface for a query builder
|
|
37
|
+
*/
|
|
38
|
+
export interface IQueryBuilder<T> {
|
|
39
|
+
/**
|
|
40
|
+
* Add a where clause to the query
|
|
41
|
+
*/
|
|
42
|
+
where(queryString: string): IQueryBuilder<T>;
|
|
43
|
+
where(field: QueryField<T>, operator: ComparisonOperator, value: QueryValue): IQueryBuilder<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Add an AND where clause to the query
|
|
46
|
+
*/
|
|
47
|
+
andWhere(queryString: string): IQueryBuilder<T>;
|
|
48
|
+
andWhere(field: QueryField<T>, operator: ComparisonOperator, value: QueryValue): IQueryBuilder<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Add an OR where clause to the query
|
|
51
|
+
*/
|
|
52
|
+
orWhere(queryString: string): IQueryBuilder<T>;
|
|
53
|
+
orWhere(field: QueryField<T>, operator: ComparisonOperator, value: QueryValue): IQueryBuilder<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Add a NOT where clause to the query
|
|
56
|
+
*/
|
|
57
|
+
notWhere(queryString: string): IQueryBuilder<T>;
|
|
58
|
+
notWhere(field: QueryField<T>, operator: ComparisonOperator, value: QueryValue): IQueryBuilder<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Add an order by clause to the query
|
|
61
|
+
*/
|
|
62
|
+
orderBy(field: QueryField<T>, direction?: SortDirection): IQueryBuilder<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Add a limit to the query
|
|
65
|
+
*/
|
|
66
|
+
limit(count: number): IQueryBuilder<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Add an offset to the query
|
|
69
|
+
*/
|
|
70
|
+
offset(count: number): IQueryBuilder<T>;
|
|
71
|
+
/**
|
|
72
|
+
* Get the current query expression
|
|
73
|
+
*/
|
|
74
|
+
getExpression(): QueryExpression;
|
|
75
|
+
/**
|
|
76
|
+
* Get the current query as a string
|
|
77
|
+
*/
|
|
78
|
+
toString(): string;
|
|
79
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./validator"), exports);
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security configuration types for QueryKit
|
|
3
|
+
*
|
|
4
|
+
* This module defines the security configuration interface and default values
|
|
5
|
+
* used throughout QueryKit to enforce security boundaries and prevent abuse.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @interface ISecurityOptions
|
|
9
|
+
* @description Comprehensive security configuration options for QueryKit
|
|
10
|
+
*
|
|
11
|
+
* These options help protect your application from potential security issues,
|
|
12
|
+
* resource exhaustion, and performance problems when exposing QueryKit to users.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { createQueryKit, type ISecurityOptions } from 'querykit';
|
|
17
|
+
*
|
|
18
|
+
* // Configure security options
|
|
19
|
+
* const securityOptions: ISecurityOptions = {
|
|
20
|
+
* allowedFields: ['id', 'name', 'createdAt'],
|
|
21
|
+
* denyFields: ['password', 'secretKey'],
|
|
22
|
+
* maxQueryDepth: 5,
|
|
23
|
+
* maxClauseCount: 20
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* // Create QueryKit instance with security options
|
|
27
|
+
* const queryKit = createQueryKit({
|
|
28
|
+
* // ...other options
|
|
29
|
+
* security: securityOptions
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface ISecurityOptions {
|
|
34
|
+
/**
|
|
35
|
+
* List of fields that are allowed to be queried.
|
|
36
|
+
* If empty, all fields in the schema are allowed by default.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Only allow specific fields to be queried
|
|
41
|
+
* allowedFields: ['id', 'name', 'email', 'createdAt']
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
allowedFields?: string[];
|
|
45
|
+
/**
|
|
46
|
+
* List of fields that are explicitly denied from being queried.
|
|
47
|
+
* These fields will be blocked even if they appear in allowedFields.
|
|
48
|
+
* Use this to protect sensitive data fields.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Prevent querying of sensitive fields
|
|
53
|
+
* denyFields: ['password', 'secretToken', 'ssn']
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
denyFields?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Maximum nesting depth of query expressions.
|
|
59
|
+
* Prevents deeply nested queries that could impact performance.
|
|
60
|
+
*
|
|
61
|
+
* @default 10
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* // Allow only simple queries with limited nesting
|
|
66
|
+
* maxQueryDepth: 3
|
|
67
|
+
*
|
|
68
|
+
* // This would allow queries like:
|
|
69
|
+
* // title:"Meeting notes" && (priority > 2 || completed == true)
|
|
70
|
+
* // But would reject more deeply nested expressions
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
maxQueryDepth?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Maximum number of clauses (AND/OR operations) in a query.
|
|
76
|
+
* Prevents overly complex queries that could impact performance.
|
|
77
|
+
*
|
|
78
|
+
* @default 50
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Limit query complexity
|
|
83
|
+
* maxClauseCount: 20
|
|
84
|
+
*
|
|
85
|
+
* // This would allow queries with up to 20 conditions joined by AND/OR
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
maxClauseCount?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Default limit for query results if none is specified by the client.
|
|
91
|
+
* Prevents unintentionally large result sets.
|
|
92
|
+
*
|
|
93
|
+
* @default 100
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* // Set conservative default limit
|
|
98
|
+
* defaultLimit: 50
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
defaultLimit?: number;
|
|
102
|
+
/**
|
|
103
|
+
* Maximum allowed limit for pagination.
|
|
104
|
+
* Prevents clients from requesting excessively large result sets.
|
|
105
|
+
*
|
|
106
|
+
* @default 1000
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Restrict maximum page size
|
|
111
|
+
* maxLimit: 500
|
|
112
|
+
*
|
|
113
|
+
* // Even if a client requests limit=10000, it will be capped at 500
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
maxLimit?: number;
|
|
117
|
+
/**
|
|
118
|
+
* Maximum string length for query values.
|
|
119
|
+
* Prevents memory exhaustion from extremely large string values.
|
|
120
|
+
*
|
|
121
|
+
* @default 1000
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // Limit string length in query values
|
|
126
|
+
* maxValueLength: 500
|
|
127
|
+
*
|
|
128
|
+
* // Prevents attacks using extremely long strings in filters
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
maxValueLength?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Whether to sanitize wildcard patterns in LIKE queries to prevent regex DoS.
|
|
134
|
+
* When enabled, excessive wildcard patterns are sanitized or rejected.
|
|
135
|
+
*
|
|
136
|
+
* @default true
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Enable wildcard sanitization
|
|
141
|
+
* sanitizeWildcards: true
|
|
142
|
+
*
|
|
143
|
+
* // Prevents regex DoS attacks like: name LIKE "%a%a%a%a%a%a%a%a%..."
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
sanitizeWildcards?: boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Timeout in milliseconds for query execution.
|
|
149
|
+
* Prevents long-running queries from consuming excessive resources.
|
|
150
|
+
*
|
|
151
|
+
* @default 30000 (30 seconds)
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // Set shorter timeout for API endpoints
|
|
156
|
+
* queryTimeout: 5000 // 5 seconds
|
|
157
|
+
*
|
|
158
|
+
* // Queries taking longer than 5 seconds will be terminated
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
queryTimeout?: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Default security configuration values
|
|
165
|
+
*
|
|
166
|
+
* These defaults provide a reasonable balance between functionality and security.
|
|
167
|
+
* It's recommended to review and adjust these settings based on your specific use case.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* import { DEFAULT_SECURITY_OPTIONS } from 'querykit';
|
|
172
|
+
*
|
|
173
|
+
* // Use defaults but override specific options
|
|
174
|
+
* const securityOptions = {
|
|
175
|
+
* ...DEFAULT_SECURITY_OPTIONS,
|
|
176
|
+
* maxLimit: 500,
|
|
177
|
+
* queryTimeout: 10000
|
|
178
|
+
* };
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare const DEFAULT_SECURITY_OPTIONS: Required<ISecurityOptions>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Security configuration types for QueryKit
|
|
4
|
+
*
|
|
5
|
+
* This module defines the security configuration interface and default values
|
|
6
|
+
* used throughout QueryKit to enforce security boundaries and prevent abuse.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DEFAULT_SECURITY_OPTIONS = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* Default security configuration values
|
|
12
|
+
*
|
|
13
|
+
* These defaults provide a reasonable balance between functionality and security.
|
|
14
|
+
* It's recommended to review and adjust these settings based on your specific use case.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { DEFAULT_SECURITY_OPTIONS } from 'querykit';
|
|
19
|
+
*
|
|
20
|
+
* // Use defaults but override specific options
|
|
21
|
+
* const securityOptions = {
|
|
22
|
+
* ...DEFAULT_SECURITY_OPTIONS,
|
|
23
|
+
* maxLimit: 500,
|
|
24
|
+
* queryTimeout: 10000
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
exports.DEFAULT_SECURITY_OPTIONS = {
|
|
29
|
+
// Field restrictions - by default, all schema fields are allowed
|
|
30
|
+
allowedFields: [], // Empty means "use schema fields"
|
|
31
|
+
denyFields: [], // Empty means no denied fields
|
|
32
|
+
// Query complexity limits
|
|
33
|
+
maxQueryDepth: 10, // Maximum nesting level of expressions
|
|
34
|
+
maxClauseCount: 50, // Maximum number of clauses (AND/OR operations)
|
|
35
|
+
// Resource protection
|
|
36
|
+
defaultLimit: 100, // Default result limit if none specified
|
|
37
|
+
maxLimit: 1000, // Maximum allowed limit for pagination
|
|
38
|
+
// Value sanitization
|
|
39
|
+
maxValueLength: 1000, // Maximum string length for query values
|
|
40
|
+
sanitizeWildcards: true, // Prevent regex DoS with wildcards in LIKE queries
|
|
41
|
+
// Performance safeguards
|
|
42
|
+
queryTimeout: 30000 // 30 second timeout by default
|
|
43
|
+
};
|