added redis provider and queueService

This commit is contained in:
rykuno 2024-06-30 10:12:55 -05:00
parent 4055dcbcf7
commit 6390f8e19a
9 changed files with 182 additions and 25 deletions

View file

@ -6,7 +6,7 @@ If you forked this repository before May 27th, you'll want to view commit `653e2
## ❔ What
A scalable, testable, extensible, template for Sveltekit.
A scalable, testable, extensible, template for Sveltekit.
Sveltekit is awesome, but sometimes you need a bit more capability in the backend than what frameworks like
NextJS & Sveltekit can deliver.
@ -25,25 +25,35 @@ export const DELETE: RequestHandler = ({ request }) => app.fetch(request);
export const POST: RequestHandler = ({ request }) => app.fetch(request);
```
## Local Setup
1. Make sure Docker is running
2. Copy the `.env.example` file and rename to `.env`
3. `pnpm install`
4. `pnpm initialize`(this will start the docker-compose and run the initial database migration.)
5. `pnpm dev`
No additional setup is required, zero api keys, zero services to signup for, zero cost.
## How to Use
This is **not** supposed to serve as an all batteries included ["production boilerplate"](https://github.com/ixartz/Next-js-Boilerplate) with 200 useless sponsored features that get in your way. Templates that do this are ANYTHING but "production" and "quick start".
This is **not** supposed to serve as an all batteries included ["production boilerplate"](https://github.com/ixartz/Next-js-Boilerplate) with 200 useless sponsored features that get in your way. Templates that do this are ANYTHING but "production" and "quick start".
This is stack is designed to be library agnostic. The philosophy here is to boostrap the concrete, repetitive, and time consuming tasks that every application will need reguardless of what you're building.
**So - fork this repo, add your favorite libraries, and build out your own "more opinionated" personal template tailored to you**!
**So - fork this repo, add your favorite libraries, and build out your own "more opinionated" personal template tailored to you**!
## Features
- 🟢 Full E2E typesafety
- 🟢 RPC Client for API Requests
- 🟢 Custom Fetch Wrapper
- 🔴 Deployment Template
- 🟢 Deployment Template
- 🟠 Authentication
- 🟢 Email/Passkey
- 🔴 OAuth
- 🟢 Email Update/Verifiaction
- 🔴 Rate limiter
- 🟢 Rate limiter
## Technologies

View file

@ -36,6 +36,7 @@
"@typescript-eslint/parser": "^7.13.1",
"arctic": "^1.9.1",
"autoprefixer": "^10.4.19",
"bullmq": "^5.8.3",
"dayjs": "^1.11.11",
"dotenv-cli": "^7.4.2",
"drizzle-kit": "^0.21.4",

View file

@ -105,6 +105,9 @@ importers:
autoprefixer:
specifier: ^10.4.19
version: 10.4.19(postcss@8.4.38)
bullmq:
specifier: ^5.8.3
version: 5.8.3
dayjs:
specifier: ^1.11.11
version: 1.11.11
@ -764,6 +767,36 @@ packages:
peerDependencies:
svelte: '>=3 <5'
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
cpu: [arm64]
os: [darwin]
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==}
cpu: [x64]
os: [darwin]
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==}
cpu: [arm64]
os: [linux]
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==}
cpu: [arm]
os: [linux]
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==}
cpu: [x64]
os: [linux]
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==}
cpu: [x64]
os: [win32]
'@napi-rs/wasm-runtime@0.2.4':
resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==}
@ -1507,6 +1540,9 @@ packages:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
bullmq@5.8.3:
resolution: {integrity: sha512-RJgQu/vgSZqjOYrZ7F1UJsSAzveNx7FFpR3Tp/1TxOMXXN9TtZMSly5MT+vjzOhQX//3+YWNRbMWpC1mkqBc9w==}
bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
@ -1612,6 +1648,10 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
cron-parser@4.9.0:
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
engines: {node: '>=12.0.0'}
cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -1689,6 +1729,10 @@ packages:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
devalue@5.0.0:
resolution: {integrity: sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA==}
@ -2442,6 +2486,10 @@ packages:
peerDependencies:
svelte: ^3 || ^4 || ^5.0.0-next.42
luxon@3.4.4:
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
engines: {node: '>=12'}
magic-string@0.30.10:
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
@ -2552,6 +2600,13 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
msgpackr-extract@3.0.3:
resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==}
hasBin: true
msgpackr@1.10.2:
resolution: {integrity: sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==}
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
@ -2583,6 +2638,13 @@ packages:
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-abort-controller@3.1.1:
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
node-gyp-build-optional-packages@5.2.2:
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
hasBin: true
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
@ -3461,6 +3523,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
uuid@9.0.1:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
valibot@0.31.1:
resolution: {integrity: sha512-2YYIhPrnVSz/gfT2/iXVTrSj92HwchCt9Cga/6hX4B26iCz9zkIsGTS0HjDYTZfTi1Un0X6aRvhBi1cfqs/i0Q==}
@ -4006,6 +4072,24 @@ snapshots:
nanoid: 5.0.7
svelte: 5.0.0-next.164
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
optional: true
'@napi-rs/wasm-runtime@0.2.4':
dependencies:
'@emnapi/core': 1.2.0
@ -4729,6 +4813,18 @@ snapshots:
builtin-modules@3.3.0: {}
bullmq@5.8.3:
dependencies:
cron-parser: 4.9.0
ioredis: 5.4.1
msgpackr: 1.10.2
node-abort-controller: 3.1.1
semver: 7.6.2
tslib: 2.6.3
uuid: 9.0.1
transitivePeerDependencies:
- supports-color
bytes@3.1.2: {}
cac@6.7.14: {}
@ -4832,6 +4928,10 @@ snapshots:
cookie@0.6.0: {}
cron-parser@4.9.0:
dependencies:
luxon: 3.4.4
cross-spawn@7.0.3:
dependencies:
path-key: 3.1.1
@ -4883,6 +4983,9 @@ snapshots:
detect-indent@6.1.0: {}
detect-libc@2.0.3:
optional: true
devalue@5.0.0: {}
didyoumean@1.2.2: {}
@ -5729,6 +5832,8 @@ snapshots:
dependencies:
svelte: 5.0.0-next.164
luxon@3.4.4: {}
magic-string@0.30.10:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
@ -5828,6 +5933,22 @@ snapshots:
ms@2.1.3: {}
msgpackr-extract@3.0.3:
dependencies:
node-gyp-build-optional-packages: 5.2.2
optionalDependencies:
'@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3
'@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3
'@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3
optional: true
msgpackr@1.10.2:
optionalDependencies:
msgpackr-extract: 3.0.3
mz@2.7.0:
dependencies:
any-promise: 1.3.0
@ -5848,6 +5969,13 @@ snapshots:
next-tick@1.1.0: {}
node-abort-controller@3.1.1: {}
node-gyp-build-optional-packages@5.2.2:
dependencies:
detect-libc: 2.0.3
optional: true
node-releases@2.0.14: {}
nodemailer@6.9.14: {}
@ -6673,6 +6801,8 @@ snapshots:
utils-merge@1.0.1: {}
uuid@9.0.1: {}
valibot@0.31.1:
optional: true

View file

@ -19,6 +19,6 @@ ensure that the correct data is being passed around.
/* -------------------------------------------------------------------------- */
export const updateEmailDto = z.object({
email: z.string()
email: z.string().email()
});
export type UpdateEmailDto = z.infer<typeof updateEmailDto>;

View file

@ -1,2 +1,3 @@
export * from './database.provider';
export * from './lucia.provider';
export * from './redis.provider';

View file

@ -0,0 +1,14 @@
import { container } from 'tsyringe';
import RedisClient from 'ioredis'
import { config } from '../common/config';
// Symbol
export const RedisProvider = Symbol('REDIS_TOKEN');
// Type
export type RedisProvider = RedisClient;
// Register
container.register<RedisProvider>(RedisProvider, {
useValue: new RedisClient(config.REDIS_URL)
});

View file

@ -0,0 +1,19 @@
import { injectable } from "tsyringe";
import RedisClient from 'ioredis'
import { config } from "../common/config";
import { Queue, Worker, type Processor } from 'bullmq';
@injectable()
export class QueuesServices {
connection = new RedisClient(config.REDIS_URL);
constructor() { }
createQueue(name: string) {
return new Queue(name, { connection: this.connection })
}
createWorker(name: string, prcoessor: Processor) {
return new Worker(name, prcoessor, { connection: this.connection })
}
}

View file

@ -3,24 +3,6 @@ import { generateRandomString } from "oslo/crypto";
import { TimeSpan, createDate, type TimeSpanUnit } from 'oslo';
import { HashingService } from './hashing.service';
/* -------------------------------------------------------------------------- */
/* Service */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* ---------------------------------- About --------------------------------- */
/*
Services are responsible for handling business logic and data manipulation.
They genreally call on repositories or other services to complete a use-case.
*/
/* ---------------------------------- Notes --------------------------------- */
/*
Services should be kept as clean and simple as possible.
Create private functions to handle complex logic and keep the public methods as
simple as possible. This makes the service easier to read, test and understand.
*/
/* -------------------------------------------------------------------------- */
@injectable()
export class TokensService {
constructor(@inject(HashingService) private readonly hashingService: HashingService) { }

View file

@ -1,6 +1,6 @@
import 'reflect-metadata';
import { LoginRequestsService } from '../services/login-requests.service';
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
import { TokensService } from '../services/tokens.service';
import { MailerService } from '../services/mailer.service';
import { UsersRepository } from '../repositories/users.repository';