20 Commits

Author SHA1 Message Date
philkunz 50789d4416 2.0.4 2024-05-30 17:53:34 +02:00
philkunz d79d93ad30 fix(core): update 2024-05-30 17:53:33 +02:00
philkunz c9bd9dbe02 2.0.3 2024-05-30 16:57:18 +02:00
philkunz 1cf88b5aad fix(core): update 2024-05-30 16:57:18 +02:00
philkunz f02d175a2a 2.0.2 2024-05-30 15:08:10 +02:00
philkunz 9f1c880c6a fix(core): update 2024-05-30 15:08:09 +02:00
philkunz 1c417e15cc update description 2024-05-29 14:13:24 +02:00
philkunz 650e8f05f8 update tsconfig 2024-04-14 17:39:13 +02:00
philkunz fbf3245df3 update npmextra.json: githost 2024-04-01 21:35:15 +02:00
philkunz 01ec3c1605 update npmextra.json: githost 2024-04-01 19:58:20 +02:00
philkunz 090f46b2e6 update npmextra.json: githost 2024-03-30 21:47:19 +01:00
philkunz 396845bf45 switch to new org scheme 2023-07-11 00:45:43 +02:00
philkunz 29d5d709c3 switch to new org scheme 2023-07-10 02:56:07 +02:00
philkunz 4131ceda93 2.0.1 2022-03-22 00:20:28 +01:00
philkunz 6003625186 2.0.0 2022-03-21 21:53:47 +01:00
philkunz 3b50e9c8cc BREAKING CHANGE(core): updated to esm 2022-03-21 21:53:46 +01:00
philkunz 2e42011eda 1.0.5 2019-08-07 16:42:25 +02:00
philkunz d9512ae3e8 fix(core): update 2019-08-07 16:42:24 +02:00
philkunz 32e72dc131 1.0.4 2019-08-07 16:34:34 +02:00
philkunz 5371bd058a fix(core): update 2019-08-07 16:34:34 +02:00
19 changed files with 25080 additions and 1742 deletions
+1 -3
View File
@@ -15,8 +15,6 @@ node_modules/
# builds # builds
dist/ dist/
dist_web/ dist_*/
dist_serve/
dist_ts_web/
# custom # custom
+69 -46
View File
@@ -1,16 +1,19 @@
# gitzone ci_default # gitzone ci_default
image: hosttoday/ht-docker-node:npmci image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache: cache:
paths: paths:
- .npmci_cache/ - .npmci_cache/
key: "$CI_BUILD_STAGE" key: '$CI_BUILD_STAGE'
stages: stages:
- security - security
- test - test
- release - release
- metadata - metadata
before_script:
- npm install -g @shipzone/npmci
# ==================== # ====================
# security stage # security stage
@@ -18,60 +21,75 @@ stages:
mirror: mirror:
stage: security stage: security
script: script:
- npmci git mirror - npmci git mirror
only:
- tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
snyk: auditProductionDependencies:
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
stage: security stage: security
script: script:
- npmci npm prepare - npmci npm prepare
- npmci command npm install -g snyk - npmci command npm install --production --ignore-scripts
- npmci command npm install --ignore-scripts - npmci command npm config set registry https://registry.npmjs.org
- npmci command snyk test - npmci command npm audit --audit-level=high --only=prod --production
tags: tags:
- docker - docker
- notpriv allow_failure: true
auditDevDependencies:
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
stage: security
script:
- npmci npm prepare
- npmci command npm install --ignore-scripts
- npmci command npm config set registry https://registry.npmjs.org
- npmci command npm audit --audit-level=high --only=dev
tags:
- docker
allow_failure: true
# ==================== # ====================
# test stage # test stage
# ==================== # ====================
testLTS: testStable:
stage: test stage: test
script: script:
- npmci npm prepare - npmci npm prepare
- npmci node install lts - npmci node install stable
- npmci npm install - npmci npm install
- npmci npm test - npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/ coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- docker - docker
- notpriv
testSTABLE: testBuild:
stage: test stage: test
script: script:
- npmci npm prepare - npmci npm prepare
- npmci node install stable - npmci node install stable
- npmci npm install - npmci npm install
- npmci npm test - npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/ coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- docker - docker
- notpriv
release: release:
stage: release stage: release
script: script:
- npmci node install stable - npmci node install stable
- npmci npm publish - npmci npm publish
only: only:
- tags - tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
# ==================== # ====================
# metadata stage # metadata stage
@@ -79,33 +97,38 @@ release:
codequality: codequality:
stage: metadata stage: metadata
allow_failure: true allow_failure: true
only:
- tags
script: script:
- npmci command npm install -g tslint typescript - npmci command npm install -g typescript
- npmci npm prepare
- npmci npm install - npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags: tags:
- docker - lossless
- priv - docker
- priv
trigger: trigger:
stage: metadata stage: metadata
script: script:
- npmci trigger - npmci trigger
only: only:
- tags - tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
pages: pages:
image: hosttoday/ht-docker-node:npmci
stage: metadata stage: metadata
script: script:
- npmci command npm install -g @gitzone/tsdoc - npmci node install lts
- npmci command npm install -g @git.zone/tsdoc
- npmci npm prepare - npmci npm prepare
- npmci npm install - npmci npm install
- npmci command tsdoc - npmci command tsdoc
tags: tags:
- lossless
- docker - docker
- notpriv - notpriv
only: only:
@@ -113,5 +136,5 @@ pages:
artifacts: artifacts:
expire_in: 1 week expire_in: 1 week
paths: paths:
- public - public
allow_failure: true allow_failure: true
+3 -21
View File
@@ -2,28 +2,10 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "current file", "command": "npm test",
"type": "node", "name": "Run npm test",
"request": "launch", "request": "launch",
"args": [ "type": "node-terminal"
"${relativeFile}"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "test.ts",
"type": "node",
"request": "launch",
"args": [
"test/test.ts"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
} }
] ]
} }
+26
View File
@@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}
+27 -5
View File
@@ -1,17 +1,39 @@
{ {
"gitzone": { "gitzone": {
"projectType": "npm",
"module": { "module": {
"githost": "gitlab.com", "githost": "code.foss.global",
"gitscope": "pushrocks", "gitscope": "push.rocks",
"gitrepo": "smartguard", "gitrepo": "smartguard",
"shortDescription": "smart guards for validations", "description": "A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.",
"npmPackagename": "@pushrocks/smartguard", "npmPackagename": "@push.rocks/smartguard",
"license": "MIT", "license": "MIT",
"projectDomain": "push.rocks" "projectDomain": "push.rocks",
"keywords": [
"validation",
"guards",
"typescript",
"async",
"nodejs",
"express",
"middleware",
"security",
"input validation",
"API",
"data validation",
"custom validation",
"composite validation",
"form validation",
"server-side validation",
"backend validation"
]
} }
}, },
"npmci": { "npmci": {
"npmGlobalTools": [], "npmGlobalTools": [],
"npmAccessLevel": "public" "npmAccessLevel": "public"
},
"tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
} }
} }
+17672 -1577
View File
File diff suppressed because it is too large Load Diff
+52 -14
View File
@@ -1,10 +1,11 @@
{ {
"name": "@pushrocks/smartguard", "name": "@push.rocks/smartguard",
"version": "1.0.3", "version": "2.0.4",
"private": false, "private": false,
"description": "smart guards for validations", "description": "A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.",
"main": "dist/index.js", "main": "dist_ts/index.js",
"typings": "dist/index.d.ts", "typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
@@ -13,16 +14,53 @@
"format": "(gitzone format)" "format": "(gitzone format)"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.0.22", "@api.global/typedserver": "^3.0.50",
"@gitzone/tstest": "^1.0.15", "@git.zone/tsbuild": "^2.1.66",
"@pushrocks/smartexpress": "^3.0.35", "@git.zone/tsrun": "^1.2.46",
"@pushrocks/tapbundle": "^3.0.7", "@git.zone/tstest": "^1.0.77",
"@types/node": "^10.11.7", "@push.rocks/tapbundle": "^5.0.8",
"tslint": "^5.11.0", "@types/node": "^20.12.13"
"tslint-config-prettier": "^1.15.0"
}, },
"dependencies": { "dependencies": {
"@pushrocks/smartpromise": "^3.0.2", "@push.rocks/smartpromise": "^4.0.2",
"@pushrocks/smartrequest": "^1.1.16" "@push.rocks/smartrequest": "^2.0.15"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
],
"keywords": [
"validation",
"guards",
"typescript",
"async",
"nodejs",
"express",
"middleware",
"security",
"input validation",
"API",
"data validation",
"custom validation",
"composite validation",
"form validation",
"server-side validation",
"backend validation"
],
"homepage": "https://code.foss.global/push.rocks/smartguard",
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smartguard.git"
} }
} }
+6691
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
+431
View File
@@ -0,0 +1,431 @@
# @push.rocks/smartguard
A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.
## Install
To install `@push.rocks/smartguard`, run the following command in your terminal:
```bash
npm install @push.rocks/smartguard --save
```
This will add `@push.rocks/smartguard` to your project's dependencies.
## Usage
`@push.rocks/smartguard` provides a robust and easy way to validate data by using guards. Guards are functions that return a boolean value indicating whether the data meets certain criteria. This package is highly beneficial for input validation, security checks, or any scenario where data needs to conform to specific rules or patterns.
### Basics
At the core of `@push.rocks/smartguard` are two main classes: `Guard` and `GuardSet`. A `Guard` represents a single rule or validation step, while a `GuardSet` allows you to combine multiple `Guard` instances and evaluate them together.
### Creating a Guard
A `Guard` is an object that encapsulates a validation rule. You define a guard by providing a function that takes an input and returns a Promise, resolving to a boolean value indicating if the input meets the criteria.
```typescript
import { Guard } from '@push.rocks/smartguard';
const isStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string';
});
```
In the example above, we define a simple guard that checks if the input is a string.
### Using GuardSets for Composite Validations
When you have multiple validation rules, you can combine them using `GuardSet`. This allows you to evaluate all guards on a piece of data and only pass if all guards return true.
```typescript
import { Guard, GuardSet } from '@push.rocks/smartguard';
const isStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string';
});
const isNotEmptyGuard = new Guard<string>(async (data) => {
return data.length > 0;
});
const stringValidationSet = new GuardSet<string>([isStringGuard, isNotEmptyGuard]);
// Now you can use stringValidationSet.executeGuardsWithData(data) to validate your data
```
### Executing Guards
To execute a guard or a set of guards against data, you use the `executeGuardWithData` method for a single guard, or `executeGuardsWithData` method for a `GuardSet`.
```typescript
const isValidString = await isStringGuard.executeGuardWithData('Hello World!');
console.log(isValidString); // true
const areValidStrings = await stringValidationSet.executeGuardsWithData('Hello World!');
console.log(areValidStrings.every(result => result)); // true if all validations passed
```
### Advanced Usage: Custom Guard Functions
Guards can perform any asynchronous operation inside their validation function, making them incredibly versatile. For instance, you could call an API to validate an address, check if a username already exists in a database, or even integrate with third-party validation services.
```typescript
import { Guard } from '@push.rocks/smartguard';
import { someApiRequestFunction } from './myApiFunctions';
const isValidAddressGuard = new Guard<string>(async (address) => {
const response = await someApiRequestFunction(address);
return response.isValid;
});
```
### Integrating with Express Middleware
`@push.rocks/smartguard` can easily integrate with frameworks like Express by utilizing guards within middleware functions. This allows you to perform validations before a request reaches your route handlers.
```typescript
import * as express from 'express';
import { Guard } from '@push.rocks/smartguard';
const app = express();
const isAuthorizedUserGuard = new Guard<express.Request>(async (req) => {
// your logic here, return true if authorized
return req.headers.authorization === 'Bearer some-token';
});
app.use(async (req, res, next) => {
const isAuthorized = await isAuthorizedUserGuard.executeGuardWithData(req);
if (!isAuthorized) {
res.status(403).send('Unauthorized');
return;
}
next();
});
app.listen(3000, () => console.log('Server running on port 3000'));
```
In the example above, we use a guard to check if a request has a valid authorization header. This demonstrates how `@push.rocks/smartguard` can be seamlessly integrated into existing server applications to enforce security or input validations.
### Combining Guards with `GuardSet`
One of the strengths of `@push.rocks/smartguard` is its ability to combine multiple guards into a `GuardSet`. This is particularly useful when you need to validate data against several criteria. For example, to validate a string that must be non-empty and start with a specific prefix:
```typescript
import { Guard, GuardSet } from '@push.rocks/smartguard';
const isStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string';
});
const isNotEmptyGuard = new Guard<string>(async (data) => {
return data.length > 0;
});
const startsWithPrefixGuard = new Guard<string>(async (data) => {
return data.startsWith('prefix');
});
const combinedValidationSet = new GuardSet<string>([isStringGuard, isNotEmptyGuard, startsWithPrefixGuard]);
const validationResults = await combinedValidationSet.executeGuardsWithData('prefix: Valid String');
console.log(validationResults.every(result => result)); // true if all validations passed
```
### Integration with Other Libraries
To demonstrate the versatility and integration capabilities of `@push.rocks/smartguard`, let's integrate it with another popular library, `@push.rocks/smartrequest`, for validating API response data.
```typescript
import { Guard } from '@push.rocks/smartguard';
import { smartrequest } from '@push.rocks/smartrequest';
const validApiResponseGuard = new Guard(async (url: string) => {
const response = await smartrequest.request(url, { method: 'GET' });
return response.status === 200;
});
const isValidResponse = await validApiResponseGuard.executeGuardWithData('https://example.com/api/data');
console.log(isValidResponse); // true if the API response status is 200
```
### Real-World Example: Form Validation
Let's create a real-world example where we use `@push.rocks/smartguard` to validate form data in a Node.js application. Suppose we have a user registration form with fields for `username`, `email`, and `password`.
```typescript
import { Guard, GuardSet } from '@push.rocks/smartguard';
// Guards for individual fields
const isUsernameValid = new Guard<string>(async (username) => {
return typeof username === 'string' && username.length >= 3;
});
const isEmailValid = new Guard<string>(async (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return typeof email === 'string' && emailRegex.test(email);
});
const isPasswordStrong = new Guard<string>(async (password) => {
return typeof password === 'string' && password.length >= 8;
});
// Combining guards using GuardSet
const registrationValidationSet = new GuardSet<{ username: string, email: string, password: string }>([
new Guard(async (data) => isUsernameValid.executeGuardWithData(data.username)),
new Guard(async (data) => isEmailValid.executeGuardWithData(data.email)),
new Guard(async (data) => isPasswordStrong.executeGuardWithData(data.password))
]);
// Form data to validate
const formData = {
username: 'exampleUser',
email: 'user@example.com',
password: 'strongpassword123'
};
const formValidationResults = await registrationValidationSet.executeGuardsWithData(formData);
console.log(formValidationResults.every(result => result)); // true if all fields are valid
```
In this example, we used guards to validate each form field. We then combined these guards into a `GuardSet` to validate the entire form data object.
### Validating Nested Objects
`@push.rocks/smartguard` can also handle validation of nested objects. Suppose you need to validate a user profile that includes nested address information.
```typescript
interface UserProfile {
username: string;
email: string;
address: {
street: string;
city: string;
postalCode: string;
};
}
const isStreetValid = new Guard<string>(async (street) => {
return typeof street === 'string' && street.length > 0;
});
const isCityValid = new Guard<string>(async (city) => {
return typeof city === 'string' && city.length > 0;
});
const isPostalCodeValid = new Guard<string>(async (postalCode) => {
return typeof postalCode === 'string' && /^[0-9]{5}$/.test(postalCode);
});
const isAddressValid = new Guard<UserProfile['address']>(async (address) => {
const streetValid = await isStreetValid.executeGuardWithData(address.street);
const cityValid = await isCityValid.executeGuardWithData(address.city);
const postalCodeValid = await isPostalCodeValid.executeGuardWithData(address.postalCode);
return streetValid && cityValid && postalCodeValid;
});
const isUsernameValid = new Guard<string>(async (username) => {
return typeof username === 'string' && username.length >= 3;
});
const isEmailValid = new Guard<string>(async (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return typeof email === 'string' && emailRegex.test(email);
});
const userProfileValidationSet = new GuardSet<UserProfile>([
new Guard(async (data) => isUsernameValid.executeGuardWithData(data.username)),
new Guard(async (data) => isEmailValid.executeGuardWithData(data.email)),
new Guard(async (data) => isAddressValid.executeGuardWithData(data.address))
]);
const userProfile = {
username: 'exampleUser',
email: 'user@example.com',
address: {
street: '123 Main St',
city: 'Anytown',
postalCode: '12345'
}
};
const userProfileValidationResults = await userProfileValidationSet.executeGuardsWithData(userProfile);
console.log(userProfileValidationResults.every(result => result)); // true if user profile is valid
```
In this example, we created a nested guard structure to validate a user profile object that includes address information. Each nested object is validated individually using its specific guards.
### Dynamic Guards
There can be situations when you need to create guards dynamically based on some conditions or input. `@push.rocks/smartguard` allows you to create and use such dynamic guards effortlessly.
```typescript
import { Guard, GuardSet } from '@push.rocks/smartguard';
const createDynamicGuard = (minLength: number) => new Guard<string>(async (data) => {
return data.length >= minLength;
});
const flexibleLengthGuardSet = (length: number) => new GuardSet<string>([createDynamicGuard(length)]);
const dynamicGuard = flexibleLengthGuardSet(5);
const isValid = await dynamicGuard.executeGuardsWithData('Hello, world!');
console.log(isValid.every(result => result)); // true because the length of 'Hello, world!' is more than 5
```
In the example above, we created a dynamic guard based on a minimum length and then evaluated some data against it.
### Validating Complex Data Structures
There can often be a need to validate complex data structures with nested arrays or objects. Using a combination of `Guard` and `GuardSet`, you can effectively handle validations of such complex structures.
```typescript
interface BlogPost {
title: string;
content: string;
tags: string[];
author: {
name: string;
email: string;
};
}
const isStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string';
});
const isNonEmptyStringGuard = new Guard<string>(async (data) => {
return await isStringGuard.executeGuardWithData(data) && data.trim().length > 0;
});
const isStringArrayGuard = new Guard<string[]>(async (data) => {
return Array.isArray(data) && data.every(item => typeof item === 'string');
});
const isEmailGuard = new Guard<string>(async (data) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return typeof data === 'string' && emailRegex.test(data);
});
const isAuthorGuardSet = new GuardSet<BlogPost['author']>([
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.name)),
new Guard(async (data) => await isEmailGuard.executeGuardWithData(data.email))
]);
const isBlogPostGuardSet = new GuardSet<BlogPost>([
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.title)),
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.content)),
new Guard(async (data) => await isStringArrayGuard.executeGuardWithData(data.tags)),
new Guard(async (data) => await isAuthorGuardSet.executeGuardsWithData(data.author).then(results => results.every(result => result)))
]);
const blogPost: BlogPost = {
title: 'Introduction to Smart Guard',
content: 'Smart Guard is a TypeScript library for creating and managing validation guards...',
tags: ['typescript', 'validation', 'library'],
author: {
name: 'John Doe',
email: 'johndoe@example.com'
}
};
const blogPostValidationResults = await isBlogPostGuardSet.executeGuardsWithData(blogPost);
console.log(blogPostValidationResults.every(result => result)); // true if the blog post is valid
```
In this example, we created different guards to validate various parts of a complex `BlogPost` object. Notice how we used nested `GuardSet` instances to validate the `author` object.
### Asynchronous Validations
`@push.rocks/smartguard` supports asynchronous guard functions, making it possible to perform validations that involve network requests or other asynchronous operations.
```typescript
import { Guard } from '@push.rocks/smartguard';
import { smartrequest } from '@push.rocks/smartrequest';
const isApiKeyValidGuard = new Guard<string>(async (apiKey) => {
const response = await smartrequest.request(`https://api.example.com/validate?key=${apiKey}`, { method: 'GET' });
return response.status === 200;
});
const apiKey = 'some-api-key';
const isApiKeyValid = await isApiKeyValidGuard.executeGuardWithData(apiKey);
console.log(isApiKeyValid); // true if the API key is valid
```
In this example, the guard performs an asynchronous API request to validate an API key.
### Default Error Handling
When using `@push.rocks/smartguard`, you can take advantage of built-in error handling mechanisms. If a guard fails, it throws an error that you can catch and handle accordingly.
```typescript
import { Guard, passGuardsOrReject } from '@push.rocks/smartguard';
const isNonEmptyStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string' && data.trim().length > 0;
});
const validateInput = async (input: string) => {
try {
await passGuardsOrReject(input, [isNonEmptyStringGuard]);
console.log('Input is valid');
} catch (error) {
console.error('Validation failed:', error.message);
}
};
await validateInput(''); // Will print "Validation failed: Guard failed"
await validateInput('Valid input'); // Will print "Input is valid"
```
In this example, we use the `passGuardsOrReject` function to validate an input. If the input is invalid, `passGuardsOrReject` throws an error that is caught and handled in the `catch` block.
### Extending Guard Functionalities
Sometimes, you may need to extend or customize the functionalities of a guard to suit specific requirements. `@push.rocks/smartguard` allows you to extend the `Guard` class to create specialized guards.
```typescript
import { Guard } from '@push.rocks/smartguard';
class MinLengthGuard extends Guard<string> {
constructor(private minLength: number) {
super(async (data) => {
return typeof data === 'string' && data.length >= this.minLength;
});
}
}
const minLengthGuard = new MinLengthGuard(10);
const isLongEnough = await minLengthGuard.executeGuardWithData('Hello, world!');
console.log(isLongEnough); // true because the length of 'Hello, world!' is more than 10
```
In this example, we create a `MinLengthGuard` class that extends `Guard` and validates a string based on its minimum length.
### Conclusion
`@push.rocks/smartguard` provides a powerful framework for creating and managing validation guards in JavaScript and TypeScript applications. The library's flexibility allows it to handle simple boolean checks, asynchronous operations, integration with external APIs, and complex composite validations. Its use of `Guard` and `GuardSet` classes ensures that validations are both modular and reusable.
Whether you are validating form inputs, securing APIs, or ensuring data integrity in your backend services, `@push.rocks/smartguard` simplifies the process and makes your code cleaner and more maintainable.
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
+25 -19
View File
@@ -1,23 +1,23 @@
import { expect, tap } from '@pushrocks/tapbundle'; import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
import * as smartguard from '../ts/index'; import * as smartguard from '../ts/index.js';
import * as smartexpress from '@pushrocks/smartexpress'; import * as typedserver from '@api.global/typedserver';
import * as smartrequest from '@pushrocks/smartrequest'; import * as smartrequest from '@push.rocks/smartrequest';
let smartexpressInstance: smartexpress.Server; let smartexpressInstance: typedserver.servertools.Server;
tap.test('should create a demo smartexpress instance', async () => { tap.test('should create a demo smartexpress instance', async () => {
smartexpressInstance = new smartexpress.Server({ smartexpressInstance = new typedserver.servertools.Server({
cors: true, cors: true,
forceSsl: false, forceSsl: false,
defaultAnswer: async () => 'hi there', defaultAnswer: async () => 'hi there',
port: 3211 port: 3211,
}); });
}); });
tap.test('should be able to create smartguards for a request', async () => { tap.test('should be able to create smartguards for a request', async () => {
interface IRequestGuardData { interface IRequestGuardData {
req: smartexpress.Request; req: typedserver.Request;
res: smartexpress.Response; res: typedserver.Response;
} }
const ipGuard = new smartguard.Guard<IRequestGuardData>(async (dataArg) => { const ipGuard = new smartguard.Guard<IRequestGuardData>(async (dataArg) => {
console.log('executing ip guard'); console.log('executing ip guard');
@@ -30,15 +30,21 @@ tap.test('should be able to create smartguards for a request', async () => {
} }
}); });
smartexpressInstance.addRoute('/testroute', new smartexpress.Handler('ALL', async (req, res) => { smartexpressInstance.addRoute(
await smartguard.passGuards({ '/testroute',
req, new typedserver.servertools.Handler('ALL', async (req, res) => {
res await smartguard.passGuardsOrReject(
}, [ipGuard]); {
console.log('ip guard said ok'); req,
res.status(200); res,
res.send('hi'); },
})); [ipGuard]
);
console.log('ip guard said ok');
res.status(200);
res.send('hi');
})
);
console.log('Got here ok'); console.log('Got here ok');
}); });
@@ -48,7 +54,7 @@ tap.test('should start server with guards in place', async () => {
tap.test('should execute a request', async () => { tap.test('should execute a request', async () => {
const response = await smartrequest.request('http://localhost:3211/testroute', { const response = await smartrequest.request('http://localhost:3211/testroute', {
method: 'GET' method: 'GET',
}); });
}); });
+8
View File
@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartguard',
version: '2.0.4',
description: 'A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.'
}
+10 -14
View File
@@ -1,18 +1,14 @@
import * as plugins from './smartguard.plugins'; import * as plugins from './smartguard.plugins.js';
import { Guard } from './smartguard.classes.guard'; import { Guard } from './smartguard.classes.guard.js';
import { GuardSet } from './smartguard.classes.guardset'; import { GuardSet } from './smartguard.classes.guardset.js';
export * from './smartguard.classes.guard'; export * from './smartguard.classes.guard.js';
export * from './smartguard.classes.guardset.js';
export const passGuards = async <T>(dataArg: T, guards: Array<Guard<T>>) => { export const passGuardsOrReject = async <T>(dataArg: T, guards: Array<Guard<T>>) => {
const done = plugins.smartpromise.defer();
const guardSet = new GuardSet<T>(guards); const guardSet = new GuardSet<T>(guards);
const results = await guardSet.executeGuardsWithData(dataArg); const result = await guardSet.allGuardsPass(dataArg);
for (const result of results) { if (!result) {
if(!result) { throw new Error('Guard failed');
return;
}
} }
done.resolve(); return ;
await done.promise;
return;
}; };
+2 -4
View File
@@ -1,8 +1,6 @@
import * as plugins from './smartguard.plugins'; import * as plugins from './smartguard.plugins.js';
/** /**
* a block handler is used * a block handler is used
*/ */
export class BlockHandler { export class BlockHandler {}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import * as plugins from './smartguard.plugins'; import * as plugins from './smartguard.plugins.js';
export type TGuardFunction<T> = (dataArg: T) => Promise<boolean>; export type TGuardFunction<T> = (dataArg: T) => Promise<boolean>;
+39 -11
View File
@@ -1,23 +1,51 @@
import * as plugins from './smartguard.plugins'; import * as plugins from './smartguard.plugins.js';
import { Guard } from './smartguard.classes.guard'; import { Guard, type TGuardFunction } from './smartguard.classes.guard.js';
/** /**
* a guardSet is a set of guards that need to be fulfilled * Extended GuardSet that inherits from Guard
* and provides additional functionalities.
*/ */
export class GuardSet<T> { export class GuardSet<T> extends Guard<T> {
public guards: Array<Guard<T>>; public guards: Array<Guard<T>>;
public passed: boolean;
constructor(guardsArrayArg: Array<Guard<T>>) { constructor(guardArray: Array<Guard<T>> = []) {
this.guards = guardsArrayArg; super(async (dataArg: T) => {
return this.allGuardsPass(dataArg);
})
this.guards = guardArray;
} }
public async executeGuardsWithData(dataArg: T) { /**
* executes all guards in all guardSets against a data argument
* @param dataArg
*/
public async executeAllGuardsWithData(dataArg: T) {
const resultPromises: Array<Promise<boolean>> = []; const resultPromises: Array<Promise<boolean>> = [];
for (const guard of this.guards) { for (const guard of this.guards) {
const resultPromise = guard.executeGuardWithData(dataArg); const guardResultPromise = guard.executeGuardWithData(dataArg);
resultPromises.push(resultPromise); resultPromises.push(guardResultPromise);
} }
const results = Promise.all(resultPromises);
const results = await Promise.all(resultPromises);
return results; return results;
} }
/**
* checks if all guards pass
* @param dataArg
*/
public async allGuardsPass(dataArg: T): Promise<boolean> {
const results = await this.executeAllGuardsWithData(dataArg);
return results.every(result => result);
}
/**
* checks if any guard passes
* @param dataArg
*/
public async anyGuardsPass(dataArg: T): Promise<boolean> {
const results = await this.executeAllGuardsWithData(dataArg);
return results.some(result => result);
}
} }
+2 -4
View File
@@ -1,6 +1,4 @@
import * as smartpromise from '@pushrocks/smartpromise'; import * as smartpromise from '@push.rocks/smartpromise';
// pushrocks scope // pushrocks scope
export { export { smartpromise };
smartpromise
};
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
}