Socket
Socket
Sign inDemoInstall

rsdi

Package Overview
Dependencies
0
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.4.1 to 3.0.0-alpha.1

44

dist/DIContainer.d.ts

@@ -1,32 +0,18 @@

import { DependencyResolver, IDIContainer, NamedResolvers, ResolveDependencyType, ResolverName, ConvertToDefinedDependencies, NonStrictNamedResolvers } from "./types";
import ReferenceResolver from "./resolvers/ReferenceResolver";
/**
* Dependency injection container
*/
export default class DIContainer<ContainerResolvers extends NamedResolvers = {}> implements IDIContainer<ContainerResolvers> {
type Factory<ContainerResolvers extends ResolvedDependencies> = (resolvers: ContainerResolvers) => any;
type ResolvedDependencies = {
[k: string]: any;
};
type StringLiteral<T> = T extends string ? string extends T ? never : T : never;
type Container<ContainerResolvers extends ResolvedDependencies> = DIContainer<ContainerResolvers> & ContainerResolvers;
export default class DIContainer<ContainerResolvers extends ResolvedDependencies = {}> {
private resolvers;
private resolvedDependencies;
/**
* Resolves dependency by name
* @param dependencyName - DefinitionName name of the dependency. String or class name.
* @param parentDeps - array of parent dependencies (used to detect circular dependencies)
*/
get<UserDefinedType = void, Name extends ResolverName<ContainerResolvers> = ResolverName<ContainerResolvers>>(dependencyName: Name, parentDeps?: string[]): UserDefinedType extends void ? ResolveDependencyType<ContainerResolvers, Name> : UserDefinedType;
use<Name extends ResolverName<ContainerResolvers> = ResolverName<ContainerResolvers>>(dependencyName: Name): ReferenceResolver<ContainerResolvers, Name>;
/**
* Adds multiple dependency resolvers to the container
* @param resolvers - named dependency object
*/
add<N extends NonStrictNamedResolvers>(resolvers: N): asserts this is this & DIContainer<ConvertToDefinedDependencies<N>>;
/**
* Adds single dependency definition to the container
* @param name - string name for the dependency
* @param resolver - raw value or instance of IDefinition
*/
private addResolver;
__(): ContainerResolvers;
private context;
add<N extends string, R extends Factory<ContainerResolvers>>(name: StringLiteral<N>, resolver: R): Container<ContainerResolvers & {
[n in N]: ReturnType<R>;
}>;
get<Name extends keyof ContainerResolvers>(dependencyName: Name): ContainerResolvers[Name];
extend<E extends (container: Container<ContainerResolvers>) => any>(f: E): ReturnType<E>;
private toContainer;
}
/**
* Resolves given function parameters
*/
export declare function resolveFunctionParameters(diContainer: DIContainer, parameters?: Array<DependencyResolver<any> | any>, parentDeps?: string[]): any[];
export {};
"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveFunctionParameters = void 0;
var AbstractResolver_1 = __importDefault(require("./resolvers/AbstractResolver"));
var RawValueResolver_1 = __importDefault(require("./resolvers/RawValueResolver"));
var errors_1 = require("./errors");
var DefinitionName_1 = require("./DefinitionName");
var ReferenceResolver_1 = __importDefault(require("./resolvers/ReferenceResolver"));
/**
* Dependency injection container
*/
var DIContainer = /** @class */ (function () {
function DIContainer() {
const errors_1 = require("./errors");
const containerMethods = ["add", "get", "extend"];
class DIContainer {
constructor() {
this.resolvers = {};
this.resolvedDependencies = {};
this.context = {};
}
/**
* Resolves dependency by name
* @param dependencyName - DefinitionName name of the dependency. String or class name.
* @param parentDeps - array of parent dependencies (used to detect circular dependencies)
*/
DIContainer.prototype.get = function (dependencyName, parentDeps) {
if (parentDeps === void 0) { parentDeps = []; }
var name = (0, DefinitionName_1.definitionNameToString)(dependencyName);
if (!(name in this.resolvers)) {
throw new errors_1.DependencyIsMissingError(name);
add(name, resolver) {
if (containerMethods.includes(name)) {
throw new errors_1.ForbiddenNameError(name);
}
if (parentDeps.includes(name)) {
throw new errors_1.CircularDependencyError(name, parentDeps);
this.resolvers = Object.assign(Object.assign({}, this.resolvers), { [name]: resolver });
let updatedObject = this;
if (!this.hasOwnProperty(name)) {
updatedObject = Object.defineProperty(this, name, {
get() {
return this.get(name);
},
});
}
if (this.resolvedDependencies[name] !== undefined) {
return this.resolvedDependencies[name];
}
var definition = this.resolvers[name];
definition.setParentDependencies(__spreadArray(__spreadArray([], parentDeps, true), [name], false));
this.resolvedDependencies[name] = definition.resolve(this);
return this.resolvedDependencies[name];
};
DIContainer.prototype.use = function (dependencyName) {
return new ReferenceResolver_1.default(dependencyName);
};
/**
* Adds multiple dependency resolvers to the container
* @param resolvers - named dependency object
*/
DIContainer.prototype.add = function (resolvers) {
var _this = this;
Object.keys(resolvers).forEach(function (name) {
_this.addResolver(name, resolvers[name]);
this.context = new Proxy(this, {
get(target, property) {
if (containerMethods.includes(property.toString())) {
throw new errors_1.IncorrectInvocationError();
}
// @ts-ignore
return target[property];
},
});
};
/**
* Adds single dependency definition to the container
* @param name - string name for the dependency
* @param resolver - raw value or instance of IDefinition
*/
DIContainer.prototype.addResolver = function (name, resolver) {
if (!(resolver instanceof AbstractResolver_1.default)) {
resolver = new RawValueResolver_1.default(resolver);
return updatedObject;
}
get(dependencyName) {
if (this.resolvedDependencies[dependencyName] !== undefined) {
return this.resolvedDependencies[dependencyName];
}
this.resolvers[name] = resolver;
};
DIContainer.prototype.__ = function () {
throw new Error("Method not implemented.");
};
return DIContainer;
}());
exports.default = DIContainer;
/**
* Resolves given function parameters
*/
function resolveFunctionParameters(diContainer, parameters, parentDeps) {
if (parameters === void 0) { parameters = []; }
if (parentDeps === void 0) { parentDeps = []; }
return parameters.map(function (parameter) {
if (parameter instanceof AbstractResolver_1.default) {
parameter.setParentDependencies(parentDeps);
return parameter.resolve(diContainer);
const resolver = this.resolvers[dependencyName];
if (!resolver) {
throw new errors_1.DependencyIsMissingError(dependencyName);
}
return parameter;
});
this.resolvedDependencies[dependencyName] = resolver(this.context);
return this.resolvedDependencies[dependencyName];
}
extend(f) {
return f(this.toContainer());
}
toContainer() {
return this;
}
}
exports.resolveFunctionParameters = resolveFunctionParameters;
//# sourceMappingURL=DIContainer.js.map
exports.default = DIContainer;

@@ -1,15 +0,9 @@

export declare class CircularDependencyError extends Error {
constructor(name: string, path: string[]);
}
export declare class DependencyIsMissingError extends Error {
constructor(name: string);
}
export declare class InvalidConstructorError extends Error {
constructor();
export declare class ForbiddenNameError extends Error {
constructor(name: string);
}
export declare class MethodIsMissingError extends Error {
constructor(objectName: string, methodName: string);
}
export declare class FactoryDefinitionError extends Error {
export declare class IncorrectInvocationError extends Error {
constructor();
}
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.FactoryDefinitionError = exports.MethodIsMissingError = exports.InvalidConstructorError = exports.DependencyIsMissingError = exports.CircularDependencyError = void 0;
var CircularDependencyError = /** @class */ (function (_super) {
__extends(CircularDependencyError, _super);
function CircularDependencyError(name, path) {
return _super.call(this, "Circular Dependency is detected. Dependency: \"".concat(name, "\", path: ") +
path.join(" -> ") +
".") || this;
exports.IncorrectInvocationError = exports.ForbiddenNameError = exports.DependencyIsMissingError = void 0;
class DependencyIsMissingError extends Error {
constructor(name) {
super(`Dependency with name ${name} is not defined`);
}
return CircularDependencyError;
}(Error));
exports.CircularDependencyError = CircularDependencyError;
var DependencyIsMissingError = /** @class */ (function (_super) {
__extends(DependencyIsMissingError, _super);
function DependencyIsMissingError(name) {
return _super.call(this, "Dependency with name ".concat(name, " is not defined")) || this;
}
return DependencyIsMissingError;
}(Error));
}
exports.DependencyIsMissingError = DependencyIsMissingError;
var InvalidConstructorError = /** @class */ (function (_super) {
__extends(InvalidConstructorError, _super);
function InvalidConstructorError() {
return _super.call(this, "Invalid constructor have been provided") || this;
class ForbiddenNameError extends Error {
constructor(name) {
super(`Dependency with name ${name} is not allowed`);
}
return InvalidConstructorError;
}(Error));
exports.InvalidConstructorError = InvalidConstructorError;
var MethodIsMissingError = /** @class */ (function (_super) {
__extends(MethodIsMissingError, _super);
function MethodIsMissingError(objectName, methodName) {
return _super.call(this, "".concat(methodName, " is not a member of ").concat(objectName)) || this;
}
exports.ForbiddenNameError = ForbiddenNameError;
class IncorrectInvocationError extends Error {
constructor() {
super(`Incorrect invocation of DIContainer`);
}
return MethodIsMissingError;
}(Error));
exports.MethodIsMissingError = MethodIsMissingError;
var FactoryDefinitionError = /** @class */ (function (_super) {
__extends(FactoryDefinitionError, _super);
function FactoryDefinitionError() {
return _super.call(this, "Factory must be a function") || this;
}
return FactoryDefinitionError;
}(Error));
exports.FactoryDefinitionError = FactoryDefinitionError;
//# sourceMappingURL=errors.js.map
}
exports.IncorrectInvocationError = IncorrectInvocationError;
import DIContainer from "./DIContainer";
import { diObject as object, diValue as value, diUse as use, diFactory as factory, diFunc as func } from "./resolversShorthands";
import { IDIContainer } from "./types";
export default DIContainer;
export { object, value, use, func, factory, IDIContainer };

@@ -6,11 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.factory = exports.func = exports.use = exports.value = exports.object = void 0;
var DIContainer_1 = __importDefault(require("./DIContainer"));
var resolversShorthands_1 = require("./resolversShorthands");
Object.defineProperty(exports, "object", { enumerable: true, get: function () { return resolversShorthands_1.diObject; } });
Object.defineProperty(exports, "value", { enumerable: true, get: function () { return resolversShorthands_1.diValue; } });
Object.defineProperty(exports, "use", { enumerable: true, get: function () { return resolversShorthands_1.diUse; } });
Object.defineProperty(exports, "factory", { enumerable: true, get: function () { return resolversShorthands_1.diFactory; } });
Object.defineProperty(exports, "func", { enumerable: true, get: function () { return resolversShorthands_1.diFunc; } });
const DIContainer_1 = __importDefault(require("./DIContainer"));
exports.default = DIContainer_1.default;
//# sourceMappingURL=index.js.map
{
"name": "rsdi",
"version": "2.4.1",
"description": "Simple dependency injection container for JavaScript/TypeScript",
"scripts": {
"test": "jest",
"test:types": "jest -c jest.config.tsd.js",
"format": "prettier 'src/**/*.ts' --write",
"build": "tsc",
"deploy": "yarn version minor && yarn build && yarn npm publish",
"pre-commit": "lint-staged",
"lint": "yarn eslint src/**/**.ts",
"prettify": "prettier --write --ignore-unknown"
},
"version": "3.0.0-alpha.1",
"description": "TypeScript dependency injection container. Strong types without decorators.",
"keywords": [

@@ -27,7 +17,2 @@ "dependency injection",

],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"homepage": "https://github.com/radzserg/rsdi",
"author": "Sergey Radzishevskii <radzserg@gmail.com>",
"license": "ISC",
"lint-staged": {

@@ -39,22 +24,20 @@ "src/**/*.ts": [

},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"homepage": "https://github.com/radzserg/rsdi",
"author": "Sergey Radzishevskii <radzserg@gmail.com>",
"license": "ISC",
"devDependencies": {
"@tsd/typescript": "^5.0.4",
"@types/jest": "^29.5.1",
"@types/node": "^20.1.2",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"eslint": "^8.17.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"husky": "^7.0.2",
"jest": "^29.5.0",
"jest-runner-tsd": "^5.0.0",
"lint-staged": "^11.2.0",
"prettier": "^2.6.2",
"ts-jest": "^29.1.0",
"tsd": "^0.20.0",
"typescript": "^5.0.4"
"eslint": "^8.44.0",
"husky": "^8.0.3",
"lint-staged": "^13.2.3",
"prettier": "^3.0.0",
"tsd": "^0.28.1",
"typescript": "^5.1.6",
"vitest": "^0.33.0"
},
"scripts": {
"build": "tsc",
"test": "vitest"
}
}
# RSDI - Dependency Injection Container
Simple and powerful dependency injection container for with strong type checking system.
Simple and powerful dependency injection container for with strong type checking system. `rsdi` offers strong
type-safety support.

@@ -9,9 +10,4 @@ - [Motivation](#motivation)

- [Architecture](#architecture)
- [Usage](#usage)
- [Raw values](#raw-values)
- [Object resolver](#object-resolver)
- [Function resolver](#function-resolver)
- [Factory resolver](#factory-resolver)
- [Typescript type resolution](#typescript-type-resolution)
- [Dependency declaration](#dependency-declaration)
- [How to use](#how-to-use)
- [Strict types](#strict-types)
- Wiki

@@ -23,13 +19,18 @@ - [Async factory resolver](./docs/async_factory_resolver.md)

Popular dependency injection libraries use `reflect-metadata` that allows to fetch argument types and based on
those types and do autowiring. Autowiring is a nice feature but the trade-off is decorators.
Popular dependency injection libraries utilize reflect-metadata to retrieve argument types and use those types
to carry out autowiring. Autowiring is an advantageous feature, but it necessitates the wrapping of all your
components with decorators.
```typescript
@injectable()
class Foo {}
class Foo {
constructor(@inject("Database") private database?: Database) {}
}
// Notice how in order to allow the use of the empty constructor new Foo(),
// we need to make the parameters optional, e.g. database?: Database.
```
Why component Foo should know that it's injectable?
Why should component Foo be aware that it's injectable?
Your business logic depends on a specific framework that is not part of your domain model and can change.
Your business logic relies on a particular framework, which isn't part of your domain model and is subject to change.

@@ -42,4 +43,3 @@ More thoughts in a [dedicated article](https://radzserg.medium.com/https-medium-com-radzserg-dependency-injection-in-react-part-2-995e93b3327c)

- Does not requires decorators
- Great types resolution
- Works great with both javascript and typescript
- Strict types resolution

@@ -66,3 +66,3 @@ ## When to use

![architecture](https://github.com/radzserg/rsdi/raw/main/docs/RSDI_architecture.jpg "RSDI Architecture")
![architecture](https://github.com/radzserg/rsdi3/raw/main/docs/RSDI_architecture.jpg "RSDI Architecture")

@@ -80,3 +80,16 @@ An application always has an entry point, whether it is a web application or a CLI application. This is the only place where you

### Simple use-case
```typescript
const container = new DIContainer()
.add("a", () => "name1")
.add("bar", () => new Bar())
.add("foo", (get) => new Foo(get("a"), get("bar")));
const foo = container.get("foo");
```
### Real life example
```typescript
// sample web application components

@@ -86,3 +99,3 @@

userRegistrator: UserRegistrator,
userRepository: UserRepository
userRepository: UserRepository,
) {

@@ -129,27 +142,21 @@ return {

```typescript
import DIContainer, { object, use, factory, func, IDIContainer } from "rsdi";
import DIContainer from "rsdi";
export type AppDIContainer = ReturnType<typeof configureDI>;
export default function configureDI() {
const container = new DIContainer();
container.add({
buildDbConnection: factory(() => {
buildDbConnection();
}),
[MyDbProviderUserRepository.name]: func(
MyDbProviderUserRepository,
use(buildDbConnection)
),
[UserRegistrator.name]: object(UserRegistrator).construct(
use(MyDbProviderUserRepository.name)
),
[UserController.name]: func(
UserController,
use(UserRegistrator.name),
use(MyDbProviderUserRepository.name)
),
});
return container;
return new DIContainer()
.add("dbConnection", buildDbConnection())
.add("userRepository", (get) =>
MyDbProviderUserRepository(get("dbConnection")),
)
.add("userRegistrator", (get) => new UserRegistrator(get("userRepository")))
.add("userController", (get) =>
UserController(get("userRepository"), get("userRegistrator")),
);
}
```
`container.get` - return type based on declaration.
**All resolvers are resolved only once and their result persists over the life of the container.**

@@ -163,5 +170,5 @@

app: core.Express,
diContainer: IDIContainer
diContainer: AppDIContainer,
) {
const usersController = diContainer.get(UsersController);
const usersController = diContainer.get("UsersController");
app

@@ -190,219 +197,8 @@ .route("/users")

## Dependency Resolvers
### Raw values resolver
## Strict types
Dependencies are set as raw values. Container keeps and return raw values.
`rsdi` offers strong type-safety due to its native TypeScript support. It leverages TypeScript's type system to provide
compile-time checks and ensure proper injection of dependencies.
```typescript
import DIContainer from "rsdi";
const container = new DIContainer();
container.add({
ENV: "PRODUCTION",
HTTP_PORT: 3000,
storage: new CookieStorage(),
});
const env: string = container.get("ENV");
const port: number = container.get("HTTP_PORT");
const authStorage: AuthStorage = container.get(AuthStorage); // instance of AuthStorage
```
### Object resolver
`object(ClassName)` - constructs an instance of the given class. The simplest scenario it calls the class constructor `new ClassName()`.
When you need to pass arguments to the constructor, you can use `construct` method. You can refer to the already defined
dependencies via the `use` helper, or you can pass raw values.
If you need to call object method after initialization you can use `method` it will be called after constructor.
```typescript
class ControllerContainer {
constructor(authStorage: AuthStorage, logger: Logger) {}
add(controller: Controller) {
this.controllers.push(controller);
}
}
// container
const container = new DIContainer();
container.add({
Storage: object(CookieStorage), // constructor without arguments
AuthStorage: object(AuthStorage).construct(
use(Storage) // refers to existing dependency
),
UsersController: object(UserController),
PostsController: object(PostsController),
ControllerContainer: object(MainCliCommand)
.construct(use(AuthStorage), new Logger()) // use existing dependency, or pass raw values
.method("add", use(UsersController)) // call class method after initialization
.method("add", use(PostsController)),
});
```
### Function resolver
Function resolver allows declaring lazy functions. Function will be called when it's actually needed.
```typescript
function UsersRepoFactory(knex: Knex): UsersRepo {
return {
async findById(id: number) {
await knex("users").where({ id });
},
};
}
const container = new DIContainer();
container.add({
DBConnection: knex(/* ... */),
UsersRepoFactory: func(UsersRepoFactory, use("DBConnection")),
});
const userRepo = container.get(UsersRepoFactory);
```
### Factory resolver
Factory resolver is similar to a Function resolver. You can use factory resolver when you need more flexibility
during initialization. `container: IDIContainer` will be passed in as an argument to the factory method. You can
resolve other dependencies inside the factory function and have conditions inside of it.
```typescript
const container = new DIContainer();
container.add({
BrowserHistory: factory(configureHistory),
});
function configureHistory(container: IDIContainer): History {
const history = createBrowserHistory();
const env = container.get("ENV");
if (env === "production") {
// do what you need
}
return history;
}
const history = container.get("BrowserHistory");
```
## Typescript type resolution
`container.get` - return type based on declaration.
```typescript
const container: DIContainer = new DIContainer();
container.add({
strVal: "raw string value",
numberVal: 123,
boolVal: true,
objectVal: object(Buzz), // resolvers to object of class Buzz
dateVal: func(function () {
return new Date(); // resolves to ReturnType of the function
}),
});
const strVal = container.get("strVal"); // strVal: string
const numberVal = container.get("numberVal"); // numberVal: number
const boolVal = container.get("boolVal"); // boolVal: boolean
const objectVal = container.get("objectVal"); // boolVal: Buzz
const dateVal = container.get("dateVal"); // dateVal: Date
```
`contrainer.use` - allows to reference declared dependency with respect to types.
```typescript
export class Foo {
constructor(name: string, bar: Bar) {}
}
const container: DIContainer = new DIContainer();
container.add({
bar: new ObjectResolver(Bar),
key1: new RawValueResolver("value1"),
// `bar` dependency cannot be referenced in the same `add` call
// Argument of type 'string' is not assignable to parameter of type... '
// foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
container.add({
foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
```
To support lazy loading `construct` method changes original Foo constructor to expect
`(string | ReferenceResolver<string>, Bar | ReferenceResolver<Bar>)`.
`container.use("bar")` - will return object `ReferenceResolver<Bar>` to respect safe types.
`use` helper
```typescript
import { use } from "rsdi";
```
`use` helper is less strict version of `container.use`. It allows to reference dependencies that **will be defined** relying
on convention over configuration rule.
- if given name is a class - instance of the class
- if given name is a function - return type of the function
- if custom type is provided - return ReferenceResolver<Custom>
- otherwise - any
```typescript
class Foo {
constructor(private readonly bar: Bar) {}
}
function returnBoolean() {
return true;
}
const container: DIContainer = new DIContainer();
container.add({
Bar: new Bar(),
Foo: object(Foo).construct(use(Bar)), // resolves Bar
expectBoolFunc: func(function (a: boolean) {
return null;
}, use(returnBoolean)), // resolves to ReturnType of returnBoolean function
expectDateFunc: func(function (a: Date) {
return null;
}, use<Date>("date")), // resolves to Date
expectDateFunc2: func(function (a: Date) {
return null;
}, use("date")), // resolves to any
});
```
## Dependency declaration
**Use string names**
```typescript
const container: DIContainer = new DIContainer();
container.add({
bar: new ObjectResolver(Bar),
key1: new RawValueResolver("value1"),
});
container.add({
foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
```
Use function and class names by declaring them as `[MyClass.name]`. In this case, it is safe to rename functions and
classes in the IDE. IDE will identify all usages and rename them in the container as well. You can declare all dependencies
in a single `add` method and use `use` helper to reference other dependencies.
```typescript
container.add({
[Foo.name]: new Foo(),
[MyFactory.name]: MyFactory(),
[Foo.name]: object(Foo).construct(use(Bar)),
});
const foo = container.get(Foo);
const buzz = container.get(MyFactory);
```
![strict type](https://github.com/radzserg/rsdi3/raw/main/docs/RSDI_types.png "RSDI types")
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc