Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Contributing to Zibri
Thank you for considering to contribute to this project!

It is open for discussion to change anything regarding contributing, linting, workflow etc. at any point in time.

All development is done using github.

# Table of Contents
- [Contributing to Zibri](#contributing-to-zibri)
- [Table of Contents](#table-of-contents)
- [Create an issue](#create-an-issue)
- [Special Notes for bugs](#special-notes-for-bugs)
- [License](#license)

# Create an issue
If you want to ask a question, need a new feature, found gaps in the documentation, found a bug, found code that can be refactored etc. you first have to start with creating an Issue.

Please check if there already is an issue for your problem.

Right now there are no specific guidelines for Issues, other than that their name and description should include enough details so that everyone knows what the issue is about.

## Special Notes for bugs
Great Bug Reports tend to have:

- A quick summary
- Steps to reproduce (be specific and try to give sample code if possible)
- What you expected would happen
- What actually happens
- Additional info (eg. why you think this might be happening, or workarounds you tried that did/did not work)

# License
By contributing to this project, you agree that your contributions will be licensed under its MIT License.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ Zibri aims to be an ***actual*** batteries included framework.
Meaning if you need something like an email service it's already there.

And, in contrast to most other node backend frameworks:<br>
Such a service is not just the most basic implementation, but one with built in templating, queuing support for thousands of mails, the option to save mails in the database, priority handling etc.
Such a service is not just the most basic implementation, but one with built in templating, queuing support for thousands of mails, the option to save mails in a data source, priority handling etc.

Due to it's dependency injection system you can always swap things out if they are not required or you need even more configuration options. But there will most likely always be a reasonable default you can rely on.

### 🧩 Features
- default jwt auth strategy with advanced features like automatic reuse detection
- builtin ORM with transaction and migration support
- controller based route definition
- controller based route definition, including websocket controllers
- OmitClass, PickClass, PartialClass, IntersectionClass helpers to extend from and easily build new entity or even controller classes
- automatic open api generation
- body parsers for json and form-data
Expand All @@ -37,7 +37,8 @@ Due to it's dependency injection system you can always swap things out if they a
- email service out of the box, with templating, mail queue, persistence and priority handling
- multithreading service with builtin support for worker files or function
- change sets and soft delete functionality
-
- backup architecture builtin
- a http client for speaking to external APIs that actually validates responses

## ✨ Ease of use
Zibri aims to be as easy to use as possible, with reasonable defaults and by the use of decorators and dependency injection.
Expand All @@ -55,17 +56,19 @@ With Zibri you can rely on a strong foundation of battle tested libraries that h
- nodemailer for sending emails
- handlebars for templating
- busboy for file uploads (the foundation of multer)
- socket.io for websockets
- node-cron for cron jobs

### 🪖 Making "shooting your foot" as hard as possible
All the public facing classes, interfaces and functions are as strictly typed as possible. Zibri even includes a custom parser for handlebar files, that automtically infer the type of the data that is needed to render the template.
All the public facing classes, interfaces and functions are as strictly typed as possible. Zibri even includes a custom parser for handlebar files, that automtically infers the type of the data that is needed to render the template.

In addition to that, you will get warnings whenever there is something off, like an endpoint that is marked to skip auth, although that is not required.
In addition to that, you will get warnings whenever there is something off. Like an endpoint that is marked to skip auth, although there isn't anything auth related to skip for it.

Fixing these warnings will keep your code base cleaner and less prone to errors in the future.

### 🛟 Making "shooting your foot" the most pleasant experience
Zibri gives you useful errors, stack traces and debug logs.

It includes source maps and handles even complex cases like giving you the specifics on why a dependency injection failed.
It includes source maps and handles even complex cases like giving you the specifics on *why* a dependency injection failed.

In a lot of cases it also directly gives you a possible fix.
Binary file added docs/assets-explorer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Assets
Zibri offers a simple way to serve static files:

Anything you put under your projects assets folder will served under `/assets/{asset-name-with-file-ending}` (With the default configuration).

For documentation purposes there is also a simple "file explorer" page provided by Zibri under `/assets` when not specifying an asset, that can also be reached from the root page:

![Zibri's builtin assets file explorer](./assets-explorer.png)
6 changes: 4 additions & 2 deletions docs/authentication-and-authorization.md → docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Each strategy comes with all the required functionality built in to
- check if that logged in user belongs to a specific entity
- functionality for resetting a password

You can register an auth strategy by defining it on the application options. By default the builtin
You can register an auth strategy by defining it on the application options. By default the builtin JwtAuthStrategy is used.

However, you will probably never use these strategies directly, as Zibri provides an AuthService that automatically manages these strategies in the background for you:

Expand All @@ -29,6 +29,7 @@ Another crucial part of the auth system are users. They need to contain at least
Zibri provides a helper class you can easily extend from:

```ts
// src/models/user.model.ts
import { Entity, Property, BaseUserEntity } from 'zibri';

import { Company } from './company.model';
Expand All @@ -40,9 +41,10 @@ export class User extends BaseUserEntity(Roles) {
}
```

For the builtin user service you now also need to register a user repository, so that a user can be found by email over multiple database tables (used eg. by the default JwtAuthStrategy):
For the builtin user service you now also need to register a user repository, so that a user can be found by email over multiple data source entities (used eg. by the default JwtAuthStrategy):

```ts
// src/repositories/user.repository.ts
import { inject, InjectRepository, JwtCredentials, Repository, repositoryTokenFor, UserRepo, UserRepositoryInterface } from 'zibri';

import { Roles, User, UserCreateData } from '../models';
Expand Down
74 changes: 74 additions & 0 deletions docs/backup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Backup
The backup system in Zibri consists of multiple parts:

### One or more backup resources
These define WHAT should be backed up and need to be marked with the `@BackupResource` decorator.

A decorated resource needs to implement `BackupResourceInterface` to define how data should be extracted from the resource (eg. by running a sql dump) and read back in.

### One or more backup transports defined for each resource
These define how extracted data from the resource is saved and how to retrive it when restoring a backup.

For more detail on those, especially if you are interested in creating your own transport, see [backup transports](./generated/interfaces/backup_transports_backup-transport.interface.BackupTransportInterface.html).

### The backup service
The backup service is responsible for creating and restoring backups based on the configured resources and transports.

## Example
In the following, we have a postgres data source that we want to backup:

```ts
// src/data-sources/db/db.data-source.ts
import { DataSource, Backup, FsBackupTransport, PostgresDataSource, PostgresOptions, BaseEntity, BackupEntity, BackupResourceEntity } from 'zibri';

@DataSource()
@Backup({
transports: [
new FsBackupTransport(
'fs-backup-transport',
'./backups'
)
]
})
class DbDataSource extends PostgresDataSource {
rootPw: string = 'password';
rootUsername: string = 'postgres';
options: PostgresOptions = {
host: 'localhost',
username: 'postgres',
password: 'password',
database: 'db',
synchronize: true
};
entities: Newable<BaseEntity>[] = [
BackupEntity,
BackupResourceEntity
//...
];
}
```

Notice that we don't need to implement `BackupResourceInterface` here, as `PostgresDataSource` already does that for us. What we did need to do was add two new entities and the root credentials. But you will get speaking error messages telling you exactly what is missing.

The `FsBackupTransport` simply writes the backup data for this resource to the local file system, so it should only be used for illustration/testing purposes.

Now we can use the backup service to create a new backup:

```ts
import { BackupServiceInterface, inject, ZIBRI_DI_TOKENS } from 'zibri';
// ...
const backupService: BackupServiceInterface = inject(ZIBRI_DI_TOKENS.BACKUP_SERVICE);
await backupService.createBackup();
// ...
```

Which you can later restore using:

```ts
import { BackupServiceInterface, inject, ZIBRI_DI_TOKENS, repositoryTokenFor, BackupEntity } from 'zibri';
// ...
const backupRepository = inject(repositoryTokenFor(BackupEntity));
const backup: BackupEntity = await backupRepository.findById('42', { relations: ['resources'] });
await backupService.restore(backup);
// ...
```
Loading
Loading