@lti-tool/postgresql 1.0.0 → 1.0.1
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/CHANGELOG.md +6 -0
- package/README.md +294 -0
- package/dist/cacheConfig.d.ts +11 -0
- package/dist/cacheConfig.d.ts.map +1 -0
- package/dist/cacheConfig.js +14 -0
- package/dist/db/schema/clients.schema.d.ts +133 -0
- package/dist/db/schema/clients.schema.d.ts.map +1 -0
- package/dist/db/schema/clients.schema.js +13 -0
- package/dist/db/schema/deployments.schema.d.ts +97 -0
- package/dist/db/schema/deployments.schema.d.ts.map +1 -0
- package/dist/db/schema/deployments.schema.js +14 -0
- package/dist/db/schema/index.d.ts +6 -0
- package/dist/db/schema/index.d.ts.map +1 -0
- package/dist/db/schema/index.js +5 -0
- package/dist/db/schema/nonces.schema.d.ts +44 -0
- package/dist/db/schema/nonces.schema.d.ts.map +1 -0
- package/dist/db/schema/nonces.schema.js +5 -0
- package/dist/db/schema/registrationSessions.schema.d.ts +62 -0
- package/dist/db/schema/registrationSessions.schema.d.ts.map +1 -0
- package/dist/db/schema/registrationSessions.schema.js +8 -0
- package/dist/db/schema/sessions.schema.d.ts +62 -0
- package/dist/db/schema/sessions.schema.d.ts.map +1 -0
- package/dist/db/schema/sessions.schema.js +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces/postgresStorageConfig.d.ts +35 -0
- package/dist/interfaces/postgresStorageConfig.d.ts.map +1 -0
- package/dist/interfaces/postgresStorageConfig.js +1 -0
- package/dist/postgresStorage.d.ts +53 -0
- package/dist/postgresStorage.d.ts.map +1 -0
- package/dist/postgresStorage.js +443 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# @lti-tool/postgresql
|
|
2
|
+
|
|
3
|
+
<p align="center">Production-ready PostgreSQL storage adapter for LTI 1.3. Includes caching and optimized for AWS Lambda.</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@lti-tool/postgresql"><img alt="npm" src="https://img.shields.io/npm/v/%40lti-tool%2Fpostgresql" /></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @lti-tool/postgresql
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { PostgresStorage } from '@lti-tool/postgresql';
|
|
19
|
+
import { LTITool } from '@lti-tool/core';
|
|
20
|
+
|
|
21
|
+
const storage = new PostgresStorage({
|
|
22
|
+
connectionUrl: process.env.DATABASE_URL!,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const ltiTool = new LTITool({
|
|
26
|
+
storage,
|
|
27
|
+
// ... other config
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Production Ready** - Handles high-scale LTI deployments
|
|
34
|
+
- **Built-in Caching** - LRU cache for frequently accessed data
|
|
35
|
+
- **Type-safe** - Uses Drizzle ORM for database operations
|
|
36
|
+
- **Transaction Support** - Handles data integrity on deletes
|
|
37
|
+
- **Tuned Connection Pool Defaults** - Connection pool defaults based on hosting environment
|
|
38
|
+
|
|
39
|
+
## API Reference
|
|
40
|
+
|
|
41
|
+
- [API Reference](https://docs.lti-tool.dev/modules/_lti-tool_postgresql.html) - Complete API documentation
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
### Using Drizzle Kit Push (Recommended for Development)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Set your DATABASE_URL
|
|
49
|
+
export DATABASE_URL="postgresql://user:password@host:port/database"
|
|
50
|
+
|
|
51
|
+
# Push schema to database
|
|
52
|
+
npx drizzle-kit push
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Using Migrations (Recommended for Production)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Apply migrations
|
|
59
|
+
npx drizzle-kit migrate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### PostgresStorageConfig
|
|
63
|
+
|
|
64
|
+
- **connectionUrl** (required): PostgreSQL connection URL
|
|
65
|
+
Format: `postgresql://user:password@host:port/database`
|
|
66
|
+
- **poolOptions** (optional): postgres.js connection options
|
|
67
|
+
- `max`: Max connections (auto: 1 for serverless, 10 for servers)
|
|
68
|
+
- `idleTimeout`: Idle timeout in seconds before connection is closed (default: 20)
|
|
69
|
+
- **nonceExpirationSeconds** (optional): Nonce TTL in seconds (default: 600)
|
|
70
|
+
|
|
71
|
+
- **logger** (optional): Pino logger for debugging
|
|
72
|
+
|
|
73
|
+
## Database Schema
|
|
74
|
+
|
|
75
|
+
The adapter uses these tables:
|
|
76
|
+
|
|
77
|
+
- **clients**: LTI platform clients
|
|
78
|
+
Unique constraint: `(iss, clientId)`
|
|
79
|
+
- **deployments**: Platform deployments (many-to-one with clients)
|
|
80
|
+
Unique constraint: `(clientId, deploymentId)`
|
|
81
|
+
- **sessions**: LTI sessions with expiration
|
|
82
|
+
Indexed: `expiresAt`
|
|
83
|
+
- **nonces**: One-time use nonces
|
|
84
|
+
Primary key: `nonce`
|
|
85
|
+
Indexed: `expiresAt`
|
|
86
|
+
- **registration_sessions**: Dynamic registration sessions
|
|
87
|
+
Indexed: `expiresAt`
|
|
88
|
+
|
|
89
|
+
All tables use native PostgreSQL UUIDs for primary keys and include indexes for performance.
|
|
90
|
+
|
|
91
|
+
### clients
|
|
92
|
+
|
|
93
|
+
| Column | Type | Constraints | Description |
|
|
94
|
+
| ---------- | ------------ | --------------------- | ------------------------------ |
|
|
95
|
+
| `id` | UUID | PRIMARY KEY, NOT NULL | Internal UUID for the client |
|
|
96
|
+
| `name` | VARCHAR(255) | NOT NULL | Human-readable platform name |
|
|
97
|
+
| `iss` | VARCHAR(255) | NOT NULL | Issuer URL (LMS platform) |
|
|
98
|
+
| `clientId` | VARCHAR(255) | NOT NULL | LMS-provided client identifier |
|
|
99
|
+
| `authUrl` | TEXT | NOT NULL | OAuth2 authorization endpoint |
|
|
100
|
+
| `tokenUrl` | TEXT | NOT NULL | OAuth2 token endpoint |
|
|
101
|
+
| `jwksUrl` | TEXT | NOT NULL | JWKS endpoint for public keys |
|
|
102
|
+
|
|
103
|
+
**Indexes:**
|
|
104
|
+
|
|
105
|
+
- `issuer_client_idx`: `(clientId, iss)` - For fast client lookups
|
|
106
|
+
- `iss_client_id_unique`: `(iss, clientId)` - Unique constraint preventing duplicate clients
|
|
107
|
+
|
|
108
|
+
### deployments
|
|
109
|
+
|
|
110
|
+
| Column | Type | Constraints | Description |
|
|
111
|
+
| -------------- | ------------ | --------------------- | ---------------------------------- |
|
|
112
|
+
| `id` | UUID | PRIMARY KEY, NOT NULL | Internal UUID for the deployment |
|
|
113
|
+
| `deploymentId` | VARCHAR(255) | NOT NULL | LMS-provided deployment identifier |
|
|
114
|
+
| `name` | VARCHAR(255) | NULL | Optional human-readable name |
|
|
115
|
+
| `description` | TEXT | NULL | Optional description |
|
|
116
|
+
| `clientId` | UUID | NOT NULL, FOREIGN KEY | References `clients.id` |
|
|
117
|
+
|
|
118
|
+
**Indexes:**
|
|
119
|
+
|
|
120
|
+
- `deployment_id_idx`: `(deploymentId)` - For fast deployment lookups
|
|
121
|
+
- `client_deployment_unique`: `(clientId, deploymentId)` - Unique constraint per client
|
|
122
|
+
|
|
123
|
+
### sessions
|
|
124
|
+
|
|
125
|
+
| Column | Type | Constraints | Description |
|
|
126
|
+
| ----------- | ------------------------ | --------------------- | ---------------------------- |
|
|
127
|
+
| `id` | UUID | PRIMARY KEY, NOT NULL | Session UUID |
|
|
128
|
+
| `data` | JSONB | NOT NULL | Complete LTI session data |
|
|
129
|
+
| `expiresAt` | TIMESTAMP WITH TIME ZONE | NOT NULL | Session expiration timestamp |
|
|
130
|
+
|
|
131
|
+
**Indexes:**
|
|
132
|
+
|
|
133
|
+
- `sessions_expires_at_idx`: `(expiresAt)` - For cleanup queries and expiration checks
|
|
134
|
+
|
|
135
|
+
### nonces
|
|
136
|
+
|
|
137
|
+
| Column | Type | Constraints | Description |
|
|
138
|
+
| ----------- | ------------------------ | --------------------- | -------------------------- |
|
|
139
|
+
| `nonce` | VARCHAR(255) | PRIMARY KEY, NOT NULL | One-time use nonce value |
|
|
140
|
+
| `expiresAt` | TIMESTAMP WITH TIME ZONE | NOT NULL | Nonce expiration timestamp |
|
|
141
|
+
|
|
142
|
+
### registration_sessions
|
|
143
|
+
|
|
144
|
+
| Column | Type | Constraints | Description |
|
|
145
|
+
| ----------- | ------------------------ | --------------------- | --------------------------------- |
|
|
146
|
+
| `id` | UUID | PRIMARY KEY, NOT NULL | Registration session UUID |
|
|
147
|
+
| `data` | JSONB | NOT NULL | Dynamic registration session data |
|
|
148
|
+
| `expiresAt` | TIMESTAMP WITH TIME ZONE | NOT NULL | Session expiration timestamp |
|
|
149
|
+
|
|
150
|
+
**Indexes:**
|
|
151
|
+
|
|
152
|
+
- `reg_sessions_expires_at_idx`: `(expiresAt)` - For cleanup queries and expiration checks
|
|
153
|
+
|
|
154
|
+
## Connection Pool Behavior
|
|
155
|
+
|
|
156
|
+
The adapter automatically detects your deployment environment:
|
|
157
|
+
|
|
158
|
+
- **Serverless** (Lambda, Cloud Functions, Vercel, Netlify): `max: 1`
|
|
159
|
+
- **Traditional Servers** (EC2, containers, VMs): `max: 10`
|
|
160
|
+
|
|
161
|
+
### How Connection Pooling Works
|
|
162
|
+
|
|
163
|
+
- Starts with **0 connections**
|
|
164
|
+
- Creates connections **on-demand** when queries execute
|
|
165
|
+
- Reuses idle connections before creating new ones
|
|
166
|
+
- Increases to `max` based on concurrent load
|
|
167
|
+
- Closes idle connections after `idleTimeout` seconds (default: 20)
|
|
168
|
+
|
|
169
|
+
### Manual Override
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const storage = new PostgresStorage({
|
|
173
|
+
connectionUrl: process.env.DATABASE_URL!,
|
|
174
|
+
poolOptions: {
|
|
175
|
+
max: 20, // Override auto-detection
|
|
176
|
+
idleTimeout: 30, // Keep connections alive longer
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Deployment Patterns
|
|
182
|
+
|
|
183
|
+
### Long-Running Servers
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { PostgresStorage } from '@lti-tool/postgresql';
|
|
187
|
+
|
|
188
|
+
export const storage = new PostgresStorage({
|
|
189
|
+
connectionUrl: process.env.DATABASE_URL!,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Optional: Graceful shutdown
|
|
193
|
+
const shutdown = async () => {
|
|
194
|
+
await storage.close();
|
|
195
|
+
process.exit(0);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
process.on('SIGTERM', shutdown);
|
|
199
|
+
process.on('SIGINT', shutdown);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Connection Limits:**
|
|
203
|
+
|
|
204
|
+
- Low traffic: `5-10 connections`
|
|
205
|
+
- Medium traffic: `10-20 connections`
|
|
206
|
+
- High traffic: `20-50 connections`
|
|
207
|
+
- Never exceed PostgreSQL `max_connections`
|
|
208
|
+
|
|
209
|
+
### AWS Lambda / Serverless
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { PostgresStorage } from '@lti-tool/postgresql';
|
|
213
|
+
|
|
214
|
+
let storage: PostgresStorage | undefined;
|
|
215
|
+
|
|
216
|
+
export const handler = async (event) => {
|
|
217
|
+
if (!storage) {
|
|
218
|
+
storage = new PostgresStorage({
|
|
219
|
+
connectionUrl: process.env.DATABASE_URL!,
|
|
220
|
+
// Auto-detects Lambda, uses max: 1
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Use storage...
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Why `max: 1`?**
|
|
229
|
+
Lambda containers handle one request at a time. The connection is reused across warm invocations.
|
|
230
|
+
|
|
231
|
+
**Do I need `close()`?**
|
|
232
|
+
No! Lambda freezes containers efficiently. Calling `close()` destroys reusable connections.
|
|
233
|
+
|
|
234
|
+
### Edge Runtime Warning
|
|
235
|
+
|
|
236
|
+
⚠️ **Not supported!**
|
|
237
|
+
|
|
238
|
+
## Periodic Cleanup
|
|
239
|
+
|
|
240
|
+
The adapter requires periodic cleanup of expired nonces and sessions.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Example - AWS Lambda with EventBridge (every 30 minutes)
|
|
244
|
+
export const handler = async () => {
|
|
245
|
+
const result = await storage.cleanup();
|
|
246
|
+
console.log('Cleanup:', result);
|
|
247
|
+
// { noncesDeleted: 42, sessionsDeleted: 15, registrationSessionsDeleted: 3 }
|
|
248
|
+
};
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Development & Testing
|
|
252
|
+
|
|
253
|
+
### Start Local PostgreSQL
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Using Docker
|
|
257
|
+
docker-compose up -d
|
|
258
|
+
|
|
259
|
+
# Using Podman
|
|
260
|
+
podman-compose up -d
|
|
261
|
+
|
|
262
|
+
# Or Podman directly
|
|
263
|
+
podman run -d \
|
|
264
|
+
--name lti-postgres \
|
|
265
|
+
-e POSTGRES_PASSWORD=postgres \
|
|
266
|
+
-e POSTGRES_DB=lti_test \
|
|
267
|
+
-e POSTGRES_USER=lti_user \
|
|
268
|
+
-p 5432:5432 \
|
|
269
|
+
postgres:16
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Run Tests
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
DATABASE_URL="postgresql://lti_user:postgres@localhost:5432/lti_test" npm test
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Important:** Always close the pool after tests:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
afterAll(async () => {
|
|
282
|
+
await storage.close();
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Environment Detection
|
|
287
|
+
|
|
288
|
+
Auto-detects serverless by checking:
|
|
289
|
+
|
|
290
|
+
- AWS Lambda: `AWS_LAMBDA_FUNCTION_NAME`, `AWS_EXECUTION_ENV`
|
|
291
|
+
- Google Cloud: `FUNCTION_NAME`, `K_SERVICE`
|
|
292
|
+
- Azure: `FUNCTIONS_WORKER_RUNTIME`
|
|
293
|
+
- Vercel: `VERCEL`
|
|
294
|
+
- Netlify: `NETLIFY`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LTILaunchConfig, LTISession } from '@lti-tool/core';
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
3
|
+
export declare const LAUNCH_CONFIG_CACHE: LRUCache<string, LTILaunchConfig | typeof undefinedLaunchConfigValue, unknown>;
|
|
4
|
+
export declare const SESSION_CACHE: LRUCache<string, LTISession | typeof undefinedSessionValue, unknown>;
|
|
5
|
+
export declare const SESSION_TTL: number;
|
|
6
|
+
export declare const NONCE_TTL: number;
|
|
7
|
+
export declare const undefinedLaunchConfigValue: unique symbol;
|
|
8
|
+
export type undefinedLaunchConfig = typeof undefinedLaunchConfigValue;
|
|
9
|
+
export declare const undefinedSessionValue: unique symbol;
|
|
10
|
+
export type undefinedSession = typeof undefinedSessionValue;
|
|
11
|
+
//# sourceMappingURL=cacheConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cacheConfig.d.ts","sourceRoot":"","sources":["../src/cacheConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,eAAO,MAAM,mBAAmB,gFAM9B,CAAC;AACH,eAAO,MAAM,aAAa,sEAGxB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAe,CAAC;AACxC,eAAO,MAAM,SAAS,QAAU,CAAC;AAGjC,eAAO,MAAM,0BAA0B,eAAkC,CAAC;AAC1E,MAAM,MAAM,qBAAqB,GAAG,OAAO,0BAA0B,CAAC;AACtE,eAAO,MAAM,qBAAqB,eAA6B,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG,OAAO,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
|
+
export const LAUNCH_CONFIG_CACHE = new LRUCache({
|
|
3
|
+
max: 1000,
|
|
4
|
+
ttl: 1000 * 60 * 15, // 15 minutes
|
|
5
|
+
});
|
|
6
|
+
export const SESSION_CACHE = new LRUCache({
|
|
7
|
+
max: 1000,
|
|
8
|
+
ttl: 1000 * 60 * 5, // 5 minutes (shorter than clients)
|
|
9
|
+
});
|
|
10
|
+
export const SESSION_TTL = 60 * 60 * 24; // session ttl is one day
|
|
11
|
+
export const NONCE_TTL = 60 * 15; // nonce ttl is fifteen minutes
|
|
12
|
+
// we need an undefined value to handle cache misses and cache them
|
|
13
|
+
export const undefinedLaunchConfigValue = Symbol('undefinedLaunchConfig');
|
|
14
|
+
export const undefinedSessionValue = Symbol('undefinedSession');
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export declare const clientsTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "clients";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "clients";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgUUID";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: true;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: undefined;
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
name: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "name";
|
|
24
|
+
tableName: "clients";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "PgVarchar";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {
|
|
39
|
+
length: 255;
|
|
40
|
+
}>;
|
|
41
|
+
iss: import("drizzle-orm/pg-core").PgColumn<{
|
|
42
|
+
name: "iss";
|
|
43
|
+
tableName: "clients";
|
|
44
|
+
dataType: "string";
|
|
45
|
+
columnType: "PgVarchar";
|
|
46
|
+
data: string;
|
|
47
|
+
driverParam: string;
|
|
48
|
+
notNull: true;
|
|
49
|
+
hasDefault: false;
|
|
50
|
+
isPrimaryKey: false;
|
|
51
|
+
isAutoincrement: false;
|
|
52
|
+
hasRuntimeDefault: false;
|
|
53
|
+
enumValues: [string, ...string[]];
|
|
54
|
+
baseColumn: never;
|
|
55
|
+
identity: undefined;
|
|
56
|
+
generated: undefined;
|
|
57
|
+
}, {}, {
|
|
58
|
+
length: 255;
|
|
59
|
+
}>;
|
|
60
|
+
clientId: import("drizzle-orm/pg-core").PgColumn<{
|
|
61
|
+
name: "client_id";
|
|
62
|
+
tableName: "clients";
|
|
63
|
+
dataType: "string";
|
|
64
|
+
columnType: "PgVarchar";
|
|
65
|
+
data: string;
|
|
66
|
+
driverParam: string;
|
|
67
|
+
notNull: true;
|
|
68
|
+
hasDefault: false;
|
|
69
|
+
isPrimaryKey: false;
|
|
70
|
+
isAutoincrement: false;
|
|
71
|
+
hasRuntimeDefault: false;
|
|
72
|
+
enumValues: [string, ...string[]];
|
|
73
|
+
baseColumn: never;
|
|
74
|
+
identity: undefined;
|
|
75
|
+
generated: undefined;
|
|
76
|
+
}, {}, {
|
|
77
|
+
length: 255;
|
|
78
|
+
}>;
|
|
79
|
+
authUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
80
|
+
name: "auth_url";
|
|
81
|
+
tableName: "clients";
|
|
82
|
+
dataType: "string";
|
|
83
|
+
columnType: "PgText";
|
|
84
|
+
data: string;
|
|
85
|
+
driverParam: string;
|
|
86
|
+
notNull: true;
|
|
87
|
+
hasDefault: false;
|
|
88
|
+
isPrimaryKey: false;
|
|
89
|
+
isAutoincrement: false;
|
|
90
|
+
hasRuntimeDefault: false;
|
|
91
|
+
enumValues: [string, ...string[]];
|
|
92
|
+
baseColumn: never;
|
|
93
|
+
identity: undefined;
|
|
94
|
+
generated: undefined;
|
|
95
|
+
}, {}, {}>;
|
|
96
|
+
tokenUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
97
|
+
name: "token_url";
|
|
98
|
+
tableName: "clients";
|
|
99
|
+
dataType: "string";
|
|
100
|
+
columnType: "PgText";
|
|
101
|
+
data: string;
|
|
102
|
+
driverParam: string;
|
|
103
|
+
notNull: true;
|
|
104
|
+
hasDefault: false;
|
|
105
|
+
isPrimaryKey: false;
|
|
106
|
+
isAutoincrement: false;
|
|
107
|
+
hasRuntimeDefault: false;
|
|
108
|
+
enumValues: [string, ...string[]];
|
|
109
|
+
baseColumn: never;
|
|
110
|
+
identity: undefined;
|
|
111
|
+
generated: undefined;
|
|
112
|
+
}, {}, {}>;
|
|
113
|
+
jwksUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
114
|
+
name: "jwks_url";
|
|
115
|
+
tableName: "clients";
|
|
116
|
+
dataType: "string";
|
|
117
|
+
columnType: "PgText";
|
|
118
|
+
data: string;
|
|
119
|
+
driverParam: string;
|
|
120
|
+
notNull: true;
|
|
121
|
+
hasDefault: false;
|
|
122
|
+
isPrimaryKey: false;
|
|
123
|
+
isAutoincrement: false;
|
|
124
|
+
hasRuntimeDefault: false;
|
|
125
|
+
enumValues: [string, ...string[]];
|
|
126
|
+
baseColumn: never;
|
|
127
|
+
identity: undefined;
|
|
128
|
+
generated: undefined;
|
|
129
|
+
}, {}, {}>;
|
|
130
|
+
};
|
|
131
|
+
dialect: "pg";
|
|
132
|
+
}>;
|
|
133
|
+
//# sourceMappingURL=clients.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clients.schema.d.ts","sourceRoot":"","sources":["../../../src/db/schema/clients.schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAexB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { index, pgTable, text, uniqueIndex, uuid, varchar } from 'drizzle-orm/pg-core';
|
|
2
|
+
export const clientsTable = pgTable('clients', {
|
|
3
|
+
id: uuid('id').primaryKey().defaultRandom(),
|
|
4
|
+
name: varchar('name', { length: 255 }).notNull(),
|
|
5
|
+
iss: varchar('iss', { length: 255 }).notNull(),
|
|
6
|
+
clientId: varchar('client_id', { length: 255 }).notNull(),
|
|
7
|
+
authUrl: text('auth_url').notNull(),
|
|
8
|
+
tokenUrl: text('token_url').notNull(),
|
|
9
|
+
jwksUrl: text('jwks_url').notNull(),
|
|
10
|
+
}, (table) => [
|
|
11
|
+
index('issuer_client_idx').on(table.clientId, table.iss),
|
|
12
|
+
uniqueIndex('iss_client_id_unique').on(table.iss, table.clientId),
|
|
13
|
+
]);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export declare const deploymentsTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "deployments";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "deployments";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgUUID";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: true;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: undefined;
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
deploymentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "deployment_id";
|
|
24
|
+
tableName: "deployments";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "PgVarchar";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {
|
|
39
|
+
length: 255;
|
|
40
|
+
}>;
|
|
41
|
+
name: import("drizzle-orm/pg-core").PgColumn<{
|
|
42
|
+
name: "name";
|
|
43
|
+
tableName: "deployments";
|
|
44
|
+
dataType: "string";
|
|
45
|
+
columnType: "PgVarchar";
|
|
46
|
+
data: string;
|
|
47
|
+
driverParam: string;
|
|
48
|
+
notNull: false;
|
|
49
|
+
hasDefault: false;
|
|
50
|
+
isPrimaryKey: false;
|
|
51
|
+
isAutoincrement: false;
|
|
52
|
+
hasRuntimeDefault: false;
|
|
53
|
+
enumValues: [string, ...string[]];
|
|
54
|
+
baseColumn: never;
|
|
55
|
+
identity: undefined;
|
|
56
|
+
generated: undefined;
|
|
57
|
+
}, {}, {
|
|
58
|
+
length: 255;
|
|
59
|
+
}>;
|
|
60
|
+
description: import("drizzle-orm/pg-core").PgColumn<{
|
|
61
|
+
name: "description";
|
|
62
|
+
tableName: "deployments";
|
|
63
|
+
dataType: "string";
|
|
64
|
+
columnType: "PgText";
|
|
65
|
+
data: string;
|
|
66
|
+
driverParam: string;
|
|
67
|
+
notNull: false;
|
|
68
|
+
hasDefault: false;
|
|
69
|
+
isPrimaryKey: false;
|
|
70
|
+
isAutoincrement: false;
|
|
71
|
+
hasRuntimeDefault: false;
|
|
72
|
+
enumValues: [string, ...string[]];
|
|
73
|
+
baseColumn: never;
|
|
74
|
+
identity: undefined;
|
|
75
|
+
generated: undefined;
|
|
76
|
+
}, {}, {}>;
|
|
77
|
+
clientId: import("drizzle-orm/pg-core").PgColumn<{
|
|
78
|
+
name: "client_id";
|
|
79
|
+
tableName: "deployments";
|
|
80
|
+
dataType: "string";
|
|
81
|
+
columnType: "PgUUID";
|
|
82
|
+
data: string;
|
|
83
|
+
driverParam: string;
|
|
84
|
+
notNull: true;
|
|
85
|
+
hasDefault: false;
|
|
86
|
+
isPrimaryKey: false;
|
|
87
|
+
isAutoincrement: false;
|
|
88
|
+
hasRuntimeDefault: false;
|
|
89
|
+
enumValues: undefined;
|
|
90
|
+
baseColumn: never;
|
|
91
|
+
identity: undefined;
|
|
92
|
+
generated: undefined;
|
|
93
|
+
}, {}, {}>;
|
|
94
|
+
};
|
|
95
|
+
dialect: "pg";
|
|
96
|
+
}>;
|
|
97
|
+
//# sourceMappingURL=deployments.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployments.schema.d.ts","sourceRoot":"","sources":["../../../src/db/schema/deployments.schema.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe5B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { index, pgTable, text, uniqueIndex, uuid, varchar } from 'drizzle-orm/pg-core';
|
|
2
|
+
import { clientsTable } from './clients.schema';
|
|
3
|
+
export const deploymentsTable = pgTable('deployments', {
|
|
4
|
+
id: uuid('id').primaryKey().defaultRandom(),
|
|
5
|
+
deploymentId: varchar('deployment_id', { length: 255 }).notNull(),
|
|
6
|
+
name: varchar('name', { length: 255 }),
|
|
7
|
+
description: text('description'),
|
|
8
|
+
clientId: uuid('client_id')
|
|
9
|
+
.notNull()
|
|
10
|
+
.references(() => clientsTable.id),
|
|
11
|
+
}, (table) => [
|
|
12
|
+
index('deployment_id_idx').on(table.deploymentId),
|
|
13
|
+
uniqueIndex('client_deployment_unique').on(table.clientId, table.deploymentId),
|
|
14
|
+
]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/schema/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const noncesTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "nonces";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
nonce: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "nonce";
|
|
7
|
+
tableName: "nonces";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgVarchar";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {
|
|
22
|
+
length: 255;
|
|
23
|
+
}>;
|
|
24
|
+
expiresAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
25
|
+
name: "expires_at";
|
|
26
|
+
tableName: "nonces";
|
|
27
|
+
dataType: "date";
|
|
28
|
+
columnType: "PgTimestamp";
|
|
29
|
+
data: Date;
|
|
30
|
+
driverParam: string;
|
|
31
|
+
notNull: true;
|
|
32
|
+
hasDefault: false;
|
|
33
|
+
isPrimaryKey: false;
|
|
34
|
+
isAutoincrement: false;
|
|
35
|
+
hasRuntimeDefault: false;
|
|
36
|
+
enumValues: undefined;
|
|
37
|
+
baseColumn: never;
|
|
38
|
+
identity: undefined;
|
|
39
|
+
generated: undefined;
|
|
40
|
+
}, {}, {}>;
|
|
41
|
+
};
|
|
42
|
+
dialect: "pg";
|
|
43
|
+
}>;
|
|
44
|
+
//# sourceMappingURL=nonces.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nonces.schema.d.ts","sourceRoot":"","sources":["../../../src/db/schema/nonces.schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGtB,CAAC"}
|