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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: CI
on:
on:
push:
branches-ignore: [release]

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
Expand Down
5 changes: 4 additions & 1 deletion cspell.words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ pg_dumpall
PGPASSWORD
psql
esnext
SEPA
SEPA
hsts
nosniff
csrf
2,856 changes: 1,678 additions & 1,178 deletions package-lock.json

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zibri",
"version": "2.3.0",
"version": "2.4.0",
"main": "./dist/cjs/index.js",
"types": "./dist/cjs/index.d.ts",
"module": "./dist/esm/index.mjs",
Expand Down Expand Up @@ -49,58 +49,60 @@
"license": "MIT",
"description": "TS Backend Framework",
"peerDependencies": {
"axios": "^1.13.2",
"bcryptjs": "^3.0.2",
"bignumber.js": "^9.3.1",
"handlebars": "^4.7.8",
"axios": "^1.15.0",
"bcryptjs": "^3.0.3",
"bignumber.js": "^10.0.2",
"handlebars": "^4.7.9",
"hi-base32": "^0.5.1",
"jsonwebtoken": "^9.0.2",
"otpauth": "^9.4.1",
"jsonwebtoken": "^9.0.3",
"otpauth": "^9.5.0",
"pdfmake": "^0.2.2",
"preact": "^10.28.3",
"preact-render-to-string": "^6.6.5",
"preact": "^10.29.1",
"preact-render-to-string": "^6.6.7",
"rxjs": "^7.8.2",
"socket.io": "^4.8.1",
"socket.io": "^4.8.3",
"ts-node": "^10.9.2",
"uuid": "^11.1.0",
"xmlbuilder2": "^4.0.3"
"xmlbuilder2": "^4.0.3",
"cookie-parser": "^1.4.7"
},
"dependencies": {
"@fastify/busboy": "^3.2.0",
"cors": "^2.8.5",
"express": "^5.1.0",
"cors": "^2.8.6",
"express": "^5.2.1",
"glob": "^13.0.6",
"node-cron": "^4.2.1",
"nodemailer": "^8.0.4",
"pg": "^8.16.3",
"nodemailer": "^8.0.5",
"pg": "^8.20.0",
"prom-client": "^15.1.3",
"reflect-metadata": "^0.2.2",
"swagger-ui-express": "^5.0.1",
"swagger2openapi": "^7.0.8",
"systeminformation": "^5.27.10",
"typeorm": "^0.3.27"
"systeminformation": "^5.31.5",
"typeorm": "^0.3.28"
},
"devDependencies": {
"@faker-js/faker": "^9.9.0",
"@jest/globals": "^30.2.0",
"@swc/core": "^1.13.5",
"@testcontainers/postgresql": "^11.6.0",
"@jest/globals": "^30.3.0",
"@swc/core": "^1.15.24",
"@testcontainers/postgresql": "^11.14.0",
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/express": "^5.0.6",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.10.13",
"@types/nodemailer": "^7.0.1",
"@types/node": "^25.6.0",
"@types/nodemailer": "^8.0.0",
"@types/pdfmake": "^0.2.11",
"@types/swagger-ui-express": "^4.1.8",
"@types/swagger2openapi": "^7.0.4",
"eslint": "^9.36.0",
"eslint-config-service-soft": "^2.1.6",
"jest": "^30.2.0",
"jest": "^30.3.0",
"npm-run-all": "^4.1.5",
"openapi3-ts": "^4.5.0",
"testcontainers": "^11.6.0",
"ts-jest": "^29.4.6",
"typedoc": "^0.28.17",
"typescript": "^5.9.3"
"testcontainers": "^11.14.0",
"ts-jest": "^29.4.9",
"typedoc": "^0.28.19",
"typescript": "^5.9.2"
}
}
13 changes: 2 additions & 11 deletions sandbox/assets/public/vendor/manifest.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
{
"MetricsPage": [
"chart.js"
],
"NetworkChart": [
"chart.js"
],
"RequestDurationChart": [
"chart.js"
],
"RequestsPerSecondChart": [
"Chart": [
"chart.js"
],
"ResourceUsageChart": [
"MetricsPage": [
"chart.js"
],
"SocketIoTestPage": [
Expand Down
15 changes: 12 additions & 3 deletions sandbox/src/controllers/metrics.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Controller, Inject, ZIBRI_DI_TOKENS, Metric, Get, Response, MetricsSnapshot, MetricsServiceInterface, HtmlResponse, PreactUtilities, GlobalRegistry } from 'zibri';
import { Controller, Inject, ZIBRI_DI_TOKENS, Metric, Get, Response, MetricsSnapshot, MetricsServiceInterface, HtmlResponse, PreactUtilities, GlobalRegistry, CacheServiceInterface, Cached } from 'zibri';

import { StaticPagesCache } from './page.controller';
import { MetricsPage } from '../templates/pages/metrics';

@Controller('/metrics')
export class MetricsController {
constructor(
@Inject(ZIBRI_DI_TOKENS.METRICS_SERVICE)
private readonly metricsService: MetricsServiceInterface
private readonly metricsService: MetricsServiceInterface,
@Inject(ZIBRI_DI_TOKENS.CACHE_SERVICE)
private readonly cacheService: CacheServiceInterface
) {}

@Response.array(Metric)
Expand All @@ -15,10 +18,16 @@ export class MetricsController {
return this.metricsService.getMetricSnapshots();
}

@Cached(StaticPagesCache, () => 'dashboard')
@Response.html()
@Get('/dashboard')
async dashboard(): Promise<HtmlResponse> {
const version: string = GlobalRegistry.getAppData('version') ?? '-';
return await PreactUtilities.renderResponse(MetricsPage, { version, primary: '#0e456f', secondary: '#00b4d8' });
const cacheNames: string[] = this.cacheService.caches.map(c => c.name);
const html: string = await PreactUtilities.renderPage(
MetricsPage,
{ version, cacheNames, primary: '#0e456f', secondary: '#00b4d8' }
);
return HtmlResponse.fromString(html);
}
}
24 changes: 21 additions & 3 deletions sandbox/src/controllers/page.controller.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import { AssetServiceInterface, Controller, Get, GlobalRegistry, HtmlResponse, inject, PreactUtilities, Response, TreeNode, ZIBRI_DI_TOKENS } from 'zibri';
import { AssetServiceInterface, Cache, Cached, CacheServiceInterface, Controller, Get, GlobalRegistry, HtmlResponse, Inject, inject, InMemoryCacheStore, LoggerInterface, MetricsServiceInterface, PreactUtilities, Response, TreeNode, WriteThroughReadThroughCache, ZIBRI_DI_TOKENS } from 'zibri';

import { AssetsPage } from '../templates/pages/assets';
import { HomePage } from '../templates/pages/home';

@Cache()
export class StaticPagesCache extends WriteThroughReadThroughCache<string, HtmlResponse, 'StaticPagesCache'> {
constructor(
@Inject(ZIBRI_DI_TOKENS.LOGGER)
protected readonly logger: LoggerInterface,
@Inject(ZIBRI_DI_TOKENS.CACHE_SERVICE)
protected readonly cacheService: CacheServiceInterface,
@Inject(ZIBRI_DI_TOKENS.METRICS_SERVICE)
protected readonly metricsService: MetricsServiceInterface
) {
super('StaticPagesCache', new InMemoryCacheStore(), []);
}
}

@Controller('/')
export class PageController {

@Cached(StaticPagesCache, () => 'index')
@Response.html()
@Get()
async index(): Promise<HtmlResponse> {
return await PreactUtilities.renderResponse(HomePage, { appName: GlobalRegistry.getAppData('name') ?? '' });
const html: string = await PreactUtilities.renderPage(HomePage, { appName: GlobalRegistry.getAppData('name') ?? '' });
return HtmlResponse.fromString(html);
}

@Cached(StaticPagesCache, () => 'assets')
@Response.html()
@Get('/assets')
async assets(): Promise<HtmlResponse> {
const assetService: AssetServiceInterface = inject(ZIBRI_DI_TOKENS.ASSET_SERVICE);
const nodes: TreeNode[] = await assetService.buildFileTree();
return PreactUtilities.renderResponse(AssetsPage, { nodes });
const html: string = await PreactUtilities.renderPage(AssetsPage, { nodes });
return HtmlResponse.fromString(html);
}
}
7 changes: 4 additions & 3 deletions sandbox/src/controllers/template.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export class TemplateController {
@Response.html()
@Get('/socket')
async socketIo(): Promise<HtmlResponse> {
return await PreactUtilities.renderResponse(SocketIoTestPage, { primary: '#0e456f', secondary: '#00b4d8' });
const html: string = await PreactUtilities.renderPage(SocketIoTestPage, { primary: '#0e456f', secondary: '#00b4d8' });
return HtmlResponse.fromString(html);
}

@Response.html()
Expand Down Expand Up @@ -47,15 +48,15 @@ export class TemplateController {
cleanupAt: new Date(),
level: logLevel,
message: 'test 42',
error: errorToLoggedError(new Error('Something Failed')),
context: {
origin,
request: {
method: HttpMethod.GET,
url: 'http://localhost:3000/templates/log',
clientIp: '123.456.789.10',
userAgent: 'Mozilla/Firefox'
}
},
error: errorToLoggedError(new Error('Something Failed'))
}
};

Expand Down
5 changes: 3 additions & 2 deletions sandbox/src/create-default-data.function.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DataSourceInterface, HashUtilities, inject, JwtCredentials, JwtCredentialsCreateData, Newable, Repository, repositoryTokenFor, Transaction } from 'zibri';
import { DataSourceInterface, HashServiceInterface, inject, JwtCredentials, JwtCredentialsCreateData, Newable, Repository, repositoryTokenFor, Transaction, ZIBRI_DI_TOKENS } from 'zibri';

import { logger } from '.';
import { Roles, User } from './models';
Expand All @@ -15,6 +15,7 @@ export async function createDefaultData(dataSourceClass: Newable<DataSourceInter
async function createDefaultAdmin(dataSource: DataSourceInterface): Promise<void> {
const userRepository: UserRepository = inject(UserRepository);
const credentialsRepository: Repository<JwtCredentials, JwtCredentialsCreateData> = inject(repositoryTokenFor(JwtCredentials));
const hashService: HashServiceInterface = inject(ZIBRI_DI_TOKENS.HASH_SERVICE);

const defaultUser: User | undefined = await userRepository.findOne({ where: { email: 'admin@test.com' } }, false);
if (defaultUser) {
Expand All @@ -26,7 +27,7 @@ async function createDefaultAdmin(dataSource: DataSourceInterface): Promise<void
try {
const user: User = await userRepository.create({ name: 'root', email: 'admin@test.com', roles: [Roles.ADMIN] }, { transaction });
await credentialsRepository.create(
{ email: user.email, password: await HashUtilities.hash('password'), userId: user.id },
{ email: user.email, password: await hashService.hash('password'), userId: user.id },
{ transaction }
);
await transaction.commit();
Expand Down
4 changes: 2 additions & 2 deletions sandbox/src/cron/status.cron-job.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { CronJob, inject, LoggerInterface, ZIBRI_DI_TOKENS, InitialCronConfig } from 'zibri';
import { CronJob, inject, LoggerInterface, ZIBRI_DI_TOKENS, InitialCronConfig, CronExpression } from 'zibri';

export class StatusCronJob extends CronJob {
readonly initialConfig: InitialCronConfig = {
name: 'Status',
cron: '* * * * * *',
cron: CronExpression.every(1, 'seconds').build(),
active: false
};

Expand Down
9 changes: 7 additions & 2 deletions sandbox/src/data-sources/db/db.data-source.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PostgresDataSource, PostgresOptions, BaseEntity, DataSource, Newable, MigrationEntity, JwtRefreshToken, JwtCredentials, PasswordResetToken, MailingList, MailingListSubscriber, MailingListSubscriptionConfirmationToken, Log, Change, ChangeSet, Entity, OmitClass, OtpCredentials, BackupResourceEntity, BackupEntity, Invoice, NumberInvoices, Email, CronJobEntity, ThreadJobEntity, WebsocketChannel, WebsocketMessage } from 'zibri';
import { PostgresDataSource, PostgresOptions, BaseEntity, DataSource, Newable, MigrationEntity, JwtRefreshToken, JwtCredentials, PasswordResetToken, MailingList, MailingListSubscriber, MailingListSubscriptionConfirmationToken, Log, Change, ChangeSet, Entity, OmitClass, OtpCredentials, BackupResourceEntity, BackupEntity, Invoice, NumberInvoices, Email, CronJobEntity, ThreadJobEntity, WebsocketChannel, WebsocketMessage, Event, EventSubscriberRun, HashStrategyEntity, EncryptionStrategyEntity, EncryptionKey } from 'zibri';

import { Company, Test, User } from '../../models';

Expand Down Expand Up @@ -42,6 +42,11 @@ export class DbDataSource extends PostgresDataSource {
CronJobEntity,
ThreadJobEntity,
WebsocketChannel,
WebsocketMessage
WebsocketMessage,
Event,
EventSubscriberRun,
HashStrategyEntity,
EncryptionStrategyEntity,
EncryptionKey
];
}
2 changes: 1 addition & 1 deletion sandbox/src/models/test.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BaseEntity, Entity, File, MimeType, OmitClass, PartialClass, Property }

@Entity()
export class Test extends BaseEntity {
@Property.string({ minLength: 28 })
@Property.string({ minLength: 28, encryption: true })
value!: string;
}

Expand Down
16 changes: 13 additions & 3 deletions sandbox/src/providers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineProvider, DiProvider, LoggerTransport, LogLevel, ZIBRI_DI_TOKENS, ZIBRI_INVOICING_PLUGIN_DI_TOKENS, ZIBRI_MAILING_LIST_PLUGIN_DI_TOKENS } from 'zibri';
import { AesGcmEncryptionStrategy, defineProvider, DiProvider, LoggerTransport, LogLevel, ZIBRI_DI_TOKENS, ZIBRI_INVOICING_PLUGIN_DI_TOKENS, ZIBRI_MAILING_LIST_PLUGIN_DI_TOKENS } from 'zibri';

import { MailingListBaseEmail } from './templates/email-components/mailing-list-base-email';
import { MailingListSubscribeConfirmationEmail } from './templates/emails/mailing-list-subscribe-confirmation';
Expand All @@ -18,7 +18,17 @@ export const providers: DiProvider<unknown>[] = [
useFactory: () => [LoggerTransport.console(LogLevel.INFO)]
}),
defineProvider({
token: ZIBRI_DI_TOKENS.JWT_PASSWORD_RESET_EMAIL_TEMPLATE,
token: ZIBRI_DI_TOKENS.ENCRYPTION_MASTER_OPTIONS,
useValue: {
currentMasterStrategy: new AesGcmEncryptionStrategy(),
currentMasterKey: {
id: 'k1',
value: '42'
}
}
}),
defineProvider({
token: ZIBRI_DI_TOKENS.PASSWORD_RESET_EMAIL_TEMPLATE,
useFactory: () => PasswordResetEmail
}),
defineProvider({
Expand All @@ -45,7 +55,7 @@ export const providers: DiProvider<unknown>[] = [
}
}),
defineProvider({
token: ZIBRI_DI_TOKENS.JWT_CONFIRM_PASSWORD_RESET_URL,
token: ZIBRI_DI_TOKENS.CONFIRM_PASSWORD_RESET_URL,
useFactory: () => 'http://localhost:4200/confirm-password-reset'
}),
defineProvider({
Expand Down
4 changes: 2 additions & 2 deletions sandbox/src/repositories/user.repository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Inject, inject, InjectRepository, JwtCredentials, LoggerInterface, Repository, repositoryTokenFor, UserRepo, UserRepositoryInterface, ZIBRI_DI_TOKENS } from 'zibri';
import { getDefaultBeforeReturnHook, getDefaultBeforeSaveHook, Inject, inject, InjectRepository, JwtCredentials, LoggerInterface, Repository, repositoryTokenFor, UserRepo, UserRepositoryInterface, ZIBRI_DI_TOKENS } from 'zibri';

import { Roles, User, UserCreateData } from '../models';

Expand All @@ -12,7 +12,7 @@ export class UserRepository extends Repository<User, UserCreateData>
@Inject(ZIBRI_DI_TOKENS.LOGGER)
logger: LoggerInterface
) {
super(User, repo, logger);
super(User, repo, logger, repo.dataSource, getDefaultBeforeSaveHook(), getDefaultBeforeReturnHook());
}

async findByEmail(email: string): Promise<User> {
Expand Down
Loading
Loading