@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.
@@ -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
+ }