@devopsplaybook.io/common-utils 1.10.0-beta.19.2cffff2 → 1.10.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.
Files changed (39) hide show
  1. package/.github/workflows/main-build.yml +1 -0
  2. package/.github/workflows/pr-check.yml +1 -0
  3. package/.github/workflows/reusable-npm-merge.yml +1 -1
  4. package/.github/workflows/reusable-npm-pr.yml +1 -1
  5. package/AGENTS.md +11 -6
  6. package/README.md +4 -5
  7. package/dist/src/ConfigBase.js +5 -16
  8. package/dist/src/DbUtils.js +0 -1
  9. package/dist/src/DbUtilsNoTelemetry.js +1 -5
  10. package/dist/src/LLM.js +0 -2
  11. package/dist/src/OTelContext.js +0 -1
  12. package/dist/src/PostgresDbUtils.js +5 -20
  13. package/dist/src/users/Auth.js +2 -15
  14. package/dist/src/users/User.js +0 -3
  15. package/dist/src/users/UserApiToken.js +0 -3
  16. package/dist/src/users/UsersApiTokensData.js +0 -1
  17. package/dist/src/users/UsersData.js +0 -1
  18. package/dist/src/users/UsersRoutes.js +0 -1
  19. package/jest.config.js +5 -2
  20. package/package.json +13 -15
  21. package/src/ConfigBase.spec.ts +0 -33
  22. package/src/ConfigBase.ts +4 -15
  23. package/src/DbUtils.ts +0 -2
  24. package/src/DbUtilsNoTelemetry.spec.ts +0 -6
  25. package/src/DbUtilsNoTelemetry.ts +0 -4
  26. package/src/LLM.ts +0 -2
  27. package/src/OTelContext.ts +0 -2
  28. package/src/PostgresDbUtils.spec.ts +0 -2
  29. package/src/PostgresDbUtils.ts +0 -13
  30. package/src/SqlDbUtils.spec.ts +0 -3
  31. package/src/SqlDbUtils.ts +0 -1
  32. package/src/users/Auth.ts +0 -9
  33. package/src/users/User.ts +0 -3
  34. package/src/users/UserApiToken.ts +0 -3
  35. package/src/users/UsersApiTokensData.ts +0 -1
  36. package/src/users/UsersData.ts +0 -1
  37. package/src/users/UsersRoutes.ts +0 -1
  38. package/tsconfig.spec.json +2 -1
  39. 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 }}
@@ -7,7 +7,7 @@ on:
7
7
  description: "Node.js version to use"
8
8
  required: false
9
9
  type: string
10
- default: "18"
10
+ default: "22"
11
11
  npm_package_name:
12
12
  description: "NPM package name (e.g. @devopsplaybook.io/otel-utils)"
13
13
  required: true
@@ -7,7 +7,7 @@ on:
7
7
  description: "Node.js version to use"
8
8
  required: false
9
9
  type: string
10
- default: "18"
10
+ default: "22"
11
11
  npm_package_name:
12
12
  description: "NPM package name (e.g. @devopsplaybook.io/otel-utils)"
13
13
  required: true
package/AGENTS.md CHANGED
@@ -36,19 +36,24 @@ src/
36
36
  .github/workflows/
37
37
  main-build.yml # Caller: push to main -> reusable-npm-merge
38
38
  pr-check.yml # Caller: PR to main -> reusable-npm-pr
39
- npm-upgrade.yml # Caller: weekly schedule -> reusable-npm-upgrade
40
39
  reusable-npm-merge.yml # Lint + test + build + publish release to npm
41
40
  reusable-npm-pr.yml # Lint + test + build + publish beta tag + comment PR
42
- reusable-npm-upgrade.yml # npm-check-updates + auto PR
41
+ reusable-npm-upgrade.yml # npm-check-updates + auto PR (manual, workflow_call)
43
42
  reusable-pr-verify.yml # Matrix Node.js + multi-platform Docker build -> beta-pr-<PR> and beta
44
43
  reusable-merge-build.yml # Promotes the PR image to the version tags on merge (no build/lint/test)
45
44
  ```
46
45
 
46
+ ## Weekly Dependency Updates
47
+
48
+ The scheduled `npm-upgrade.yml` caller was retired: it created dependency upgrade pull requests every week that no one merged. `reusable-npm-upgrade.yml` is kept for manual, on-demand upgrades (`workflow_call`; adopting repositories can trigger it through their own `workflow_dispatch` caller).
49
+
50
+ The weekly update of the shared npm libraries is agent-driven instead: a Kubernetes CronJob (`planner-shared-libraries-update` in the `DidierHoarau/didier-home` GitOps repository) creates a Planner task in the `Projects/xMaintenance` project every Friday, and the planner-llm-agent executes the `update-shared-libraries` skill from `DidierHoarau/planner-llm-agent-config`. The skill updates `otel-utils` first, then `otel-utils-fastify` and `common-utils` once the freshly published `otel-utils` version is visible on npm, then the consumer repositories discovered with GitHub code search. It applies minor/patch updates only (majors are reported, never applied), skips repositories already current against the npm registry, and delivers one squash-merged pull request per repository after green checks. Do not reintroduce a scheduled upgrade workflow in this repository: it would compete with the agent-driven update.
51
+
47
52
  ## Key Conventions
48
53
 
49
54
  - **TypeScript**: Target ES2019, CommonJS output, strict mode enabled, declarations generated.
50
- - **ESLint**: Uses `typescript-eslint` with `strict` and `stylistic` rule sets. Minimize `eslint-disable` comments; use them only when the type system cannot express the constraint (e.g., `@typescript-eslint/no-explicit-any` for `this as any` dynamic field access in `ConfigBase`).
51
- - **Tests**: Jest with `ts-jest`. Spec files live next to source (`*.spec.ts`). Run with `npm run test`. The `tsconfig.spec.json` includes jest types.
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`).
52
57
  - **No default exports**: All modules use named exports only.
53
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.
54
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.
@@ -63,7 +68,7 @@ src/
63
68
  ```bash
64
69
  npm install
65
70
  npm run build # tsc -> dist/
66
- npm run lint # eslint src (must pass with 0 errors)
71
+ npm run lint # oxlint src (must pass with 0 errors)
67
72
  npm run test # jest --coverage (all tests must pass)
68
73
  ```
69
74
 
@@ -86,7 +91,7 @@ All three commands must pass before committing. The CI pipeline (`reusable-npm-m
86
91
 
87
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'`.
88
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.
89
- - **eslint-disable placement**: `eslint-disable-next-line` applies to the **immediately following line only**. When disabling a rule inside a function call argument, place the comment directly before the offending expression, not before the function call.
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.
90
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.
91
96
 
92
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 | `"18"` | Node.js version |
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 |
@@ -607,13 +607,12 @@ jobs:
607
607
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
608
608
  ```
609
609
 
610
- And `.github/workflows/npm-upgrade.yml` for weekly dependency updates:
610
+ And `.github/workflows/npm-upgrade.yml` for manual dependency upgrades (the weekly update of the shared devopsplaybook.io libraries is agent-driven — see the AGENTS.md of this repository — so no schedule trigger is used):
611
611
 
612
612
  ```yaml
613
613
  name: NPM Upgrade
614
614
  on:
615
- schedule:
616
- - cron: "0 6 * * 1" # Monday 6am UTC
615
+ workflow_dispatch:
617
616
  jobs:
618
617
  npm-upgrade:
619
618
  uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-upgrade.yml@main
@@ -631,7 +630,7 @@ jobs:
631
630
  ```bash
632
631
  npm install
633
632
  npm run build # TypeScript compilation -> dist/
634
- npm run lint # ESLint (strict + stylistic)
633
+ npm run lint # oxlint (recommended preset)
635
634
  npm run test # Jest with coverage
636
635
  ```
637
636
 
@@ -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;
@@ -139,17 +138,13 @@ class ConfigBase {
139
138
  this._fields = [];
140
139
  this.SERVICE_ID = serviceId;
141
140
  this.CONFIG_FILE = configFile || process.env.CONFIG_FILE || "config.json";
142
- // Auto-detect the host application version from its package.json.
143
- // Services run with their project root as the current working
144
- // directory, so <cwd>/package.json is the host app's manifest. The
145
- // installed library's own package.json is deliberately not used: it
146
- // would report the library version, not the service version.
141
+ // Auto-detect version from nearest package.json
147
142
  try {
148
- const pkg = fse.readJsonSync(path_1.default.resolve(process.cwd(), "package.json"));
143
+ const pkg = fse.readJsonSync(path_1.default.resolve(__dirname, "../package.json"));
149
144
  if (pkg && pkg.version) {
150
145
  this.VERSION = pkg.version;
151
146
  }
152
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
147
+ // eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
153
148
  }
154
149
  catch (_e) {
155
150
  // fallback to "1"
@@ -200,7 +195,6 @@ class ConfigBase {
200
195
  field: def.field,
201
196
  sensitive: (_a = def.sensitive) !== null && _a !== void 0 ? _a : false,
202
197
  envAliases: (_b = def.envAliases) !== null && _b !== void 0 ? _b : [],
203
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
198
  defaultValue: this[def.field],
205
199
  });
206
200
  }
@@ -212,12 +206,11 @@ class ConfigBase {
212
206
  * When omitted nothing is logged (useful in tests).
213
207
  */
214
208
  async reload(logger) {
215
- // eslint-disable-next-line @typescript-eslint/no-empty-function
216
209
  const log = logger !== null && logger !== void 0 ? logger : (() => { });
217
210
  let content = {};
218
211
  try {
219
212
  content = await fse.readJson(this.CONFIG_FILE);
220
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
213
+ // eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
221
214
  }
222
215
  catch (_e) {
223
216
  // config file is optional – fall back to env + defaults
@@ -248,13 +241,11 @@ class ConfigBase {
248
241
  // 3. Apply environment value (full name or alias) if found,
249
242
  // coercing strings to match the default value type
250
243
  if (foundValue !== undefined) {
251
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
244
  this[field] = coerceValue(foundValue, defaultValue);
253
245
  }
254
246
  // 4. Config file override (environment always wins, but if neither
255
247
  // environment nor alias matched, check config file)
256
248
  if (foundValue === undefined && content[field] !== undefined) {
257
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
249
  this[field] = content[field];
259
250
  from = "config";
260
251
  }
@@ -262,9 +253,7 @@ class ConfigBase {
262
253
  log(`Configuration Value: ${field}: ******************** (from ${from})`);
263
254
  }
264
255
  else {
265
- log(
266
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
267
- `Configuration Value: ${field}: ${this[field]} (from ${from}${usedAlias ? ` via alias` : ""})`);
256
+ log(`Configuration Value: ${field}: ${this[field]} (from ${from}${usedAlias ? ` via alias` : ""})`);
268
257
  }
269
258
  }
270
259
  }
@@ -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;
@@ -36,7 +36,6 @@ function createOTelContext() {
36
36
  }
37
37
  return logger;
38
38
  },
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
39
  OTelRequestSpan: (req) => req === null || req === void 0 ? void 0 : req.tracerSpanApi,
41
40
  };
42
41
  }
@@ -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) {
@@ -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);
@@ -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;
@@ -86,7 +86,6 @@ async function UsersDataDelete(context, id) {
86
86
  span.end();
87
87
  }
88
88
  // Private Functions
89
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
89
  function fromRaw(userRaw) {
91
90
  const user = new User_1.User();
92
91
  user.id = userRaw.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
- "ts-jest",
5
+ "@swc/jest",
6
6
  {
7
- tsconfig: "tsconfig.spec.json",
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.10.0-beta.19.2cffff2",
3
+ "version": "1.10.0",
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,39 +21,37 @@
21
21
  "main": "dist/index.js",
22
22
  "types": "dist/index.d.ts",
23
23
  "scripts": {
24
- "build": "tsc",
25
- "lint": "eslint src",
24
+ "build": "tsc && tsc -p tsconfig.spec.json --noEmit",
25
+ "lint": "oxlint src",
26
26
  "test": "jest --coverage"
27
27
  },
28
28
  "dependencies": {
29
- "@devopsplaybook.io/otel-utils": "^1.1.2",
29
+ "@devopsplaybook.io/otel-utils": "^1.1.5",
30
30
  "@opentelemetry/api": "^1.9.1",
31
- "@opentelemetry/sdk-trace-base": "^2.10.0",
32
- "axios": "^1.19.0",
31
+ "@opentelemetry/sdk-trace-base": "^2.11.0",
32
+ "axios": "^1.20.0",
33
33
  "bcrypt": "^6.0.0",
34
34
  "better-sqlite3": "^13.0.3",
35
- "fastify": "^5.12.1",
35
+ "fastify": "^5.12.5",
36
36
  "fs-extra": "^11.4.0",
37
37
  "jsonwebtoken": "^9.0.3",
38
38
  "pg": "^8.23.0",
39
39
  "uuid": "^14.0.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@eslint/js": "^10.0.1",
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",
46
47
  "@types/jest": "^30.0.0",
47
48
  "@types/jsonwebtoken": "^9.0.10",
48
- "@types/node": "^26.2.0",
49
+ "@types/node": "^26.6.2",
49
50
  "@types/pg": "^8.23.1",
50
51
  "@types/uuid": "^11.0.0",
51
- "eslint": "^10.9.0",
52
- "jest": "^30.4.2",
53
- "ts-jest": "^29.4.12",
54
- "ts-node": "^10.9.2",
55
- "typescript": "^6.0.3",
56
- "typescript-eslint": "^8.67.0"
52
+ "jest": "^30.5.2",
53
+ "oxlint": "^1.83.0",
54
+ "typescript": "^7.0.2"
57
55
  },
58
56
  "publishConfig": {
59
57
  "access": "public"
@@ -105,37 +105,4 @@ describe("ConfigBase", () => {
105
105
  await config.reload();
106
106
  expect(config.DATABASE_TYPE).toBe("postgres");
107
107
  });
108
-
109
- describe("VERSION detection", () => {
110
- let cwdSpy: jest.SpyInstance;
111
-
112
- afterEach(() => {
113
- cwdSpy.mockRestore();
114
- });
115
-
116
- it("should detect VERSION from a package.json in the working directory", () => {
117
- fse.writeJsonSync(path.join(tmpDir, "package.json"), {
118
- name: "host-app",
119
- version: "3.2.1",
120
- });
121
- cwdSpy = jest.spyOn(process, "cwd").mockReturnValue(tmpDir);
122
- const config = new TestConfig(configPath);
123
- expect(config.VERSION).toBe("3.2.1");
124
- });
125
-
126
- it("should fall back to VERSION '1' when the working directory has no package.json", () => {
127
- cwdSpy = jest.spyOn(process, "cwd").mockReturnValue(tmpDir);
128
- const config = new TestConfig(configPath);
129
- expect(config.VERSION).toBe("1");
130
- });
131
-
132
- it("should fall back to VERSION '1' when package.json has no version field", () => {
133
- fse.writeJsonSync(path.join(tmpDir, "package.json"), {
134
- name: "host-app",
135
- });
136
- cwdSpy = jest.spyOn(process, "cwd").mockReturnValue(tmpDir);
137
- const config = new TestConfig(configPath);
138
- expect(config.VERSION).toBe("1");
139
- });
140
- });
141
108
  });
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
 
@@ -167,17 +165,13 @@ export abstract class ConfigBase implements ConfigCommonInterface {
167
165
  this.SERVICE_ID = serviceId;
168
166
  this.CONFIG_FILE = configFile || process.env.CONFIG_FILE || "config.json";
169
167
 
170
- // Auto-detect the host application version from its package.json.
171
- // Services run with their project root as the current working
172
- // directory, so <cwd>/package.json is the host app's manifest. The
173
- // installed library's own package.json is deliberately not used: it
174
- // would report the library version, not the service version.
168
+ // Auto-detect version from nearest package.json
175
169
  try {
176
- const pkg = fse.readJsonSync(path.resolve(process.cwd(), "package.json"));
170
+ const pkg = fse.readJsonSync(path.resolve(__dirname, "../package.json"));
177
171
  if (pkg && pkg.version) {
178
172
  this.VERSION = pkg.version;
179
173
  }
180
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
174
+ // eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
181
175
  } catch (_e) {
182
176
  // fallback to "1"
183
177
  }
@@ -228,7 +222,6 @@ export abstract class ConfigBase implements ConfigCommonInterface {
228
222
  field: def.field,
229
223
  sensitive: def.sensitive ?? false,
230
224
  envAliases: def.envAliases ?? [],
231
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
232
225
  defaultValue: (this as any)[def.field],
233
226
  });
234
227
  }
@@ -241,12 +234,11 @@ export abstract class ConfigBase implements ConfigCommonInterface {
241
234
  * When omitted nothing is logged (useful in tests).
242
235
  */
243
236
  public async reload(logger?: (message: string) => void): Promise<void> {
244
- // eslint-disable-next-line @typescript-eslint/no-empty-function
245
237
  const log = logger ?? (() => {});
246
238
  let content: Record<string, unknown> = {};
247
239
  try {
248
240
  content = await fse.readJson(this.CONFIG_FILE);
249
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
241
+ // eslint-disable-next-line no-unused-vars -- catch binding kept so dist/ stays byte-identical to the TS6 build
250
242
  } catch (_e) {
251
243
  // config file is optional – fall back to env + defaults
252
244
  }
@@ -281,14 +273,12 @@ export abstract class ConfigBase implements ConfigCommonInterface {
281
273
  // 3. Apply environment value (full name or alias) if found,
282
274
  // coercing strings to match the default value type
283
275
  if (foundValue !== undefined) {
284
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
285
276
  (this as any)[field] = coerceValue(foundValue, defaultValue);
286
277
  }
287
278
 
288
279
  // 4. Config file override (environment always wins, but if neither
289
280
  // environment nor alias matched, check config file)
290
281
  if (foundValue === undefined && content[field] !== undefined) {
291
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
292
282
  (this as any)[field] = content[field];
293
283
  from = "config";
294
284
  }
@@ -299,7 +289,6 @@ export abstract class ConfigBase implements ConfigCommonInterface {
299
289
  );
300
290
  } else {
301
291
  log(
302
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
303
292
  `Configuration Value: ${field}: ${(this as any)[field]} (from ${from}${usedAlias ? ` via alias` : ""})`,
304
293
  );
305
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;
@@ -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(
@@ -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) {
@@ -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;
@@ -109,7 +109,6 @@ export async function UsersDataDelete(
109
109
 
110
110
  // Private Functions
111
111
 
112
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
112
  function fromRaw(userRaw: any): User {
114
113
  const user = new User();
115
114
  user.id = userRaw.id;
@@ -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
  }
@@ -3,5 +3,6 @@
3
3
  "compilerOptions": {
4
4
  "types": ["jest", "node"]
5
5
  },
6
- "include": ["src/**/*.spec.ts"]
6
+ "include": ["src/**/*.spec.ts"],
7
+ "exclude": []
7
8
  }
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
- );