@open-xchange/fastify-sdk 0.1.0
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/README.md +370 -0
- package/lib/app.js +324 -0
- package/lib/config/index.js +4 -0
- package/lib/config/read.js +38 -0
- package/lib/config/registry.js +57 -0
- package/lib/config/util.js +28 -0
- package/lib/database/migrations.js +37 -0
- package/lib/database/mysql.js +81 -0
- package/lib/database/postgres.js +34 -0
- package/lib/dotenv.js +6 -0
- package/lib/health.js +36 -0
- package/lib/index.js +28 -0
- package/lib/lint/index.js +5 -0
- package/lib/logger.js +60 -0
- package/lib/metrics-server.js +33 -0
- package/lib/plugins/cors.js +16 -0
- package/lib/plugins/helmet.js +14 -0
- package/lib/plugins/jwt.js +88 -0
- package/lib/plugins/logging.js +15 -0
- package/lib/plugins/metrics.js +8 -0
- package/lib/plugins/swagger.js +31 -0
- package/lib/redis/index.js +58 -0
- package/lib/testing/index.js +32 -0
- package/lib/testing/jwt.js +17 -0
- package/package.json +85 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Redis from 'ioredis'
|
|
2
|
+
|
|
3
|
+
const defaultQueueOptions = { enableReadyCheck: false, maxRetriesPerRequest: null }
|
|
4
|
+
|
|
5
|
+
export function createRedisClient (options = {}) {
|
|
6
|
+
const hosts = (process.env.REDIS_HOSTS || process.env.REDIS_HOST || '').split(',').filter(Boolean).map(host => {
|
|
7
|
+
const [hostname, port] = host.split(':')
|
|
8
|
+
return { host: hostname, port: Number(port) || 6379 }
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const tlsOptions = {}
|
|
12
|
+
if (process.env.REDIS_TLS_ENABLED === 'true') {
|
|
13
|
+
tlsOptions.tls = {}
|
|
14
|
+
if (process.env.REDIS_TLS_CA) tlsOptions.tls.ca = process.env.REDIS_TLS_CA
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let clientOptions = {
|
|
18
|
+
username: process.env.REDIS_USERNAME,
|
|
19
|
+
db: Number(process.env.REDIS_DB) || 0,
|
|
20
|
+
password: process.env.REDIS_PASSWORD,
|
|
21
|
+
...tlsOptions,
|
|
22
|
+
...defaultQueueOptions,
|
|
23
|
+
...options
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const mode = process.env.REDIS_MODE || 'standalone'
|
|
27
|
+
|
|
28
|
+
if (mode === 'sentinel') {
|
|
29
|
+
clientOptions = {
|
|
30
|
+
sentinels: hosts,
|
|
31
|
+
name: process.env.REDIS_SENTINEL_MASTER_ID,
|
|
32
|
+
...clientOptions
|
|
33
|
+
}
|
|
34
|
+
} else if (mode === 'standalone' && hosts.length > 0) {
|
|
35
|
+
clientOptions = {
|
|
36
|
+
...hosts[0],
|
|
37
|
+
...clientOptions
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (mode === 'cluster') {
|
|
42
|
+
return new Redis.Cluster(hosts, { redisOptions: clientOptions })
|
|
43
|
+
}
|
|
44
|
+
return new Redis(clientOptions)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function createRedisClientFromEnv (options = {}) {
|
|
48
|
+
return createRedisClient(options)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function redisReadyCheck (client) {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const rawClient = client.getClient ? client.getClient() : client
|
|
54
|
+
if (rawClient.status === 'ready') return resolve()
|
|
55
|
+
rawClient.once('ready', () => resolve())
|
|
56
|
+
rawClient.once('error', (err) => reject(err))
|
|
57
|
+
})
|
|
58
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import pino from 'pino'
|
|
2
|
+
import { createApp } from '../app.js'
|
|
3
|
+
|
|
4
|
+
export { generateTokenForJwks, getJwks } from './jwt.js'
|
|
5
|
+
|
|
6
|
+
const silentLogger = pino({ level: 'silent' })
|
|
7
|
+
|
|
8
|
+
export async function createTestApp (options = {}) {
|
|
9
|
+
const {
|
|
10
|
+
plugins: pluginOverrides = {},
|
|
11
|
+
...rest
|
|
12
|
+
} = options
|
|
13
|
+
|
|
14
|
+
const defaultTestPlugins = {
|
|
15
|
+
cors: false,
|
|
16
|
+
helmet: false,
|
|
17
|
+
metrics: false,
|
|
18
|
+
logging: false,
|
|
19
|
+
...pluginOverrides
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return createApp({
|
|
23
|
+
pluginsDir: null,
|
|
24
|
+
metricsServer: false,
|
|
25
|
+
...rest,
|
|
26
|
+
plugins: defaultTestPlugins,
|
|
27
|
+
fastify: {
|
|
28
|
+
loggerInstance: silentLogger,
|
|
29
|
+
...options.fastify
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as jose from 'jose'
|
|
2
|
+
|
|
3
|
+
const { publicKey, privateKey } = await jose.generateKeyPair('RS256')
|
|
4
|
+
|
|
5
|
+
export async function generateTokenForJwks (payload, kid, issuer) {
|
|
6
|
+
return new jose.SignJWT(payload)
|
|
7
|
+
.setProtectedHeader({ alg: 'RS256', kid })
|
|
8
|
+
.setSubject(payload.userId || payload.sub || 'test')
|
|
9
|
+
.setIssuer(issuer)
|
|
10
|
+
.sign(privateKey)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function getJwks (kid) {
|
|
14
|
+
const jwk = await jose.exportJWK(publicKey)
|
|
15
|
+
jwk.kid = kid || jwk.kid
|
|
16
|
+
return { keys: [jwk] }
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-xchange/fastify-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared foundation package for OX App Suite Node.js services",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./mysql": "./lib/database/mysql.js",
|
|
10
|
+
"./postgres": "./lib/database/postgres.js",
|
|
11
|
+
"./migrations": "./lib/database/migrations.js",
|
|
12
|
+
"./config": "./lib/config/index.js",
|
|
13
|
+
"./redis": "./lib/redis/index.js",
|
|
14
|
+
"./testing": "./lib/testing/index.js",
|
|
15
|
+
"./lint": "./lib/lint/index.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"lint": "eslint . --cache --fix",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:coverage": "vitest run --coverage"
|
|
21
|
+
},
|
|
22
|
+
"author": "Open-Xchange",
|
|
23
|
+
"license": "AGPL-3.0-or-later",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@fastify/autoload": "^6.3.1",
|
|
26
|
+
"@fastify/cors": "^11.2.0",
|
|
27
|
+
"@fastify/helmet": "^13.0.2",
|
|
28
|
+
"@fastify/jwt": "^10.0.0",
|
|
29
|
+
"@fastify/sensible": "^6.0.4",
|
|
30
|
+
"@fastify/static": "^9.0.0",
|
|
31
|
+
"@fastify/swagger": "^9.7.0",
|
|
32
|
+
"@fastify/swagger-ui": "^5.2.5",
|
|
33
|
+
"ajv-errors": "^3.0.0",
|
|
34
|
+
"chokidar": "^5.0.0",
|
|
35
|
+
"fastify": "^5.7.4",
|
|
36
|
+
"fastify-metrics": "^12.1.0",
|
|
37
|
+
"fastify-plugin": "^5.1.0",
|
|
38
|
+
"http-errors": "^2.0.1",
|
|
39
|
+
"joi": "^18.0.2",
|
|
40
|
+
"jose": "^6.1.3",
|
|
41
|
+
"js-yaml": "^4.1.1",
|
|
42
|
+
"pino": "^10.3.1",
|
|
43
|
+
"pino-pretty": "^13.1.3",
|
|
44
|
+
"prom-client": "^15.1.3"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"ioredis": "^5.9.0",
|
|
48
|
+
"mysql2": "^3.16.0",
|
|
49
|
+
"pg": "^8.16.0",
|
|
50
|
+
"umzug": "^3.8.2"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"ioredis": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"mysql2": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"pg": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"umzug": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@open-xchange/lint": "^0.2.1",
|
|
68
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
69
|
+
"eslint": "^9.39.2",
|
|
70
|
+
"ioredis": "^5.9.2",
|
|
71
|
+
"mysql2": "^3.16.3",
|
|
72
|
+
"pg": "^8.18.0",
|
|
73
|
+
"umzug": "^3.8.2",
|
|
74
|
+
"vitest": "^4.0.18"
|
|
75
|
+
},
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=20"
|
|
78
|
+
},
|
|
79
|
+
"packageManager": "pnpm@10.27.0",
|
|
80
|
+
"pnpm": {
|
|
81
|
+
"onlyBuiltDependencies": [
|
|
82
|
+
"unrs-resolver"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|