exisjs 0.5.9 → 0.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.ts +3 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +4 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/oauth/core.d.ts +96 -0
- package/dist/auth/oauth/core.d.ts.map +1 -0
- package/dist/auth/oauth/core.js +203 -0
- package/dist/auth/oauth/core.js.map +1 -0
- package/dist/auth/oauth/index.d.ts +45 -0
- package/dist/auth/oauth/index.d.ts.map +1 -0
- package/dist/auth/oauth/index.js +64 -0
- package/dist/auth/oauth/index.js.map +1 -0
- package/dist/auth/oauth/middleware.d.ts +63 -0
- package/dist/auth/oauth/middleware.d.ts.map +1 -0
- package/dist/auth/oauth/middleware.js +164 -0
- package/dist/auth/oauth/middleware.js.map +1 -0
- package/dist/auth/oauth/providers/custom.d.ts +41 -0
- package/dist/auth/oauth/providers/custom.d.ts.map +1 -0
- package/dist/auth/oauth/providers/custom.js +204 -0
- package/dist/auth/oauth/providers/custom.js.map +1 -0
- package/dist/auth/oauth/providers/discord.d.ts +23 -0
- package/dist/auth/oauth/providers/discord.d.ts.map +1 -0
- package/dist/auth/oauth/providers/discord.js +130 -0
- package/dist/auth/oauth/providers/discord.js.map +1 -0
- package/dist/auth/oauth/providers/facebook.d.ts +28 -0
- package/dist/auth/oauth/providers/facebook.d.ts.map +1 -0
- package/dist/auth/oauth/providers/facebook.js +124 -0
- package/dist/auth/oauth/providers/facebook.js.map +1 -0
- package/dist/auth/oauth/providers/github.d.ts +25 -0
- package/dist/auth/oauth/providers/github.d.ts.map +1 -0
- package/dist/auth/oauth/providers/github.js +132 -0
- package/dist/auth/oauth/providers/github.js.map +1 -0
- package/dist/auth/oauth/providers/google.d.ts +23 -0
- package/dist/auth/oauth/providers/google.d.ts.map +1 -0
- package/dist/auth/oauth/providers/google.js +134 -0
- package/dist/auth/oauth/providers/google.js.map +1 -0
- package/dist/auth/oauth/providers/microsoft.d.ts +28 -0
- package/dist/auth/oauth/providers/microsoft.d.ts.map +1 -0
- package/dist/auth/oauth/providers/microsoft.js +136 -0
- package/dist/auth/oauth/providers/microsoft.js.map +1 -0
- package/dist/auth/oauth/types.d.ts +158 -0
- package/dist/auth/oauth/types.d.ts.map +1 -0
- package/dist/auth/oauth/types.js +4 -0
- package/dist/auth/oauth/types.js.map +1 -0
- package/dist/auth/session.d.ts +4 -1
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/auth/session.js +33 -5
- package/dist/auth/session.js.map +1 -1
- package/dist/cache/store.d.ts +11 -3
- package/dist/cache/store.d.ts.map +1 -1
- package/dist/cache/store.js +87 -19
- package/dist/cache/store.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +4 -6
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/database/adapters/mongodb.d.ts +58 -0
- package/dist/database/adapters/mongodb.d.ts.map +1 -0
- package/dist/database/adapters/mongodb.js +264 -0
- package/dist/database/adapters/mongodb.js.map +1 -0
- package/dist/database/adapters/mysql.d.ts +27 -0
- package/dist/database/adapters/mysql.d.ts.map +1 -0
- package/dist/database/adapters/mysql.js +188 -0
- package/dist/database/adapters/mysql.js.map +1 -0
- package/dist/database/adapters/postgres.d.ts +28 -0
- package/dist/database/adapters/postgres.d.ts.map +1 -0
- package/dist/database/adapters/postgres.js +174 -0
- package/dist/database/adapters/postgres.js.map +1 -0
- package/dist/database/adapters/sqlite.d.ts +27 -0
- package/dist/database/adapters/sqlite.d.ts.map +1 -0
- package/dist/database/adapters/sqlite.js +149 -0
- package/dist/database/adapters/sqlite.js.map +1 -0
- package/dist/database/index.d.ts +42 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +58 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/manager.d.ts +114 -0
- package/dist/database/manager.d.ts.map +1 -0
- package/dist/database/manager.js +269 -0
- package/dist/database/manager.js.map +1 -0
- package/dist/database/migration.d.ts +57 -0
- package/dist/database/migration.d.ts.map +1 -0
- package/dist/database/migration.js +329 -0
- package/dist/database/migration.js.map +1 -0
- package/dist/database/query-builder.d.ts +89 -0
- package/dist/database/query-builder.d.ts.map +1 -0
- package/dist/database/query-builder.js +353 -0
- package/dist/database/query-builder.js.map +1 -0
- package/dist/database/types.d.ts +184 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +4 -0
- package/dist/database/types.js.map +1 -0
- package/dist/docs/ARCHITECTURE.md +349 -0
- package/dist/docs/BENCHMARKS.md +36 -0
- package/dist/docs/README.md +34 -0
- package/dist/docs/content/README.md +44 -0
- package/dist/docs/content/adapters.mdx +199 -0
- package/dist/docs/content/cache.mdx +239 -0
- package/dist/docs/content/circuit-breaker.mdx +130 -0
- package/dist/docs/content/cli/commands.mdx +214 -0
- package/dist/docs/content/cli/overview.mdx +92 -0
- package/dist/docs/content/cli/usage.mdx +61 -0
- package/dist/docs/content/config.mdx +214 -0
- package/dist/docs/content/controllers.mdx +241 -0
- package/dist/docs/content/cron.mdx +109 -0
- package/dist/docs/content/database.mdx +209 -0
- package/dist/docs/content/dataloader.mdx +170 -0
- package/dist/docs/content/decorators.mdx +204 -0
- package/dist/docs/content/errors.mdx +344 -0
- package/dist/docs/content/gateways.mdx +376 -0
- package/dist/docs/content/installation.mdx +210 -0
- package/dist/docs/content/introduction.mdx +96 -0
- package/dist/docs/content/middleware.mdx +441 -0
- package/dist/docs/content/modules.mdx +144 -0
- package/dist/docs/content/oauth.mdx +179 -0
- package/dist/docs/content/providers.mdx +147 -0
- package/dist/docs/content/queues.mdx +177 -0
- package/dist/docs/content/requests.mdx +293 -0
- package/dist/docs/content/responses.mdx +271 -0
- package/dist/docs/content/routing.mdx +541 -0
- package/dist/docs/content/rpc.mdx +146 -0
- package/dist/docs/content/security.mdx +294 -0
- package/dist/docs/content/sse.mdx +159 -0
- package/dist/docs/content/structure.mdx +116 -0
- package/dist/docs/content/testing.mdx +139 -0
- package/dist/docs/content/validation.mdx +249 -0
- package/dist/docs/content/websockets.mdx +289 -0
- package/dist/docs/integrations/README.md +23 -0
- package/dist/docs/integrations/jwt.mdx +151 -0
- package/dist/docs/integrations/mongo.mdx +183 -0
- package/dist/docs/integrations/observability.mdx +125 -0
- package/dist/docs/integrations/openai.mdx +108 -0
- package/dist/docs/integrations/postgres.mdx +190 -0
- package/dist/docs/integrations/posthog.mdx +122 -0
- package/dist/docs/integrations/redis.mdx +141 -0
- package/dist/docs/integrations/resend.mdx +117 -0
- package/dist/docs/integrations/s3.mdx +122 -0
- package/dist/docs/integrations/swagger.mdx +113 -0
- package/dist/docs/reference/README.md +3 -0
- package/dist/docs/reference/adapters.mdx +130 -0
- package/dist/docs/reference/auth.mdx +183 -0
- package/dist/docs/reference/cache.mdx +132 -0
- package/dist/docs/reference/circuit-breaker.mdx +71 -0
- package/dist/docs/reference/config.mdx +118 -0
- package/dist/docs/reference/context.mdx +168 -0
- package/dist/docs/reference/dataloader.mdx +91 -0
- package/dist/docs/reference/decorators.mdx +293 -0
- package/dist/docs/reference/di.mdx +123 -0
- package/dist/docs/reference/error.mdx +170 -0
- package/dist/docs/reference/exis.mdx +124 -0
- package/dist/docs/reference/middleware.mdx +304 -0
- package/dist/docs/reference/plugin.mdx +113 -0
- package/dist/docs/reference/queue.mdx +155 -0
- package/dist/docs/reference/router.mdx +248 -0
- package/dist/docs/reference/sanitize.mdx +130 -0
- package/dist/docs/reference/storage.mdx +116 -0
- package/dist/docs/reference/swagger.mdx +132 -0
- package/dist/docs/reference/testing.mdx +145 -0
- package/dist/docs/reference/validator.mdx +186 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/backpressure.d.ts.map +1 -1
- package/dist/middleware/backpressure.js +21 -12
- package/dist/middleware/backpressure.js.map +1 -1
- package/dist/middleware/cache.d.ts +6 -0
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +84 -28
- package/dist/middleware/cache.js.map +1 -1
- package/dist/middleware/idempotency.d.ts +4 -1
- package/dist/middleware/idempotency.d.ts.map +1 -1
- package/dist/middleware/idempotency.js +29 -4
- package/dist/middleware/idempotency.js.map +1 -1
- package/dist/middleware/ip-filter.d.ts.map +1 -1
- package/dist/middleware/ip-filter.js +16 -0
- package/dist/middleware/ip-filter.js.map +1 -1
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +29 -12
- package/dist/middleware/rate-limit.js.map +1 -1
- package/dist/queue/drivers/MemoryDriver.d.ts +6 -3
- package/dist/queue/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/queue/drivers/MemoryDriver.js +76 -23
- package/dist/queue/drivers/MemoryDriver.js.map +1 -1
- package/dist/server/bootstrapper.d.ts +3 -0
- package/dist/server/bootstrapper.d.ts.map +1 -1
- package/dist/server/bootstrapper.js +56 -8
- package/dist/server/bootstrapper.js.map +1 -1
- package/dist/server/bun-adapter.d.ts +2 -0
- package/dist/server/bun-adapter.d.ts.map +1 -1
- package/dist/server/bun-adapter.js +23 -12
- package/dist/server/bun-adapter.js.map +1 -1
- package/dist/server/request-handler.d.ts +0 -2
- package/dist/server/request-handler.d.ts.map +1 -1
- package/dist/server/request-handler.js +2 -24
- package/dist/server/request-handler.js.map +1 -1
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/request.js +24 -11
- package/dist/server/request.js.map +1 -1
- package/dist/server/uws-adapter.d.ts +80 -0
- package/dist/server/uws-adapter.d.ts.map +1 -0
- package/dist/server/uws-adapter.js +357 -0
- package/dist/server/uws-adapter.js.map +1 -0
- package/dist/server/ws-orchestrator.d.ts +1 -0
- package/dist/server/ws-orchestrator.d.ts.map +1 -1
- package/dist/server/ws-orchestrator.js +83 -0
- package/dist/server/ws-orchestrator.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/validator/tex.d.ts +21 -16
- package/dist/validator/tex.d.ts.map +1 -1
- package/dist/validator/tex.js.map +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextUrl: "/docs/integrations/mongo"
|
|
3
|
+
nextTitle: "Database (NoSQL)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Database (SQL)
|
|
7
|
+
|
|
8
|
+
ExisJS provides native integrations for SQL databases and ORMs in the Node.js ecosystem. Instead of writing boilerplate connection logic, ExisJS manages your connection pools using the `DATABASE_URL` environment variable.
|
|
9
|
+
|
|
10
|
+
Because these plugins manage their own state, you do **NOT** need to register them in your `server.ts` file. They lazily initialize their connection pools when you first query them.
|
|
11
|
+
|
|
12
|
+
The framework provides first-class plugins for **Drizzle ORM**, **Prisma**, and raw **PostgreSQL** (`postgres.js`).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Environment Variables
|
|
17
|
+
|
|
18
|
+
All SQL plugins securely read your connection string from your `.env` file.
|
|
19
|
+
Before using any of the plugins below, ensure you have your Postgres connection string set:
|
|
20
|
+
|
|
21
|
+
```bash filename=".env"
|
|
22
|
+
# Your PostgreSQL connection string
|
|
23
|
+
DATABASE_URL="postgres://user:password@localhost:5432/my_database"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. Drizzle ORM (Recommended)
|
|
29
|
+
|
|
30
|
+
[Drizzle ORM](https://orm.drizzle.team/) is the recommended database solution for ExisJS. It provides type safety and performance.
|
|
31
|
+
|
|
32
|
+
### Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install drizzle-orm postgres
|
|
36
|
+
npm install -D drizzle-kit
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Usage
|
|
40
|
+
|
|
41
|
+
Simply define your schema and call the native `drizzle()` integration helper. ExisJS will initialize a `postgres.js` connection pool using your `DATABASE_URL` environment variable.
|
|
42
|
+
|
|
43
|
+
```typescript filename="src/db/index.ts"
|
|
44
|
+
import { drizzle } from 'exisjs/drizzle'
|
|
45
|
+
import { pgTable, serial, text, varchar } from 'drizzle-orm/pg-core'
|
|
46
|
+
|
|
47
|
+
// 1. Define your schema
|
|
48
|
+
export const users = pgTable('users', {
|
|
49
|
+
id: serial('id').primaryKey(),
|
|
50
|
+
fullName: text('full_name'),
|
|
51
|
+
phone: varchar('phone', { length: 256 }),
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const schema = { users }
|
|
55
|
+
|
|
56
|
+
// 2. Initialize the client
|
|
57
|
+
// ExisJS automatically reads process.env.DATABASE_URL
|
|
58
|
+
export const db = drizzle(schema)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Now you can use `db` in your routes:
|
|
62
|
+
|
|
63
|
+
#### Functional Paradigm
|
|
64
|
+
|
|
65
|
+
```typescript filename="src/http/users/route.ts"
|
|
66
|
+
import { controller, route } from 'exisjs/router'
|
|
67
|
+
import { db, users } from '../../db'
|
|
68
|
+
|
|
69
|
+
export default controller({
|
|
70
|
+
listUsers: route.get('/', {
|
|
71
|
+
async handle() {
|
|
72
|
+
return await db.select().from(users)
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Class-Based (OOP) Paradigm
|
|
79
|
+
|
|
80
|
+
```typescript filename="src/http/users/route.ts"
|
|
81
|
+
import { Controller, Get } from 'exisjs/decorators'
|
|
82
|
+
import { db, users } from '../../db'
|
|
83
|
+
|
|
84
|
+
@Controller()
|
|
85
|
+
export default class UsersController {
|
|
86
|
+
@Get('/')
|
|
87
|
+
async listUsers() {
|
|
88
|
+
return await db.select().from(users)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 2. Prisma ORM
|
|
96
|
+
|
|
97
|
+
If you prefer a schema-first approach, ExisJS includes a wrapper for Prisma.
|
|
98
|
+
|
|
99
|
+
### Installation
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install @prisma/client
|
|
103
|
+
npm install -D prisma
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Initialize your schema:
|
|
107
|
+
```bash
|
|
108
|
+
npx prisma init
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Usage
|
|
112
|
+
|
|
113
|
+
Use the native `prisma()` helper to instantiate a singleton `PrismaClient` that manages the connection.
|
|
114
|
+
|
|
115
|
+
```typescript filename="src/db/index.ts"
|
|
116
|
+
import { prisma } from 'exisjs/prisma'
|
|
117
|
+
|
|
118
|
+
// Singleton initialization
|
|
119
|
+
export const db = prisma()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 3. Raw PostgreSQL (`postgres.js`)
|
|
125
|
+
|
|
126
|
+
If you don't want to use an ORM and prefer writing raw SQL, ExisJS provides an integration for the `postgres.js` driver.
|
|
127
|
+
|
|
128
|
+
### Installation
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm install postgres
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Usage
|
|
135
|
+
|
|
136
|
+
Import the tagged template literal `sql` from `exisjs/postgres`. The first time you use it, ExisJS will boot up a connection pool using `DATABASE_URL`.
|
|
137
|
+
|
|
138
|
+
#### Functional Paradigm
|
|
139
|
+
|
|
140
|
+
```typescript filename="src/http/users/route.ts"
|
|
141
|
+
import { controller, route } from 'exisjs/router'
|
|
142
|
+
import { sql } from 'exisjs/postgres'
|
|
143
|
+
|
|
144
|
+
export default controller({
|
|
145
|
+
getUser: route.get('/:id', {
|
|
146
|
+
async handle(req) {
|
|
147
|
+
// Write raw SQL with native parameterization.
|
|
148
|
+
const users = await sql`SELECT * FROM users WHERE id = ${req.params.id}`
|
|
149
|
+
return users[0]
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Class-Based (OOP) Paradigm
|
|
156
|
+
|
|
157
|
+
```typescript filename="src/http/users/route.ts"
|
|
158
|
+
import { Controller, Get, Param } from 'exisjs/decorators'
|
|
159
|
+
import { sql } from 'exisjs/postgres'
|
|
160
|
+
|
|
161
|
+
@Controller()
|
|
162
|
+
export default class UsersController {
|
|
163
|
+
@Get('/:id')
|
|
164
|
+
async getUser(@Param('id') id: string) {
|
|
165
|
+
// Write raw SQL with native parameterization!
|
|
166
|
+
const users = await sql`SELECT * FROM users WHERE id = ${id}`
|
|
167
|
+
return users[0]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Customizing Connection Options
|
|
173
|
+
|
|
174
|
+
If you need to pass custom options to the Postgres connection pool (like SSL config or max pool sizes), call `configurePostgres(options)` before you run your first query (e.g. inside your `server.ts` `onStart` hook).
|
|
175
|
+
|
|
176
|
+
```typescript filename="src/http/server.ts"
|
|
177
|
+
import { exis } from 'exisjs'
|
|
178
|
+
import { configurePostgres } from 'exisjs/postgres'
|
|
179
|
+
|
|
180
|
+
export default exis({
|
|
181
|
+
async onStart() {
|
|
182
|
+
// Initialize with custom connection limits
|
|
183
|
+
configurePostgres({
|
|
184
|
+
max: 20,
|
|
185
|
+
idle_timeout: 30000,
|
|
186
|
+
ssl: process.env.NODE_ENV === 'production' ? 'require' : false
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
```
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextUrl: "/docs/integrations/observability"
|
|
3
|
+
nextTitle: "Observability"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PostHog Integration
|
|
7
|
+
|
|
8
|
+
ExisJS provides an integration for PostHog, an open-source product analytics platform.
|
|
9
|
+
|
|
10
|
+
This enables you to capture server-side events, identify users, and evaluate feature flags directly inside your route handlers.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Environment Variables
|
|
15
|
+
|
|
16
|
+
The PostHog plugin securely reads your project API key directly from your `.env` file.
|
|
17
|
+
|
|
18
|
+
Before using the plugin, ensure you have your API key set. You can optionally define a custom host if you are self-hosting PostHog (it defaults to `https://app.posthog.com`).
|
|
19
|
+
|
|
20
|
+
```bash filename=".env"
|
|
21
|
+
POSTHOG_API_KEY="phc_123456789"
|
|
22
|
+
POSTHOG_HOST="https://eu.posthog.com" # Optional (For EU Cloud or Self-Hosted)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
ExisJS wraps the official `posthog-node` SDK as an optional peer dependency.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install posthog-node
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
Simply import the `posthog` proxy from `exisjs/posthog`. ExisJS will boot the client behind the scenes the first time you track an event.
|
|
40
|
+
|
|
41
|
+
#### Functional Paradigm
|
|
42
|
+
|
|
43
|
+
```typescript filename="src/http/auth/route.ts"
|
|
44
|
+
import { controller, route } from 'exisjs/router'
|
|
45
|
+
import { posthog } from 'exisjs/posthog'
|
|
46
|
+
|
|
47
|
+
export default controller({
|
|
48
|
+
login: route.post('/login', {
|
|
49
|
+
async handle(req) {
|
|
50
|
+
const { email, userId } = req.body
|
|
51
|
+
|
|
52
|
+
// Your auth logic here...
|
|
53
|
+
|
|
54
|
+
// The posthog client lazy-loads here
|
|
55
|
+
posthog.identify({
|
|
56
|
+
distinctId: userId,
|
|
57
|
+
properties: { email }
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
posthog.capture({
|
|
61
|
+
distinctId: userId,
|
|
62
|
+
event: 'user_logged_in'
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return { success: true }
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Class-Based (OOP) Paradigm
|
|
72
|
+
|
|
73
|
+
```typescript filename="src/http/auth/route.ts"
|
|
74
|
+
import { Controller, Post, Body } from 'exisjs/decorators'
|
|
75
|
+
import { posthog } from 'exisjs/posthog'
|
|
76
|
+
|
|
77
|
+
@Controller('/auth')
|
|
78
|
+
export default class AuthController {
|
|
79
|
+
|
|
80
|
+
@Post('/login')
|
|
81
|
+
async login(@Body() body: any) {
|
|
82
|
+
const { email, userId } = body
|
|
83
|
+
|
|
84
|
+
// Your auth logic here...
|
|
85
|
+
|
|
86
|
+
// The posthog client lazy-loads here
|
|
87
|
+
posthog.identify({
|
|
88
|
+
distinctId: userId,
|
|
89
|
+
properties: { email }
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
posthog.capture({
|
|
93
|
+
distinctId: userId,
|
|
94
|
+
event: 'user_logged_in'
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return { success: true }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Graceful Shutdown (Flushing)
|
|
105
|
+
|
|
106
|
+
PostHog queues events in memory and sends them in batches for high performance.
|
|
107
|
+
|
|
108
|
+
When your application shuts down, you must ensure all pending events are successfully flushed to PostHog before the Node.js process exits so you don't lose analytics data.
|
|
109
|
+
|
|
110
|
+
Simply await `posthog.shutdown()` in your `onStop` hook.
|
|
111
|
+
|
|
112
|
+
```typescript filename="src/http/server.ts"
|
|
113
|
+
import { exis } from 'exisjs'
|
|
114
|
+
import { posthog } from 'exisjs/posthog'
|
|
115
|
+
|
|
116
|
+
export default exis({
|
|
117
|
+
async onStop() {
|
|
118
|
+
// Ensures all pending events are flushed before the server exits
|
|
119
|
+
await posthog.shutdown()
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextUrl: "/docs/integrations/jwt"
|
|
3
|
+
nextTitle: "JWT Auth"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Redis Integration
|
|
7
|
+
|
|
8
|
+
ExisJS provides an integration for Redis via the `ioredis` package. You do **NOT** need to register Redis in your `server.ts` file. The connection pool is lazily initialized when you execute your first command.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Environment Variables
|
|
13
|
+
|
|
14
|
+
The Redis plugin securely reads your connection string from your `.env` file. It automatically looks for either `REDIS_URL` or `KV_URL` (compatible with Vercel KV).
|
|
15
|
+
|
|
16
|
+
Before using the plugin, ensure you have your Redis URI set:
|
|
17
|
+
|
|
18
|
+
```bash filename=".env"
|
|
19
|
+
# Your Redis connection string
|
|
20
|
+
REDIS_URL="redis://default:password@localhost:6379"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
ExisJS wraps the `ioredis` client.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install ioredis
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Import the `redis` proxy from `exisjs/redis`. ExisJS will connect to your Redis instance behind the scenes.
|
|
38
|
+
|
|
39
|
+
#### Functional Paradigm
|
|
40
|
+
|
|
41
|
+
```typescript filename="src/http/cache/route.ts"
|
|
42
|
+
import { controller, route } from 'exisjs/router'
|
|
43
|
+
import { redis } from 'exisjs/redis'
|
|
44
|
+
|
|
45
|
+
export default controller({
|
|
46
|
+
getCache: route.get('/:key', {
|
|
47
|
+
async handle(req) {
|
|
48
|
+
const value = await redis.get(req.params.key)
|
|
49
|
+
return { key: req.params.key, value }
|
|
50
|
+
}
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
setCache: route.post('/:key', {
|
|
54
|
+
async handle(req) {
|
|
55
|
+
// Set key with an expiration of 60 seconds
|
|
56
|
+
await redis.set(req.params.key, JSON.stringify(req.body), 'EX', 60)
|
|
57
|
+
return { success: true }
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Class-Based (OOP) Paradigm
|
|
64
|
+
|
|
65
|
+
```typescript filename="src/http/cache/route.ts"
|
|
66
|
+
import { Controller, Get, Post, Param, Body } from 'exisjs/decorators'
|
|
67
|
+
import { redis } from 'exisjs/redis'
|
|
68
|
+
|
|
69
|
+
@Controller('/cache')
|
|
70
|
+
export default class CacheController {
|
|
71
|
+
@Get('/:key')
|
|
72
|
+
async getCache(@Param('key') key: string) {
|
|
73
|
+
const value = await redis.get(key)
|
|
74
|
+
return { key, value }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@Post('/:key')
|
|
78
|
+
async setCache(@Param('key') key: string, @Body() body: any) {
|
|
79
|
+
// Set key with an expiration of 60 seconds
|
|
80
|
+
await redis.set(key, JSON.stringify(body), 'EX', 60)
|
|
81
|
+
return { success: true }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Redis as a Job Queue
|
|
89
|
+
|
|
90
|
+
ExisJS's native distributed Job Queue can run on top of Redis. This is a common approach for production environments to process background jobs across multiple server instances.
|
|
91
|
+
|
|
92
|
+
To enable the Redis queue driver, configure it either in `server.ts` or centrally in your `exis.config.ts` file:
|
|
93
|
+
|
|
94
|
+
### `exis.config.ts`
|
|
95
|
+
|
|
96
|
+
```typescript filename="exis.config.ts"
|
|
97
|
+
import { defineConfig } from 'exisjs/config'
|
|
98
|
+
|
|
99
|
+
export default defineConfig({
|
|
100
|
+
queue: {
|
|
101
|
+
driver: 'redis',
|
|
102
|
+
// ExisJS will automatically use process.env.REDIS_URL.
|
|
103
|
+
// If you need a custom URL just for the queue, you can specify it:
|
|
104
|
+
// redisUrl: process.env.CUSTOM_QUEUE_REDIS_URL
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `src/http/server.ts`
|
|
110
|
+
|
|
111
|
+
```typescript filename="src/http/server.ts"
|
|
112
|
+
import { exis } from 'exisjs'
|
|
113
|
+
|
|
114
|
+
export default exis({
|
|
115
|
+
queue: {
|
|
116
|
+
driver: 'redis',
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Customizing Connection Options
|
|
124
|
+
|
|
125
|
+
If you need to pass custom options to the Redis connection pool (like custom retry strategies, lazy connections, or TLS settings), call `configureRedis(options)` inside your `server.ts` `onStart` hook.
|
|
126
|
+
|
|
127
|
+
```typescript filename="src/http/server.ts"
|
|
128
|
+
import { exis } from 'exisjs'
|
|
129
|
+
import { configureRedis } from 'exisjs/redis'
|
|
130
|
+
|
|
131
|
+
export default exis({
|
|
132
|
+
async onStart() {
|
|
133
|
+
// Initialize with custom connection options
|
|
134
|
+
configureRedis({
|
|
135
|
+
maxRetriesPerRequest: 3,
|
|
136
|
+
connectTimeout: 10000,
|
|
137
|
+
lazyConnect: true
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextUrl: "/docs/integrations/openai"
|
|
3
|
+
nextTitle: "OpenAI"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Resend (Email) Integration
|
|
7
|
+
|
|
8
|
+
ExisJS provides an integration for Resend to send emails.
|
|
9
|
+
|
|
10
|
+
Just like all our other integrations, ExisJS treats the `resend` SDK as an optional dependency. You only install it if you need it, keeping your core application lightweight.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Environment Variables
|
|
15
|
+
|
|
16
|
+
The Resend plugin securely reads your API key directly from your `.env` file.
|
|
17
|
+
|
|
18
|
+
Before using the plugin, ensure you have your API key set:
|
|
19
|
+
|
|
20
|
+
```bash filename=".env"
|
|
21
|
+
RESEND_API_KEY="re_123456789"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
ExisJS wraps the official `resend` Node.js SDK.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install resend
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
Simply import the `resend` proxy from `exisjs/resend`. ExisJS will boot the client behind the scenes the first time you attempt to send an email.
|
|
39
|
+
|
|
40
|
+
#### Functional Paradigm
|
|
41
|
+
|
|
42
|
+
```typescript filename="src/http/emails/route.ts"
|
|
43
|
+
import { controller, route } from 'exisjs/router'
|
|
44
|
+
import { resend } from 'exisjs/resend'
|
|
45
|
+
|
|
46
|
+
export default controller({
|
|
47
|
+
sendWelcomeEmail: route.post('/welcome', {
|
|
48
|
+
async handle(req) {
|
|
49
|
+
const { email, name } = req.body
|
|
50
|
+
|
|
51
|
+
// The resend client lazy-loads here
|
|
52
|
+
const { data, error } = await resend.emails.send({
|
|
53
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
54
|
+
to: [email],
|
|
55
|
+
subject: 'Welcome to Acme!',
|
|
56
|
+
html: `<strong>Hello ${name}, welcome aboard!</strong>`
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if (error) {
|
|
60
|
+
return { success: false, error }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { success: true, data }
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Class-Based (OOP) Paradigm
|
|
70
|
+
|
|
71
|
+
```typescript filename="src/http/emails/route.ts"
|
|
72
|
+
import { Controller, Post, Body } from 'exisjs/decorators'
|
|
73
|
+
import { resend } from 'exisjs/resend'
|
|
74
|
+
|
|
75
|
+
@Controller('/emails')
|
|
76
|
+
export default class EmailsController {
|
|
77
|
+
|
|
78
|
+
@Post('/welcome')
|
|
79
|
+
async sendWelcomeEmail(@Body() body: any) {
|
|
80
|
+
// The resend client magically lazy-loads here!
|
|
81
|
+
const { data, error } = await resend.emails.send({
|
|
82
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
83
|
+
to: [body.email],
|
|
84
|
+
subject: 'Welcome to Acme!',
|
|
85
|
+
html: `<strong>Hello ${body.name}, welcome aboard!</strong>`
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (error) {
|
|
89
|
+
return { success: false, error }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { success: true, data }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Customizing Connection Options
|
|
100
|
+
|
|
101
|
+
If you need to pass custom options to the Resend Client, call `configureResend(options)` inside your `server.ts` `onStart` hook.
|
|
102
|
+
|
|
103
|
+
```typescript filename="src/http/server.ts"
|
|
104
|
+
import { exis } from 'exisjs'
|
|
105
|
+
import { configureResend } from 'exisjs/resend'
|
|
106
|
+
|
|
107
|
+
export default exis({
|
|
108
|
+
async onStart() {
|
|
109
|
+
// Inject custom fetch options or headers
|
|
110
|
+
configureResend({
|
|
111
|
+
headers: {
|
|
112
|
+
'X-Custom-Header': 'ExisJS'
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
```
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextUrl: "/docs/integrations/resend"
|
|
3
|
+
nextTitle: "Resend"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AWS S3 Integration
|
|
7
|
+
|
|
8
|
+
ExisJS provides an integration for AWS S3 via the official `@aws-sdk/client-s3` package.
|
|
9
|
+
|
|
10
|
+
You do **NOT** need to write boilerplate to initialize the AWS SDK. The S3 client is lazily initialized when you execute your first `PutObject` or `GetObject` command.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Environment Variables
|
|
15
|
+
|
|
16
|
+
The AWS S3 plugin securely reads your credentials directly from your `.env` file using the industry-standard AWS variable names.
|
|
17
|
+
|
|
18
|
+
Before using the plugin, ensure you have your credentials set:
|
|
19
|
+
|
|
20
|
+
```bash filename=".env"
|
|
21
|
+
AWS_ACCESS_KEY_ID="your_access_key"
|
|
22
|
+
AWS_SECRET_ACCESS_KEY="your_secret_key"
|
|
23
|
+
AWS_REGION="us-east-1"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
ExisJS wraps the `@aws-sdk/client-s3` library.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @aws-sdk/client-s3
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Simply import the `s3` proxy from `exisjs/s3` and use standard AWS SDK commands. ExisJS will boot the client behind the scenes.
|
|
41
|
+
|
|
42
|
+
#### Functional Paradigm
|
|
43
|
+
|
|
44
|
+
```typescript filename="src/http/uploads/route.ts"
|
|
45
|
+
import { controller, route } from 'exisjs/router'
|
|
46
|
+
import { s3 } from 'exisjs/s3'
|
|
47
|
+
import { PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3'
|
|
48
|
+
|
|
49
|
+
export default controller({
|
|
50
|
+
// ExisJS parses multipart/form-data when you access req.files
|
|
51
|
+
uploadFile: route.post('/', {
|
|
52
|
+
async handle(req) {
|
|
53
|
+
// req.files is automatically populated natively by ExisJS
|
|
54
|
+
const file = req.files[0]
|
|
55
|
+
|
|
56
|
+
const command = new PutObjectCommand({
|
|
57
|
+
Bucket: 'my-exis-bucket',
|
|
58
|
+
Key: file.filename,
|
|
59
|
+
Body: file.data, // Buffer
|
|
60
|
+
ContentType: file.mimetype,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// The s3 client lazy-loads here
|
|
64
|
+
await s3.send(command)
|
|
65
|
+
|
|
66
|
+
return { success: true, url: `https://my-exis-bucket.s3.amazonaws.com/${file.filename}` }
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Class-Based (OOP) Paradigm
|
|
73
|
+
|
|
74
|
+
```typescript filename="src/http/uploads/route.ts"
|
|
75
|
+
import { Controller, Post, UploadedFile, type ExisFile } from 'exisjs/decorators'
|
|
76
|
+
import { s3 } from 'exisjs/s3'
|
|
77
|
+
import { PutObjectCommand } from '@aws-sdk/client-s3'
|
|
78
|
+
|
|
79
|
+
@Controller('/uploads')
|
|
80
|
+
export default class UploadsController {
|
|
81
|
+
|
|
82
|
+
@Post('/')
|
|
83
|
+
async uploadFile(@UploadedFile('avatar') file: ExisFile) {
|
|
84
|
+
const command = new PutObjectCommand({
|
|
85
|
+
Bucket: 'my-exis-bucket',
|
|
86
|
+
Key: file.filename,
|
|
87
|
+
Body: file.data, // Buffer
|
|
88
|
+
ContentType: file.mimetype,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// The s3 client magically lazy-loads here!
|
|
92
|
+
await s3.send(command)
|
|
93
|
+
|
|
94
|
+
return { success: true, url: `https://my-exis-bucket.s3.amazonaws.com/${file.filename}` }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Customizing Connection Options
|
|
102
|
+
|
|
103
|
+
If you need to pass custom options to the S3 Client (like a custom Endpoint URL for Cloudflare R2 or DigitalOcean Spaces), call `configureS3(options)` inside your `server.ts` `onStart` hook.
|
|
104
|
+
|
|
105
|
+
```typescript filename="src/http/server.ts"
|
|
106
|
+
import { exis } from 'exisjs'
|
|
107
|
+
import { configureS3 } from 'exisjs/s3'
|
|
108
|
+
|
|
109
|
+
export default exis({
|
|
110
|
+
async onStart() {
|
|
111
|
+
// Compatible with S3 APIs like Cloudflare R2
|
|
112
|
+
configureS3({
|
|
113
|
+
endpoint: 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',
|
|
114
|
+
forcePathStyle: true
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
<Hint>
|
|
121
|
+
Because ExisJS uses the official AWS SDK under the hood, the S3 integration works with Cloudflare R2, DigitalOcean Spaces, MinIO, and any other S3-compatible storage provider.
|
|
122
|
+
</Hint>
|