@devopsplaybook.io/common-utils 1.9.2 → 1.10.0-beta.22.53149f9
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/.github/workflows/main-build.yml +1 -0
- package/.github/workflows/pr-check.yml +1 -0
- package/.github/workflows/reusable-npm-merge.yml +1 -1
- package/.github/workflows/reusable-npm-pr.yml +1 -1
- package/AGENTS.md +4 -4
- package/README.md +2 -2
- package/dist/src/ConfigBase.js +3 -10
- package/dist/src/DbUtils.js +0 -1
- package/dist/src/DbUtilsNoTelemetry.js +1 -5
- package/dist/src/LLM.js +0 -2
- package/dist/src/OTelContext.js +0 -1
- package/dist/src/PostgresDbUtils.js +5 -20
- package/dist/src/users/Auth.js +2 -15
- package/dist/src/users/User.js +0 -3
- package/dist/src/users/UserApiToken.js +0 -3
- package/dist/src/users/UsersApiTokensData.js +0 -1
- package/dist/src/users/UsersData.js +0 -1
- package/dist/src/users/UsersRoutes.js +0 -1
- package/jest.config.js +5 -2
- package/package.json +7 -9
- package/src/ConfigBase.ts +2 -9
- package/src/DbUtils.ts +0 -2
- package/src/DbUtilsNoTelemetry.spec.ts +0 -6
- package/src/DbUtilsNoTelemetry.ts +0 -4
- package/src/LLM.ts +0 -2
- package/src/OTelContext.ts +0 -2
- package/src/PostgresDbUtils.spec.ts +0 -2
- package/src/PostgresDbUtils.ts +0 -13
- package/src/SqlDbUtils.spec.ts +0 -3
- package/src/SqlDbUtils.ts +0 -1
- package/src/users/Auth.ts +0 -9
- package/src/users/User.ts +0 -3
- package/src/users/UserApiToken.ts +0 -3
- package/src/users/UsersApiTokensData.ts +0 -1
- package/src/users/UsersData.ts +0 -1
- package/src/users/UsersRoutes.ts +0 -1
- package/tsconfig.spec.json +2 -1
- package/eslint.config.mjs +0 -11
|
@@ -11,6 +11,7 @@ jobs:
|
|
|
11
11
|
uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-merge.yml@main
|
|
12
12
|
with:
|
|
13
13
|
npm_package_name: "@devopsplaybook.io/common-utils"
|
|
14
|
+
node_version: "22"
|
|
14
15
|
secrets:
|
|
15
16
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
16
17
|
QUALITY_DASHBOARD_URL: ${{ secrets.QUALITY_DASHBOARD_URL }}
|
|
@@ -20,6 +20,7 @@ jobs:
|
|
|
20
20
|
uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-pr.yml@main
|
|
21
21
|
with:
|
|
22
22
|
npm_package_name: "@devopsplaybook.io/common-utils"
|
|
23
|
+
node_version: "22"
|
|
23
24
|
secrets:
|
|
24
25
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
25
26
|
QUALITY_DASHBOARD_URL: ${{ secrets.QUALITY_DASHBOARD_URL }}
|
package/AGENTS.md
CHANGED
|
@@ -52,8 +52,8 @@ The weekly update of the shared npm libraries is agent-driven instead: a Kuberne
|
|
|
52
52
|
## Key Conventions
|
|
53
53
|
|
|
54
54
|
- **TypeScript**: Target ES2019, CommonJS output, strict mode enabled, declarations generated.
|
|
55
|
-
- **
|
|
56
|
-
- **Tests**: Jest with `
|
|
55
|
+
- **Linting**: Uses `oxlint` with its default **recommended** preset. Minimize disable comments (`eslint-disable`-style comments are honored by oxlint); use them only when the rule cannot be satisfied (e.g. `no-explicit-any` is not enabled by the recommended preset, so `any` needs no directive).
|
|
56
|
+
- **Tests**: Jest with `@swc/jest` transform (`jsc.target` matches tsconfig ES2019) and `v8` coverage provider. Spec files live next to source (`*.spec.ts`). Run with `npm run test`. The `tsconfig.spec.json` includes jest types; `npm run build` also type-checks specs (`tsc -p tsconfig.spec.json --noEmit`).
|
|
57
57
|
- **No default exports**: All modules use named exports only.
|
|
58
58
|
- **OTel dependency injection**: Every DB module exposes a `*SetOTel(tracer, logger)` function that must be called before `*Init()`. OTel instances are stored as module-level singletons.
|
|
59
59
|
- **Auth modules**: `AuthSetOTel(tracer)` and `UsersDataSetOTel(tracer)` must be called before `AuthInit`. Application scopes are registered through `AuthInit(context, config, allScopes)`; `UsersRoutes` relies on `req.tracerSpanApi` set by the `otel-utils-fastify` hooks.
|
|
@@ -68,7 +68,7 @@ The weekly update of the shared npm libraries is agent-driven instead: a Kuberne
|
|
|
68
68
|
```bash
|
|
69
69
|
npm install
|
|
70
70
|
npm run build # tsc -> dist/
|
|
71
|
-
npm run lint #
|
|
71
|
+
npm run lint # oxlint src (must pass with 0 errors)
|
|
72
72
|
npm run test # jest --coverage (all tests must pass)
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -91,7 +91,7 @@ All three commands must pass before committing. The CI pipeline (`reusable-npm-m
|
|
|
91
91
|
|
|
92
92
|
- **uuid ESM**: `uuid` v14+ ships ESM. In any test that transitively imports `uuid`, add `jest.mock("uuid", () => ({ v4: () => "mock-uuid-1234" }))` to avoid `SyntaxError: Unexpected token 'export'`.
|
|
93
93
|
- **better-sqlite3 is synchronous**: `SqlDbUtils` functions return values directly (not Promises). `PostgresDbUtils` functions return Promises. The `DbUtils` facade returns `number | Promise<number>` depending on the active backend.
|
|
94
|
-
- **
|
|
94
|
+
- **Disable-comment placement**: `eslint-disable-next-line` applies to the **immediately following line only** (oxlint honors these comments too). When disabling a rule inside a function call argument, place the comment directly before the offending expression, not before the function call.
|
|
95
95
|
- **pg callback typing**: Always explicitly type pg callback parameters: `(error: Error | null, result: { rowCount: number | null })`. TypeScript cannot infer these from the overloaded `pool.query` signature.
|
|
96
96
|
|
|
97
97
|
## Adopting in Other Projects
|
package/README.md
CHANGED
|
@@ -498,7 +498,7 @@ The `.github/workflows/` directory contains **reusable workflows** that other re
|
|
|
498
498
|
|
|
499
499
|
| Input | Required | Default | Description |
|
|
500
500
|
| ------------------ | -------- | ------- | --------------------------------------------------------- |
|
|
501
|
-
| `node_version` | No | `"
|
|
501
|
+
| `node_version` | No | `"22"` | Node.js version |
|
|
502
502
|
| `npm_package_name` | Yes | -- | npm package name (e.g. `@devopsplaybook.io/common-utils`) |
|
|
503
503
|
|
|
504
504
|
| Secret | Required | Description |
|
|
@@ -630,7 +630,7 @@ jobs:
|
|
|
630
630
|
```bash
|
|
631
631
|
npm install
|
|
632
632
|
npm run build # TypeScript compilation -> dist/
|
|
633
|
-
npm run lint #
|
|
633
|
+
npm run lint # oxlint (recommended preset)
|
|
634
634
|
npm run test # Jest with coverage
|
|
635
635
|
```
|
|
636
636
|
|
package/dist/src/ConfigBase.js
CHANGED
|
@@ -46,7 +46,6 @@ const path_1 = __importDefault(require("path"));
|
|
|
46
46
|
* array → JSON.parse, etc.). When the default is already a string or
|
|
47
47
|
* there is no default, the original string is returned as-is.
|
|
48
48
|
*/
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
49
|
function coerceValue(value, defaultValue) {
|
|
51
50
|
if (defaultValue === undefined || defaultValue === null) {
|
|
52
51
|
return value;
|
|
@@ -145,7 +144,7 @@ class ConfigBase {
|
|
|
145
144
|
if (pkg && pkg.version) {
|
|
146
145
|
this.VERSION = pkg.version;
|
|
147
146
|
}
|
|
148
|
-
// eslint-disable-next-line
|
|
147
|
+
// eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
|
|
149
148
|
}
|
|
150
149
|
catch (_e) {
|
|
151
150
|
// fallback to "1"
|
|
@@ -196,7 +195,6 @@ class ConfigBase {
|
|
|
196
195
|
field: def.field,
|
|
197
196
|
sensitive: (_a = def.sensitive) !== null && _a !== void 0 ? _a : false,
|
|
198
197
|
envAliases: (_b = def.envAliases) !== null && _b !== void 0 ? _b : [],
|
|
199
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
200
198
|
defaultValue: this[def.field],
|
|
201
199
|
});
|
|
202
200
|
}
|
|
@@ -208,12 +206,11 @@ class ConfigBase {
|
|
|
208
206
|
* When omitted nothing is logged (useful in tests).
|
|
209
207
|
*/
|
|
210
208
|
async reload(logger) {
|
|
211
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
212
209
|
const log = logger !== null && logger !== void 0 ? logger : (() => { });
|
|
213
210
|
let content = {};
|
|
214
211
|
try {
|
|
215
212
|
content = await fse.readJson(this.CONFIG_FILE);
|
|
216
|
-
// eslint-disable-next-line
|
|
213
|
+
// eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
|
|
217
214
|
}
|
|
218
215
|
catch (_e) {
|
|
219
216
|
// config file is optional – fall back to env + defaults
|
|
@@ -244,13 +241,11 @@ class ConfigBase {
|
|
|
244
241
|
// 3. Apply environment value (full name or alias) if found,
|
|
245
242
|
// coercing strings to match the default value type
|
|
246
243
|
if (foundValue !== undefined) {
|
|
247
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
244
|
this[field] = coerceValue(foundValue, defaultValue);
|
|
249
245
|
}
|
|
250
246
|
// 4. Config file override (environment always wins, but if neither
|
|
251
247
|
// environment nor alias matched, check config file)
|
|
252
248
|
if (foundValue === undefined && content[field] !== undefined) {
|
|
253
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
249
|
this[field] = content[field];
|
|
255
250
|
from = "config";
|
|
256
251
|
}
|
|
@@ -258,9 +253,7 @@ class ConfigBase {
|
|
|
258
253
|
log(`Configuration Value: ${field}: ******************** (from ${from})`);
|
|
259
254
|
}
|
|
260
255
|
else {
|
|
261
|
-
log(
|
|
262
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
263
|
-
`Configuration Value: ${field}: ${this[field]} (from ${from}${usedAlias ? ` via alias` : ""})`);
|
|
256
|
+
log(`Configuration Value: ${field}: ${this[field]} (from ${from}${usedAlias ? ` via alias` : ""})`);
|
|
264
257
|
}
|
|
265
258
|
}
|
|
266
259
|
}
|
package/dist/src/DbUtils.js
CHANGED
|
@@ -75,7 +75,6 @@ async function DbUtilsInit(context, config, sqlDir) {
|
|
|
75
75
|
* - SQLite: `better-sqlite3` `Database` instance
|
|
76
76
|
* - Postgres: `pg` `Pool` instance
|
|
77
77
|
*/
|
|
78
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
78
|
function DbUtilsGetDatabase() {
|
|
80
79
|
if (databaseType === "postgres") {
|
|
81
80
|
return PostgresDbUtils.PostgresDbUtilsGetPool();
|
|
@@ -19,9 +19,7 @@ function DbUtilsNoTelemetrySetLogger(loggerIn) {
|
|
|
19
19
|
*
|
|
20
20
|
* @returns Number of rows inserted.
|
|
21
21
|
*/
|
|
22
|
-
function DbUtilsNoTelemetryBatchInsert(tableCols, numCols,
|
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
-
rows) {
|
|
22
|
+
function DbUtilsNoTelemetryBatchInsert(tableCols, numCols, rows) {
|
|
25
23
|
if (rows.length === 0)
|
|
26
24
|
return 0;
|
|
27
25
|
const rowSQL = `(${Array.from({ length: numCols }, () => "?").join(",")})`;
|
|
@@ -40,7 +38,6 @@ function DbUtilsNoTelemetryExecSQL(sql, params = []) {
|
|
|
40
38
|
if (dbType === "postgres") {
|
|
41
39
|
const pgSql = (0, DbUtils_1.convertToPostgresPlaceholders)(sql);
|
|
42
40
|
return new Promise((resolve, reject) => {
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
41
|
(0, DbUtils_1.DbUtilsGetDatabase)().query(pgSql, params, (error, result) => {
|
|
45
42
|
if (error) {
|
|
46
43
|
logger.error(`SQL INSERT ERROR: ${sql.substring(0, 200)}`, error);
|
|
@@ -71,7 +68,6 @@ function DbUtilsNoTelemetryQuerySQL(sql, params = [], debug = false) {
|
|
|
71
68
|
if (dbType === "postgres") {
|
|
72
69
|
const pgSql = (0, DbUtils_1.convertToPostgresPlaceholders)(sql);
|
|
73
70
|
return new Promise((resolve, reject) => {
|
|
74
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
71
|
(0, DbUtils_1.DbUtilsGetDatabase)().query(pgSql, params, (error, result) => {
|
|
76
72
|
if (error) {
|
|
77
73
|
logger.error(`SQL ERROR: ${sql}`, error);
|
package/dist/src/LLM.js
CHANGED
|
@@ -87,7 +87,6 @@ class LLMClient {
|
|
|
87
87
|
throw new Error("LLM integration disabled (apiKey, apiUrl or model not set)");
|
|
88
88
|
}
|
|
89
89
|
const model = (options === null || options === void 0 ? void 0 : options.model) || this.model;
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
90
|
const body = {
|
|
92
91
|
model,
|
|
93
92
|
messages,
|
|
@@ -122,7 +121,6 @@ class LLMClient {
|
|
|
122
121
|
extractErrorMessage(err) {
|
|
123
122
|
var _a, _b, _c;
|
|
124
123
|
if (axios_1.default.isAxiosError(err)) {
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
126
124
|
const providerMessage = (_c = (_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.message;
|
|
127
125
|
if (providerMessage) {
|
|
128
126
|
return providerMessage;
|
package/dist/src/OTelContext.js
CHANGED
|
@@ -166,9 +166,7 @@ class PostgresSchemaDbUtils {
|
|
|
166
166
|
* otherwise use the runtime pool (default).
|
|
167
167
|
* @returns Number of rows changed.
|
|
168
168
|
*/
|
|
169
|
-
execSQL(context, sql,
|
|
170
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
|
-
params = [], useSchemaPool = false) {
|
|
169
|
+
execSQL(context, sql, params = [], useSchemaPool = false) {
|
|
172
170
|
const span = tracer.startSpan("PostgresSchemaDbUtilsExecSQL", context);
|
|
173
171
|
const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
|
|
174
172
|
if (!pool) {
|
|
@@ -219,9 +217,7 @@ class PostgresSchemaDbUtils {
|
|
|
219
217
|
* Execute a read SQL query with OTel tracing.
|
|
220
218
|
* @returns Array of row objects.
|
|
221
219
|
*/
|
|
222
|
-
querySQL(context, sql,
|
|
223
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
224
|
-
params = [], useSchemaPool = false) {
|
|
220
|
+
querySQL(context, sql, params = [], useSchemaPool = false) {
|
|
225
221
|
const span = tracer.startSpan("PostgresSchemaDbUtilsQuerySQL", context);
|
|
226
222
|
const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
|
|
227
223
|
if (!pool) {
|
|
@@ -247,9 +243,7 @@ class PostgresSchemaDbUtils {
|
|
|
247
243
|
/**
|
|
248
244
|
* Run a callback inside a transaction.
|
|
249
245
|
*/
|
|
250
|
-
async transaction(context,
|
|
251
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
-
callback, useSchemaPool = false) {
|
|
246
|
+
async transaction(context, callback, useSchemaPool = false) {
|
|
253
247
|
const span = tracer.startSpan("PostgresSchemaDbUtilsTransaction", context);
|
|
254
248
|
const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
|
|
255
249
|
if (!pool) {
|
|
@@ -294,15 +288,12 @@ class PostgresSchemaDbUtils {
|
|
|
294
288
|
this.moduleLogger.info("All database pools closed");
|
|
295
289
|
}
|
|
296
290
|
// -- Internal helpers (schema pool only) ----------------------------------
|
|
297
|
-
execSQLForSchema(context, sql,
|
|
298
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
299
|
-
params = []) {
|
|
291
|
+
execSQLForSchema(context, sql, params = []) {
|
|
300
292
|
const span = tracer.startSpan("PostgresSchemaDbUtilsExecSQLForSchema", context);
|
|
301
293
|
if (!this.schemaPool) {
|
|
302
294
|
throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
|
|
303
295
|
}
|
|
304
296
|
return new Promise((resolve, reject) => {
|
|
305
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
306
297
|
this.schemaPool.query(sql, params, (error) => {
|
|
307
298
|
span.end();
|
|
308
299
|
if (error) {
|
|
@@ -322,11 +313,9 @@ class PostgresSchemaDbUtils {
|
|
|
322
313
|
throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
|
|
323
314
|
}
|
|
324
315
|
return new Promise((resolve, reject) => {
|
|
325
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
326
316
|
this.schemaPool.query(sql, (error) => {
|
|
327
317
|
span.end();
|
|
328
318
|
if (error) {
|
|
329
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
330
319
|
if (error.code === "ENOENT") {
|
|
331
320
|
resolve();
|
|
332
321
|
}
|
|
@@ -341,22 +330,18 @@ class PostgresSchemaDbUtils {
|
|
|
341
330
|
});
|
|
342
331
|
}
|
|
343
332
|
catch (error) {
|
|
344
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
345
333
|
if (error.code === "ENOENT") {
|
|
346
334
|
return;
|
|
347
335
|
}
|
|
348
336
|
throw error;
|
|
349
337
|
}
|
|
350
338
|
}
|
|
351
|
-
querySQLForSchema(context, sql,
|
|
352
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
353
|
-
params = []) {
|
|
339
|
+
querySQLForSchema(context, sql, params = []) {
|
|
354
340
|
const span = tracer.startSpan("PostgresSchemaDbUtilsQuerySQLForSchema", context);
|
|
355
341
|
if (!this.schemaPool) {
|
|
356
342
|
throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
|
|
357
343
|
}
|
|
358
344
|
return new Promise((resolve, reject) => {
|
|
359
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
360
345
|
this.schemaPool.query(sql, params, (error, result) => {
|
|
361
346
|
span.end();
|
|
362
347
|
if (error) {
|
package/dist/src/users/Auth.js
CHANGED
|
@@ -104,7 +104,6 @@ async function AuthGenerateJWT(user) {
|
|
|
104
104
|
* mirroring the owning user's live role and scopes is built (valid until
|
|
105
105
|
* the token is revoked).
|
|
106
106
|
*/
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
107
|
async function jwtDecodeCached(req) {
|
|
109
108
|
if (req._jwtPayload) {
|
|
110
109
|
return req._jwtPayload;
|
|
@@ -131,7 +130,6 @@ async function jwtDecodeCached(req) {
|
|
|
131
130
|
* Permissions are read from the user record at resolution time, so
|
|
132
131
|
* role/scope changes apply to existing tokens immediately.
|
|
133
132
|
*/
|
|
134
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
133
|
async function resolveApiToken(authorizationHeader) {
|
|
136
134
|
const token = authorizationHeader.split(" ")[1];
|
|
137
135
|
if (!token) {
|
|
@@ -140,7 +138,6 @@ async function resolveApiToken(authorizationHeader) {
|
|
|
140
138
|
const span = tracer.startSpan("AuthResolveApiToken");
|
|
141
139
|
const tokenHash = (0, crypto_1.createHash)("sha256").update(token).digest("hex");
|
|
142
140
|
const apiToken = await (0, UsersApiTokensData_1.UsersApiTokensDataGetByTokenHash)(span, tokenHash);
|
|
143
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
144
141
|
let payload = null;
|
|
145
142
|
if (apiToken) {
|
|
146
143
|
const user = await (0, UsersData_1.UsersDataGet)(span, apiToken.userId);
|
|
@@ -156,17 +153,12 @@ async function resolveApiToken(authorizationHeader) {
|
|
|
156
153
|
span.end();
|
|
157
154
|
return payload;
|
|
158
155
|
}
|
|
159
|
-
async function AuthMustBeAuthenticated(
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
161
|
-
req,
|
|
162
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
-
res) {
|
|
156
|
+
async function AuthMustBeAuthenticated(req, res) {
|
|
164
157
|
if (!(await jwtDecodeCached(req))) {
|
|
165
158
|
res.status(403).send({ error: "Access Denied" });
|
|
166
159
|
throw new Error("Access Denied");
|
|
167
160
|
}
|
|
168
161
|
}
|
|
169
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
170
162
|
async function AuthMustBeAdmin(req, res) {
|
|
171
163
|
const info = await jwtDecodeCached(req);
|
|
172
164
|
if ((info === null || info === void 0 ? void 0 : info.role) === "admin") {
|
|
@@ -175,11 +167,7 @@ async function AuthMustBeAdmin(req, res) {
|
|
|
175
167
|
res.status(403).send({ error: "Access Denied" });
|
|
176
168
|
throw new Error("Access Denied");
|
|
177
169
|
}
|
|
178
|
-
async function AuthHasScope(
|
|
179
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
180
|
-
req,
|
|
181
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
-
res, scope) {
|
|
170
|
+
async function AuthHasScope(req, res, scope) {
|
|
183
171
|
const info = await jwtDecodeCached(req);
|
|
184
172
|
if (!info) {
|
|
185
173
|
res.status(403).send({ error: "Access Denied" });
|
|
@@ -195,7 +183,6 @@ res, scope) {
|
|
|
195
183
|
res.status(403).send({ error: "Access Denied" });
|
|
196
184
|
throw new Error("Access Denied");
|
|
197
185
|
}
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
186
|
async function AuthGetUserSession(req) {
|
|
200
187
|
const userSession = { isAuthenticated: false };
|
|
201
188
|
const info = await jwtDecodeCached(req);
|
package/dist/src/users/User.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.User = void 0;
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
5
|
class User {
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
6
|
static fromJson(json) {
|
|
8
7
|
if (!json) {
|
|
9
8
|
return null;
|
|
@@ -34,7 +33,6 @@ class User {
|
|
|
34
33
|
this.scopes = [...User.DEFAULT_SCOPES];
|
|
35
34
|
this.id = (0, uuid_1.v4)();
|
|
36
35
|
}
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
36
|
toJson() {
|
|
39
37
|
return {
|
|
40
38
|
id: this.id,
|
|
@@ -44,7 +42,6 @@ class User {
|
|
|
44
42
|
scopes: this.scopes,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
45
|
toTransportJson() {
|
|
49
46
|
return {
|
|
50
47
|
id: this.id,
|
|
@@ -12,7 +12,6 @@ const uuid_1 = require("uuid");
|
|
|
12
12
|
*/
|
|
13
13
|
class UserApiToken {
|
|
14
14
|
//
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
15
|
static fromJson(json) {
|
|
17
16
|
if (!json) {
|
|
18
17
|
return null;
|
|
@@ -28,7 +27,6 @@ class UserApiToken {
|
|
|
28
27
|
constructor() {
|
|
29
28
|
this.id = (0, uuid_1.v4)();
|
|
30
29
|
}
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
30
|
toJson() {
|
|
33
31
|
return {
|
|
34
32
|
id: this.id,
|
|
@@ -39,7 +37,6 @@ class UserApiToken {
|
|
|
39
37
|
};
|
|
40
38
|
}
|
|
41
39
|
// Transport representation: never exposes the token hash.
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
40
|
toTransportJson() {
|
|
44
41
|
return {
|
|
45
42
|
id: this.id,
|
|
@@ -71,7 +71,6 @@ async function UsersApiTokensDataDeleteByUser(context, userId) {
|
|
|
71
71
|
span.end();
|
|
72
72
|
}
|
|
73
73
|
// Private Functions
|
|
74
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
74
|
function fromRaw(tokenRaw) {
|
|
76
75
|
const apiToken = new UserApiToken_1.UserApiToken();
|
|
77
76
|
apiToken.id = tokenRaw.id;
|
|
@@ -13,7 +13,6 @@ const UsersApiTokensData_1 = require("./UsersApiTokensData");
|
|
|
13
13
|
* Retrieves the OTel span attached to the request by the
|
|
14
14
|
* `@devopsplaybook.io/otel-utils-fastify` hooks.
|
|
15
15
|
*/
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
16
|
function requestSpan(req) {
|
|
18
17
|
return req === null || req === void 0 ? void 0 : req.tracerSpanApi;
|
|
19
18
|
}
|
package/jest.config.js
CHANGED
|
@@ -2,12 +2,15 @@ module.exports = {
|
|
|
2
2
|
moduleFileExtensions: ["ts", "js"],
|
|
3
3
|
transform: {
|
|
4
4
|
"^.+\\.(ts|tsx)$": [
|
|
5
|
-
"
|
|
5
|
+
"@swc/jest",
|
|
6
6
|
{
|
|
7
|
-
|
|
7
|
+
jsc: {
|
|
8
|
+
target: "es2019",
|
|
9
|
+
},
|
|
8
10
|
},
|
|
9
11
|
],
|
|
10
12
|
},
|
|
13
|
+
coverageProvider: "v8",
|
|
11
14
|
testMatch: ["/**/src/**/*.spec.(ts|js)"],
|
|
12
15
|
testPathIgnorePatterns: ["/node_modules/", "/dist/"],
|
|
13
16
|
testEnvironment: "node",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devopsplaybook.io/common-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0-beta.22.53149f9",
|
|
4
4
|
"description": "Shared utility modules for devopsplaybook.io projects (DB, Config, OTel context, auth/users, notifications, LLM, system helpers)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Open Telemetry",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"main": "dist/index.js",
|
|
22
22
|
"types": "dist/index.d.ts",
|
|
23
23
|
"scripts": {
|
|
24
|
-
"build": "tsc",
|
|
25
|
-
"lint": "
|
|
24
|
+
"build": "tsc && tsc -p tsconfig.spec.json --noEmit",
|
|
25
|
+
"lint": "oxlint src",
|
|
26
26
|
"test": "jest --coverage"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"uuid": "^14.0.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@
|
|
42
|
+
"@swc/core": "^1.16.2",
|
|
43
|
+
"@swc/jest": "^0.2.39",
|
|
43
44
|
"@types/bcrypt": "^6.0.0",
|
|
44
45
|
"@types/better-sqlite3": "^9.6.0",
|
|
45
46
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -48,12 +49,9 @@
|
|
|
48
49
|
"@types/node": "^26.6.2",
|
|
49
50
|
"@types/pg": "^8.23.1",
|
|
50
51
|
"@types/uuid": "^11.0.0",
|
|
51
|
-
"eslint": "^10.11.0",
|
|
52
52
|
"jest": "^30.5.2",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"typescript": "^6.0.3",
|
|
56
|
-
"typescript-eslint": "^8.70.0"
|
|
53
|
+
"oxlint": "^1.83.0",
|
|
54
|
+
"typescript": "^7.0.2"
|
|
57
55
|
},
|
|
58
56
|
"publishConfig": {
|
|
59
57
|
"access": "public"
|
package/src/ConfigBase.ts
CHANGED
|
@@ -59,7 +59,6 @@ export interface ConfigCommonInterface
|
|
|
59
59
|
* array → JSON.parse, etc.). When the default is already a string or
|
|
60
60
|
* there is no default, the original string is returned as-is.
|
|
61
61
|
*/
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
62
|
function coerceValue(value: string, defaultValue: any): any {
|
|
64
63
|
if (defaultValue === undefined || defaultValue === null) {
|
|
65
64
|
return value;
|
|
@@ -155,7 +154,6 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
155
154
|
field: string;
|
|
156
155
|
sensitive: boolean;
|
|
157
156
|
envAliases: string[];
|
|
158
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
159
157
|
defaultValue: any;
|
|
160
158
|
}[] = [];
|
|
161
159
|
|
|
@@ -173,7 +171,7 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
173
171
|
if (pkg && pkg.version) {
|
|
174
172
|
this.VERSION = pkg.version;
|
|
175
173
|
}
|
|
176
|
-
// eslint-disable-next-line
|
|
174
|
+
// eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
|
|
177
175
|
} catch (_e) {
|
|
178
176
|
// fallback to "1"
|
|
179
177
|
}
|
|
@@ -224,7 +222,6 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
224
222
|
field: def.field,
|
|
225
223
|
sensitive: def.sensitive ?? false,
|
|
226
224
|
envAliases: def.envAliases ?? [],
|
|
227
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
228
225
|
defaultValue: (this as any)[def.field],
|
|
229
226
|
});
|
|
230
227
|
}
|
|
@@ -237,12 +234,11 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
237
234
|
* When omitted nothing is logged (useful in tests).
|
|
238
235
|
*/
|
|
239
236
|
public async reload(logger?: (message: string) => void): Promise<void> {
|
|
240
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
241
237
|
const log = logger ?? (() => {});
|
|
242
238
|
let content: Record<string, unknown> = {};
|
|
243
239
|
try {
|
|
244
240
|
content = await fse.readJson(this.CONFIG_FILE);
|
|
245
|
-
// eslint-disable-next-line
|
|
241
|
+
// eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
|
|
246
242
|
} catch (_e) {
|
|
247
243
|
// config file is optional – fall back to env + defaults
|
|
248
244
|
}
|
|
@@ -277,14 +273,12 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
277
273
|
// 3. Apply environment value (full name or alias) if found,
|
|
278
274
|
// coercing strings to match the default value type
|
|
279
275
|
if (foundValue !== undefined) {
|
|
280
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
281
276
|
(this as any)[field] = coerceValue(foundValue, defaultValue);
|
|
282
277
|
}
|
|
283
278
|
|
|
284
279
|
// 4. Config file override (environment always wins, but if neither
|
|
285
280
|
// environment nor alias matched, check config file)
|
|
286
281
|
if (foundValue === undefined && content[field] !== undefined) {
|
|
287
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
288
282
|
(this as any)[field] = content[field];
|
|
289
283
|
from = "config";
|
|
290
284
|
}
|
|
@@ -295,7 +289,6 @@ export abstract class ConfigBase implements ConfigCommonInterface {
|
|
|
295
289
|
);
|
|
296
290
|
} else {
|
|
297
291
|
log(
|
|
298
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
299
292
|
`Configuration Value: ${field}: ${(this as any)[field]} (from ${from}${usedAlias ? ` via alias` : ""})`,
|
|
300
293
|
);
|
|
301
294
|
}
|
package/src/DbUtils.ts
CHANGED
|
@@ -53,7 +53,6 @@ export async function DbUtilsInit(
|
|
|
53
53
|
* - SQLite: `better-sqlite3` `Database` instance
|
|
54
54
|
* - Postgres: `pg` `Pool` instance
|
|
55
55
|
*/
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
56
|
export function DbUtilsGetDatabase(): any {
|
|
58
57
|
if (databaseType === "postgres") {
|
|
59
58
|
return PostgresDbUtils.PostgresDbUtilsGetPool();
|
|
@@ -99,7 +98,6 @@ export function DbUtilsQuerySQL(
|
|
|
99
98
|
sql: string,
|
|
100
99
|
params: unknown[] = [],
|
|
101
100
|
debug = false,
|
|
102
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
101
|
): any[] | Promise<any[]> {
|
|
104
102
|
if (databaseType === "postgres") {
|
|
105
103
|
return PostgresDbUtils.PostgresDbUtilsQuerySQL(
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
DbUtilsNoTelemetryQuerySQL,
|
|
5
5
|
} from "./DbUtilsNoTelemetry";
|
|
6
6
|
|
|
7
|
-
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
|
8
7
|
|
|
9
8
|
// Shared mock DB handle – defined BEFORE jest.mock factory so it's hoisted correctly.
|
|
10
9
|
// We use jest.fn() at module scope; the mock factory captures the same reference.
|
|
@@ -38,11 +37,9 @@ beforeAll(() => {
|
|
|
38
37
|
error: jest.fn(),
|
|
39
38
|
info: jest.fn(),
|
|
40
39
|
warn: jest.fn(),
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
40
|
} as any;
|
|
43
41
|
DbUtilsNoTelemetryModule.DbUtilsNoTelemetrySetLogger({
|
|
44
42
|
createModuleLogger: () => mockLogger,
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
43
|
} as any);
|
|
47
44
|
});
|
|
48
45
|
|
|
@@ -62,7 +59,6 @@ describe("DbUtilsNoTelemetryBatchInsert", () => {
|
|
|
62
59
|
mockPrepare.mockReturnValue({
|
|
63
60
|
run: jest.fn().mockReturnValue({ changes: 2 }),
|
|
64
61
|
all: jest.fn(),
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
62
|
} as any);
|
|
67
63
|
|
|
68
64
|
const rows = [
|
|
@@ -83,7 +79,6 @@ describe("DbUtilsNoTelemetryExecSQL (sqlite)", () => {
|
|
|
83
79
|
mockPrepare.mockReturnValue({
|
|
84
80
|
run: jest.fn().mockReturnValue({ changes: 3 }),
|
|
85
81
|
all: jest.fn(),
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
82
|
} as any);
|
|
88
83
|
|
|
89
84
|
const result = DbUtilsNoTelemetryExecSQL("INSERT INTO t (c) VALUES (?)", [
|
|
@@ -135,7 +130,6 @@ describe("DbUtilsNoTelemetryQuerySQL (sqlite)", () => {
|
|
|
135
130
|
mockPrepare.mockReturnValue({
|
|
136
131
|
run: jest.fn(),
|
|
137
132
|
all: jest.fn().mockReturnValue(expectedRows),
|
|
138
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
133
|
} as any);
|
|
140
134
|
|
|
141
135
|
const result = DbUtilsNoTelemetryQuerySQL("SELECT * FROM t");
|
|
@@ -24,7 +24,6 @@ export function DbUtilsNoTelemetrySetLogger(loggerIn: StandardLogger): void {
|
|
|
24
24
|
export function DbUtilsNoTelemetryBatchInsert(
|
|
25
25
|
tableCols: string,
|
|
26
26
|
numCols: number,
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
27
|
rows: any[][],
|
|
29
28
|
): number | Promise<number> {
|
|
30
29
|
if (rows.length === 0) return 0;
|
|
@@ -50,7 +49,6 @@ export function DbUtilsNoTelemetryExecSQL(
|
|
|
50
49
|
if (dbType === "postgres") {
|
|
51
50
|
const pgSql = convertToPostgresPlaceholders(sql);
|
|
52
51
|
return new Promise((resolve, reject) => {
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
52
|
(DbUtilsGetDatabase() as any).query(
|
|
55
53
|
pgSql,
|
|
56
54
|
params,
|
|
@@ -87,7 +85,6 @@ export function DbUtilsNoTelemetryQuerySQL(
|
|
|
87
85
|
sql: string,
|
|
88
86
|
params: unknown[] = [],
|
|
89
87
|
debug = false,
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
88
|
): any[] | Promise<any[]> {
|
|
92
89
|
if (debug) {
|
|
93
90
|
console.log(sql);
|
|
@@ -96,7 +93,6 @@ export function DbUtilsNoTelemetryQuerySQL(
|
|
|
96
93
|
if (dbType === "postgres") {
|
|
97
94
|
const pgSql = convertToPostgresPlaceholders(sql);
|
|
98
95
|
return new Promise((resolve, reject) => {
|
|
99
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
100
96
|
(DbUtilsGetDatabase() as any).query(
|
|
101
97
|
pgSql,
|
|
102
98
|
params,
|
package/src/LLM.ts
CHANGED
|
@@ -159,7 +159,6 @@ export class LLMClient {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
const model = options?.model || this.model;
|
|
162
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
162
|
const body: Record<string, any> = {
|
|
164
163
|
model,
|
|
165
164
|
messages,
|
|
@@ -195,7 +194,6 @@ export class LLMClient {
|
|
|
195
194
|
*/
|
|
196
195
|
private extractErrorMessage(err: unknown): string {
|
|
197
196
|
if (axios.isAxiosError(err)) {
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
197
|
const providerMessage = (err.response?.data as any)?.error?.message;
|
|
200
198
|
if (providerMessage) {
|
|
201
199
|
return providerMessage;
|
package/src/OTelContext.ts
CHANGED
|
@@ -20,7 +20,6 @@ export interface OTelContext {
|
|
|
20
20
|
* Retrieves the span previously attached to a request object.
|
|
21
21
|
* Equivalent to `req.tracerSpanApi`.
|
|
22
22
|
*/
|
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
23
|
OTelRequestSpan: (req: any) => Span | undefined;
|
|
25
24
|
}
|
|
26
25
|
|
|
@@ -59,7 +58,6 @@ export function createOTelContext(): OTelContext {
|
|
|
59
58
|
}
|
|
60
59
|
return logger;
|
|
61
60
|
},
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
61
|
OTelRequestSpan: (req: any) => req?.tracerSpanApi as Span | undefined,
|
|
64
62
|
};
|
|
65
63
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
1
|
|
|
3
2
|
// Mock pg before imports
|
|
4
3
|
const mockQuery = jest.fn();
|
|
@@ -58,7 +57,6 @@ describe("PostgresDbUtils", () => {
|
|
|
58
57
|
beforeEach(() => {
|
|
59
58
|
jest.clearAllMocks();
|
|
60
59
|
jest.isolateModules(() => {
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
60
|
PostgresDbUtils = require("./PostgresDbUtils");
|
|
63
61
|
});
|
|
64
62
|
PostgresDbUtils.PostgresDbUtilsSetOTel(
|
package/src/PostgresDbUtils.ts
CHANGED
|
@@ -181,7 +181,6 @@ export class PostgresSchemaDbUtils {
|
|
|
181
181
|
execSQL(
|
|
182
182
|
context: Span,
|
|
183
183
|
sql: string,
|
|
184
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
184
|
params: any[] = [],
|
|
186
185
|
useSchemaPool = false,
|
|
187
186
|
): Promise<number> {
|
|
@@ -257,10 +256,8 @@ export class PostgresSchemaDbUtils {
|
|
|
257
256
|
querySQL(
|
|
258
257
|
context: Span,
|
|
259
258
|
sql: string,
|
|
260
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
259
|
params: any[] = [],
|
|
262
260
|
useSchemaPool = false,
|
|
263
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
264
261
|
): Promise<any[]> {
|
|
265
262
|
const span = tracer.startSpan("PostgresSchemaDbUtilsQuerySQL", context);
|
|
266
263
|
const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
|
|
@@ -300,7 +297,6 @@ export class PostgresSchemaDbUtils {
|
|
|
300
297
|
*/
|
|
301
298
|
async transaction(
|
|
302
299
|
context: Span,
|
|
303
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
304
300
|
callback: (client: any) => Promise<void>,
|
|
305
301
|
useSchemaPool = false,
|
|
306
302
|
): Promise<void> {
|
|
@@ -370,7 +366,6 @@ export class PostgresSchemaDbUtils {
|
|
|
370
366
|
private execSQLForSchema(
|
|
371
367
|
context: Span,
|
|
372
368
|
sql: string,
|
|
373
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
374
369
|
params: any[] = [],
|
|
375
370
|
): Promise<void> {
|
|
376
371
|
const span = tracer.startSpan(
|
|
@@ -383,7 +378,6 @@ export class PostgresSchemaDbUtils {
|
|
|
383
378
|
}
|
|
384
379
|
|
|
385
380
|
return new Promise((resolve, reject) => {
|
|
386
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
387
381
|
this.schemaPool!.query(sql, params, (error: Error | null) => {
|
|
388
382
|
span.end();
|
|
389
383
|
if (error) {
|
|
@@ -411,11 +405,9 @@ export class PostgresSchemaDbUtils {
|
|
|
411
405
|
}
|
|
412
406
|
|
|
413
407
|
return new Promise((resolve, reject) => {
|
|
414
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
415
408
|
this.schemaPool!.query(sql, (error: Error | null) => {
|
|
416
409
|
span.end();
|
|
417
410
|
if (error) {
|
|
418
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
419
411
|
if ((error as any).code === "ENOENT") {
|
|
420
412
|
resolve();
|
|
421
413
|
} else {
|
|
@@ -427,7 +419,6 @@ export class PostgresSchemaDbUtils {
|
|
|
427
419
|
});
|
|
428
420
|
});
|
|
429
421
|
} catch (error) {
|
|
430
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
431
422
|
if ((error as any).code === "ENOENT") {
|
|
432
423
|
return;
|
|
433
424
|
}
|
|
@@ -438,9 +429,7 @@ export class PostgresSchemaDbUtils {
|
|
|
438
429
|
private querySQLForSchema(
|
|
439
430
|
context: Span,
|
|
440
431
|
sql: string,
|
|
441
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
442
432
|
params: any[] = [],
|
|
443
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
444
433
|
): Promise<any[]> {
|
|
445
434
|
const span = tracer.startSpan(
|
|
446
435
|
"PostgresSchemaDbUtilsQuerySQLForSchema",
|
|
@@ -452,7 +441,6 @@ export class PostgresSchemaDbUtils {
|
|
|
452
441
|
}
|
|
453
442
|
|
|
454
443
|
return new Promise((resolve, reject) => {
|
|
455
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
456
444
|
this.schemaPool!.query(
|
|
457
445
|
sql,
|
|
458
446
|
params,
|
|
@@ -616,7 +604,6 @@ export function PostgresDbUtilsQuerySQL(
|
|
|
616
604
|
sql: string,
|
|
617
605
|
params: unknown[] = [],
|
|
618
606
|
debug = false,
|
|
619
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
620
607
|
): Promise<any[]> {
|
|
621
608
|
const span = tracer.startSpan("PostgresDbUtilsQuerySQL", context);
|
|
622
609
|
if (debug) {
|
package/src/SqlDbUtils.spec.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
1
|
|
|
3
2
|
// Mock dependencies before imports
|
|
4
3
|
jest.mock("better-sqlite3", () => {
|
|
@@ -64,7 +63,6 @@ describe("SqlDbUtils", () => {
|
|
|
64
63
|
jest.clearAllMocks();
|
|
65
64
|
// Re-import to reset module state
|
|
66
65
|
jest.isolateModules(() => {
|
|
67
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
68
66
|
SqlDbUtils = require("./SqlDbUtils");
|
|
69
67
|
});
|
|
70
68
|
SqlDbUtils.SqlDbUtilsSetOTel(mockTracer as any, mockLogger as any);
|
|
@@ -77,7 +75,6 @@ describe("SqlDbUtils", () => {
|
|
|
77
75
|
});
|
|
78
76
|
|
|
79
77
|
it("SqlDbUtilsExecSQL should call prepare and run", () => {
|
|
80
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
81
78
|
const Database = require("better-sqlite3");
|
|
82
79
|
const db = new Database("/tmp/test.db");
|
|
83
80
|
const mockRun = jest.fn().mockReturnValue({ changes: 5 });
|
package/src/SqlDbUtils.ts
CHANGED
|
@@ -133,7 +133,6 @@ export function SqlDbUtilsQuerySQL(
|
|
|
133
133
|
sql: string,
|
|
134
134
|
params: unknown[] = [],
|
|
135
135
|
debug = false,
|
|
136
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
137
136
|
): any[] {
|
|
138
137
|
const span = tracer.startSpan("SqlDbUtilsQuerySQL", context);
|
|
139
138
|
if (debug) {
|
package/src/users/Auth.ts
CHANGED
|
@@ -85,7 +85,6 @@ export async function AuthGenerateJWT(user: User): Promise<string> {
|
|
|
85
85
|
* mirroring the owning user's live role and scopes is built (valid until
|
|
86
86
|
* the token is revoked).
|
|
87
87
|
*/
|
|
88
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
88
|
async function jwtDecodeCached(req: any): Promise<any | null> {
|
|
90
89
|
if (req._jwtPayload) {
|
|
91
90
|
return req._jwtPayload;
|
|
@@ -115,7 +114,6 @@ async function jwtDecodeCached(req: any): Promise<any | null> {
|
|
|
115
114
|
* Permissions are read from the user record at resolution time, so
|
|
116
115
|
* role/scope changes apply to existing tokens immediately.
|
|
117
116
|
*/
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
117
|
async function resolveApiToken(authorizationHeader: string): Promise<any | null> {
|
|
120
118
|
const token = authorizationHeader.split(" ")[1];
|
|
121
119
|
if (!token) {
|
|
@@ -124,7 +122,6 @@ async function resolveApiToken(authorizationHeader: string): Promise<any | null>
|
|
|
124
122
|
const span = tracer.startSpan("AuthResolveApiToken");
|
|
125
123
|
const tokenHash = createHash("sha256").update(token).digest("hex");
|
|
126
124
|
const apiToken = await UsersApiTokensDataGetByTokenHash(span, tokenHash);
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
128
125
|
let payload: any | null = null;
|
|
129
126
|
if (apiToken) {
|
|
130
127
|
const user = await UsersDataGet(span, apiToken.userId);
|
|
@@ -142,9 +139,7 @@ async function resolveApiToken(authorizationHeader: string): Promise<any | null>
|
|
|
142
139
|
}
|
|
143
140
|
|
|
144
141
|
export async function AuthMustBeAuthenticated(
|
|
145
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
142
|
req: any,
|
|
147
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
143
|
res: any,
|
|
149
144
|
): Promise<void> {
|
|
150
145
|
if (!(await jwtDecodeCached(req))) {
|
|
@@ -153,7 +148,6 @@ export async function AuthMustBeAuthenticated(
|
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
|
|
156
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
157
151
|
export async function AuthMustBeAdmin(req: any, res: any): Promise<void> {
|
|
158
152
|
const info = await jwtDecodeCached(req);
|
|
159
153
|
if (info?.role === "admin") {
|
|
@@ -164,9 +158,7 @@ export async function AuthMustBeAdmin(req: any, res: any): Promise<void> {
|
|
|
164
158
|
}
|
|
165
159
|
|
|
166
160
|
export async function AuthHasScope(
|
|
167
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
168
161
|
req: any,
|
|
169
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
170
162
|
res: any,
|
|
171
163
|
scope: UserScope,
|
|
172
164
|
): Promise<void> {
|
|
@@ -186,7 +178,6 @@ export async function AuthHasScope(
|
|
|
186
178
|
throw new Error("Access Denied");
|
|
187
179
|
}
|
|
188
180
|
|
|
189
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
190
181
|
export async function AuthGetUserSession(req: any): Promise<UserSession> {
|
|
191
182
|
const userSession: UserSession = { isAuthenticated: false };
|
|
192
183
|
const info = await jwtDecodeCached(req);
|
package/src/users/User.ts
CHANGED
|
@@ -19,7 +19,6 @@ export class User {
|
|
|
19
19
|
/** Full scope set of the host application, registered via `AuthInit`. */
|
|
20
20
|
public static ALL_SCOPES: UserScope[] = [];
|
|
21
21
|
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
22
|
public static fromJson(json: any): User | null {
|
|
24
23
|
if (!json) {
|
|
25
24
|
return null;
|
|
@@ -55,7 +54,6 @@ export class User {
|
|
|
55
54
|
this.id = uuidv4();
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
57
|
public toJson(): any {
|
|
60
58
|
return {
|
|
61
59
|
id: this.id,
|
|
@@ -66,7 +64,6 @@ export class User {
|
|
|
66
64
|
};
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
67
|
public toTransportJson(): any {
|
|
71
68
|
return {
|
|
72
69
|
id: this.id,
|
|
@@ -10,7 +10,6 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
10
10
|
*/
|
|
11
11
|
export class UserApiToken {
|
|
12
12
|
//
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
13
|
public static fromJson(json: any): UserApiToken | null {
|
|
15
14
|
if (!json) {
|
|
16
15
|
return null;
|
|
@@ -34,7 +33,6 @@ export class UserApiToken {
|
|
|
34
33
|
this.id = uuidv4();
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
36
|
public toJson(): any {
|
|
39
37
|
return {
|
|
40
38
|
id: this.id,
|
|
@@ -46,7 +44,6 @@ export class UserApiToken {
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
// Transport representation: never exposes the token hash.
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
47
|
public toTransportJson(): any {
|
|
51
48
|
return {
|
|
52
49
|
id: this.id,
|
|
@@ -100,7 +100,6 @@ export async function UsersApiTokensDataDeleteByUser(
|
|
|
100
100
|
|
|
101
101
|
// Private Functions
|
|
102
102
|
|
|
103
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
103
|
function fromRaw(tokenRaw: any): UserApiToken {
|
|
105
104
|
const apiToken = new UserApiToken();
|
|
106
105
|
apiToken.id = tokenRaw.id;
|
package/src/users/UsersData.ts
CHANGED
package/src/users/UsersRoutes.ts
CHANGED
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
* Retrieves the OTel span attached to the request by the
|
|
31
31
|
* `@devopsplaybook.io/otel-utils-fastify` hooks.
|
|
32
32
|
*/
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
33
|
function requestSpan(req: any): Span | undefined {
|
|
35
34
|
return req?.tracerSpanApi;
|
|
36
35
|
}
|
package/tsconfig.spec.json
CHANGED
package/eslint.config.mjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import eslint from "@eslint/js";
|
|
4
|
-
import tseslint from "typescript-eslint";
|
|
5
|
-
|
|
6
|
-
export default tseslint.config(
|
|
7
|
-
{ ignores: ["dist/", "node_modules/"] },
|
|
8
|
-
eslint.configs.recommended,
|
|
9
|
-
...tseslint.configs.strict,
|
|
10
|
-
...tseslint.configs.stylistic,
|
|
11
|
-
);
|