@devopsplaybook.io/common-utils 1.10.1-beta.23.b1906d7 → 1.11.0-beta.24.d8f9aef

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 (69) hide show
  1. package/README.md +73 -27
  2. package/dist/src/ConfigBase.d.ts +31 -0
  3. package/dist/src/ConfigBase.js +58 -16
  4. package/dist/src/DbUtils.d.ts +20 -3
  5. package/dist/src/DbUtils.js +93 -2
  6. package/dist/src/DbUtilsNoTelemetry.d.ts +4 -1
  7. package/dist/src/DbUtilsNoTelemetry.js +62 -6
  8. package/dist/src/PostgresDbUtils.d.ts +41 -10
  9. package/dist/src/PostgresDbUtils.js +357 -304
  10. package/dist/src/SqlDbUtils.d.ts +12 -4
  11. package/dist/src/SqlDbUtils.js +76 -30
  12. package/dist/src/users/Auth.d.ts +11 -1
  13. package/dist/src/users/Auth.js +160 -44
  14. package/dist/src/users/User.d.ts +10 -0
  15. package/dist/src/users/User.js +30 -10
  16. package/dist/src/users/UserApiToken.d.ts +4 -0
  17. package/dist/src/users/UserApiToken.js +11 -0
  18. package/dist/src/users/UsersApiTokensData.d.ts +12 -0
  19. package/dist/src/users/UsersApiTokensData.js +130 -33
  20. package/dist/src/users/UsersData.d.ts +20 -1
  21. package/dist/src/users/UsersData.js +150 -52
  22. package/dist/src/users/UsersRoutes.js +178 -61
  23. package/dist/src/users/index.d.ts +8 -0
  24. package/dist/src/users/index.js +24 -0
  25. package/package.json +58 -1
  26. package/.github/workflows/main-build.yml +0 -18
  27. package/.github/workflows/pr-check.yml +0 -27
  28. package/.github/workflows/reusable-merge-build.yml +0 -197
  29. package/.github/workflows/reusable-npm-merge.yml +0 -135
  30. package/.github/workflows/reusable-npm-pr.yml +0 -183
  31. package/.github/workflows/reusable-npm-upgrade.yml +0 -92
  32. package/.github/workflows/reusable-pr-verify.yml +0 -181
  33. package/AGENTS.md +0 -105
  34. package/index.ts +0 -18
  35. package/jest.config.js +0 -17
  36. package/prettierrc.json +0 -5
  37. package/src/ConfigBase.spec.ts +0 -108
  38. package/src/ConfigBase.ts +0 -297
  39. package/src/DbUtils.spec.ts +0 -23
  40. package/src/DbUtils.ts +0 -116
  41. package/src/DbUtilsNoTelemetry.spec.ts +0 -168
  42. package/src/DbUtilsNoTelemetry.ts +0 -117
  43. package/src/LLM.spec.ts +0 -303
  44. package/src/LLM.ts +0 -204
  45. package/src/Notifications.spec.ts +0 -265
  46. package/src/Notifications.ts +0 -201
  47. package/src/OTelContext.spec.ts +0 -58
  48. package/src/OTelContext.ts +0 -63
  49. package/src/PostgresDbUtils.spec.ts +0 -153
  50. package/src/PostgresDbUtils.ts +0 -666
  51. package/src/SqlDbUtils.spec.ts +0 -108
  52. package/src/SqlDbUtils.ts +0 -152
  53. package/src/SystemCommand.spec.ts +0 -18
  54. package/src/SystemCommand.ts +0 -23
  55. package/src/Timeout.spec.ts +0 -18
  56. package/src/Timeout.ts +0 -12
  57. package/src/users/Auth.spec.ts +0 -268
  58. package/src/users/Auth.ts +0 -202
  59. package/src/users/User.ts +0 -75
  60. package/src/users/UserApiToken.ts +0 -55
  61. package/src/users/UserPassword.spec.ts +0 -28
  62. package/src/users/UserPassword.ts +0 -20
  63. package/src/users/UserSession.ts +0 -9
  64. package/src/users/UsersApiTokensData.spec.ts +0 -158
  65. package/src/users/UsersApiTokensData.ts +0 -125
  66. package/src/users/UsersData.ts +0 -141
  67. package/src/users/UsersRoutes.ts +0 -374
  68. package/tsconfig.json +0 -15
  69. package/tsconfig.spec.json +0 -8
@@ -2,13 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UsersRoutes = void 0;
4
4
  const crypto_1 = require("crypto");
5
- const uuid_1 = require("uuid");
6
5
  const Auth_1 = require("./Auth");
6
+ const DbUtils_1 = require("../DbUtils");
7
7
  const User_1 = require("./User");
8
8
  const UserApiToken_1 = require("./UserApiToken");
9
9
  const UserPassword_1 = require("./UserPassword");
10
10
  const UsersData_1 = require("./UsersData");
11
11
  const UsersApiTokensData_1 = require("./UsersApiTokensData");
12
+ /** Maximum accepted API token name length. */
13
+ const API_TOKEN_NAME_MAX_LENGTH = 255;
12
14
  /**
13
15
  * Retrieves the OTel span attached to the request by the
14
16
  * `@devopsplaybook.io/otel-utils-fastify` hooks.
@@ -16,6 +18,17 @@ const UsersApiTokensData_1 = require("./UsersApiTokensData");
16
18
  function requestSpan(req) {
17
19
  return req === null || req === void 0 ? void 0 : req.tracerSpanApi;
18
20
  }
21
+ /** Parse an optional non-negative integer query parameter. */
22
+ function parseNonNegativeInt(value) {
23
+ if (value === undefined || value === null || value === "") {
24
+ return undefined;
25
+ }
26
+ const parsed = Number(value);
27
+ if (!Number.isInteger(parsed) || parsed < 0) {
28
+ return undefined;
29
+ }
30
+ return parsed;
31
+ }
19
32
  /**
20
33
  * Standard user management routes shared across applications:
21
34
  * initialization status, login (session), user CRUD and password changes.
@@ -30,14 +43,12 @@ class UsersRoutes {
30
43
  async getRoutes(fastify) {
31
44
  //
32
45
  fastify.get("/status/initialization", async (req, res) => {
33
- if ((await (0, UsersData_1.UsersDataList)(requestSpan(req))).length === 0) {
34
- res.status(201).send({ initialized: false });
35
- }
36
- else {
37
- res.status(201).send({ initialized: true });
38
- }
46
+ const count = await (0, UsersData_1.UsersDataCount)(requestSpan(req));
47
+ return res.status(200).send({ initialized: count > 0 });
39
48
  });
40
49
  fastify.post("/session", async (req, res) => {
50
+ var _a;
51
+ const body = (_a = req.body) !== null && _a !== void 0 ? _a : {};
41
52
  let user;
42
53
  // From token
43
54
  const userSession = await (0, Auth_1.AuthGetUserSession)(req);
@@ -54,17 +65,17 @@ class UsersRoutes {
54
65
  });
55
66
  }
56
67
  // From User/Pass
57
- if (!req.body.name) {
68
+ if (!body.name) {
58
69
  return res.status(400).send({ error: "Missing: Name" });
59
70
  }
60
- if (!req.body.password) {
71
+ if (!body.password) {
61
72
  return res.status(400).send({ error: "Missing: Password" });
62
73
  }
63
- user = await (0, UsersData_1.UsersDataGetByName)(requestSpan(req), req.body.name);
74
+ user = await (0, UsersData_1.UsersDataGetByName)(requestSpan(req), body.name);
64
75
  if (!user) {
65
76
  return res.status(403).send({ error: "Authentication Failed" });
66
77
  }
67
- else if (await (0, UserPassword_1.UserPasswordCheckPassword)(requestSpan(req), user, req.body.password)) {
78
+ else if (await (0, UserPassword_1.UserPasswordCheckPassword)(requestSpan(req), user, body.password)) {
68
79
  return res.status(201).send({
69
80
  success: true,
70
81
  token: await (0, Auth_1.AuthGenerateJWT)(user),
@@ -77,58 +88,96 @@ class UsersRoutes {
77
88
  });
78
89
  // ==================== LIST USERS (Admin only) ====================
79
90
  fastify.get("/", async (req, res) => {
91
+ var _a;
80
92
  try {
81
93
  await (0, Auth_1.AuthMustBeAdmin)(req, res);
82
94
  }
83
95
  catch {
84
96
  return;
85
97
  }
86
- const users = await (0, UsersData_1.UsersDataList)(requestSpan(req));
98
+ const query = ((_a = req.query) !== null && _a !== void 0 ? _a : {});
99
+ const limit = parseNonNegativeInt(query.limit);
100
+ const offset = parseNonNegativeInt(query.offset);
101
+ if (query.limit !== undefined && limit === undefined) {
102
+ return res.status(400).send({ error: "Invalid: limit" });
103
+ }
104
+ if (query.offset !== undefined && offset === undefined) {
105
+ return res.status(400).send({ error: "Invalid: offset" });
106
+ }
107
+ const users = await (0, UsersData_1.UsersDataList)(requestSpan(req), limit, offset);
87
108
  return res.status(200).send(users.map((u) => u.toTransportJson()));
88
109
  });
89
110
  fastify.post("/", async (req, res) => {
111
+ var _a;
90
112
  const context = requestSpan(req);
91
- let isInitialized = true;
92
- if ((await (0, UsersData_1.UsersDataList)(context)).length === 0) {
93
- isInitialized = false;
94
- }
95
- // If initialized, only admin can create users
96
- if (isInitialized) {
113
+ const body = (_a = req.body) !== null && _a !== void 0 ? _a : {};
114
+ const createUser = async (isFirstUser) => {
115
+ if (!body.name) {
116
+ return res.status(400).send({ error: "Missing: Name" });
117
+ }
118
+ if (!body.password) {
119
+ return res.status(400).send({ error: "Missing: Password" });
120
+ }
121
+ if (await (0, UsersData_1.UsersDataGetByName)(context, body.name)) {
122
+ return res.status(400).send({ error: "Username Already Exists" });
123
+ }
124
+ const newUser = new User_1.User();
125
+ newUser.name = body.name;
126
+ // First user is always admin
127
+ if (isFirstUser) {
128
+ newUser.role = "admin";
129
+ newUser.scopes = [...User_1.User.ALL_SCOPES];
130
+ }
131
+ else {
132
+ newUser.role = body.role === "admin" ? "admin" : "user";
133
+ if (body.scopes && Array.isArray(body.scopes)) {
134
+ newUser.scopes = body.scopes.filter((s) => User_1.User.ALL_SCOPES.includes(s));
135
+ }
136
+ }
137
+ await (0, UserPassword_1.UserPasswordSetPassword)(context, newUser, body.password);
138
+ try {
139
+ await (0, UsersData_1.UsersDataAdd)(context, newUser);
140
+ }
141
+ catch (error) {
142
+ // Uniqueness also holds when the pre-check races another request
143
+ // (unique index on LOWER("name") – see README migration).
144
+ if ((0, UsersData_1.isUniqueViolationError)(error)) {
145
+ return res.status(400).send({ error: "Username Already Exists" });
146
+ }
147
+ throw error;
148
+ }
149
+ return res.status(201).send({ user: newUser.toTransportJson() });
150
+ };
151
+ if ((await (0, UsersData_1.UsersDataCount)(context)) > 0) {
152
+ // If initialized, only admin can create users
97
153
  try {
98
154
  await (0, Auth_1.AuthMustBeAdmin)(req, res);
99
155
  }
100
156
  catch {
101
157
  return;
102
158
  }
159
+ return createUser(false);
103
160
  }
104
- if (!req.body.name) {
105
- return res.status(400).send({ error: "Missing: Name" });
106
- }
107
- if (!req.body.password) {
108
- return res.status(400).send({ error: "Missing: Password" });
109
- }
110
- if (await (0, UsersData_1.UsersDataGetByName)(context, req.body.name)) {
111
- return res.status(400).send({ error: "Username Already Exists" });
112
- }
113
- const newUser = new User_1.User();
114
- newUser.name = req.body.name;
115
- // First user is always admin
116
- if (isInitialized) {
117
- newUser.role = req.body.role === "admin" ? "admin" : "user";
118
- if (req.body.scopes && Array.isArray(req.body.scopes)) {
119
- newUser.scopes = req.body.scopes.filter((s) => User_1.User.ALL_SCOPES.includes(s));
161
+ // Bootstrap: serialise the "no user yet → first admin" sequence across
162
+ // replicas (advisory lock on Postgres; single writer on SQLite).
163
+ return (0, DbUtils_1.DbUtilsWithLock)("users_bootstrap", async () => {
164
+ if ((await (0, UsersData_1.UsersDataCount)(context)) === 0) {
165
+ return createUser(true);
120
166
  }
121
- }
122
- else {
123
- newUser.role = "admin";
124
- newUser.scopes = [...User_1.User.ALL_SCOPES];
125
- }
126
- await (0, UserPassword_1.UserPasswordSetPassword)(context, newUser, req.body.password);
127
- await (0, UsersData_1.UsersDataAdd)(context, newUser);
128
- res.status(201).send({ user: newUser.toTransportJson() });
167
+ // Another replica bootstrapped first: require admin credentials.
168
+ try {
169
+ await (0, Auth_1.AuthMustBeAdmin)(req, res);
170
+ }
171
+ catch {
172
+ return;
173
+ }
174
+ return createUser(false);
175
+ });
129
176
  });
130
177
  fastify.put("/password", async (req, res) => {
178
+ var _a;
131
179
  const context = requestSpan(req);
180
+ const body = (_a = req.body) !== null && _a !== void 0 ? _a : {};
132
181
  const userSession = await (0, Auth_1.AuthGetUserSession)(req);
133
182
  if (!userSession.isAuthenticated) {
134
183
  return res.status(403).send({ error: "Access Denied" });
@@ -138,41 +187,75 @@ class UsersRoutes {
138
187
  if (!user) {
139
188
  return res.status(403).send({ error: "Access Denied" });
140
189
  }
141
- if (!req.body.password) {
190
+ if (!body.password) {
142
191
  return res.status(400).send({ error: "Missing: Password" });
143
192
  }
144
- if (!(await (0, UserPassword_1.UserPasswordCheckPassword)(context, user, req.body.passwordOld))) {
193
+ if (!(await (0, UserPassword_1.UserPasswordCheckPassword)(context, user, body.passwordOld))) {
145
194
  return res.status(403).send({ error: "Old Password Wrong" });
146
195
  }
147
- await (0, UserPassword_1.UserPasswordSetPassword)(context, user, req.body.password);
196
+ await (0, UserPassword_1.UserPasswordSetPassword)(context, user, body.password);
148
197
  await (0, UsersData_1.UsersDataUpdatePassword)(context, user);
149
- res.status(201).send({});
198
+ if ((0, Auth_1.AuthJwtRevocationEnabled)()) {
199
+ await (0, UsersData_1.UsersDataBumpTokenVersion)(context, user.id);
200
+ }
201
+ return res.status(201).send({});
150
202
  });
151
203
  fastify.put("/:id", async (req, res) => {
204
+ var _a;
152
205
  const context = requestSpan(req);
206
+ const body = (_a = req.body) !== null && _a !== void 0 ? _a : {};
153
207
  try {
154
208
  await (0, Auth_1.AuthMustBeAdmin)(req, res);
155
209
  }
156
210
  catch {
157
211
  return;
158
212
  }
213
+ // A body expecting nothing to change is malformed: answer 400, not 404/201
214
+ if (body.role === undefined &&
215
+ body.scopes === undefined &&
216
+ body.password === undefined) {
217
+ return res.status(400).send({ error: "Missing: Body" });
218
+ }
159
219
  const user = await (0, UsersData_1.UsersDataGet)(context, req.params.id);
160
220
  if (!user) {
161
221
  return res.status(404).send({ error: "User Not Found" });
162
222
  }
163
- if (req.body.role) {
164
- user.role = req.body.role === "admin" ? "admin" : "user";
223
+ let changed = false;
224
+ if (body.role) {
225
+ const newRole = body.role === "admin" ? "admin" : "user";
226
+ if (newRole !== user.role) {
227
+ // At least 1 admin must remain (mirrors the delete guard)
228
+ if (user.role === "admin" &&
229
+ newRole === "user" &&
230
+ (await (0, UsersData_1.UsersDataCountAdmins)(context)) <= 1) {
231
+ return res
232
+ .status(400)
233
+ .send({ error: "At least 1 admin must be defined" });
234
+ }
235
+ user.role = newRole;
236
+ changed = true;
237
+ }
238
+ }
239
+ if (body.scopes && Array.isArray(body.scopes)) {
240
+ const newScopes = body.scopes.filter((s) => User_1.User.ALL_SCOPES.includes(s));
241
+ if (JSON.stringify(newScopes) !== JSON.stringify(user.scopes)) {
242
+ user.scopes = newScopes;
243
+ changed = true;
244
+ }
165
245
  }
166
- if (req.body.scopes && Array.isArray(req.body.scopes)) {
167
- user.scopes = req.body.scopes.filter((s) => User_1.User.ALL_SCOPES.includes(s));
246
+ if (changed) {
247
+ await (0, UsersData_1.UsersDataUpdateUser)(context, user);
168
248
  }
169
- await (0, UsersData_1.UsersDataUpdateUser)(context, user);
170
249
  // If password change requested
171
- if (req.body.password) {
172
- await (0, UserPassword_1.UserPasswordSetPassword)(context, user, req.body.password);
250
+ if (body.password) {
251
+ await (0, UserPassword_1.UserPasswordSetPassword)(context, user, body.password);
173
252
  await (0, UsersData_1.UsersDataUpdatePassword)(context, user);
253
+ changed = true;
254
+ }
255
+ if (changed && (0, Auth_1.AuthJwtRevocationEnabled)()) {
256
+ await (0, UsersData_1.UsersDataBumpTokenVersion)(context, user.id);
174
257
  }
175
- res.status(201).send({ user: user.toTransportJson() });
258
+ return res.status(201).send({ user: user.toTransportJson() });
176
259
  });
177
260
  fastify.delete("/:id", async (req, res) => {
178
261
  const context = requestSpan(req);
@@ -193,8 +276,8 @@ class UsersRoutes {
193
276
  }
194
277
  // Check that at least 1 admin remains
195
278
  if (user.role === "admin") {
196
- const admins = (await (0, UsersData_1.UsersDataList)(context)).filter((u) => u.role === "admin");
197
- if (admins.length <= 1) {
279
+ const admins = await (0, UsersData_1.UsersDataCountAdmins)(context);
280
+ if (admins <= 1) {
198
281
  return res
199
282
  .status(400)
200
283
  .send({ error: "At least 1 admin must be defined" });
@@ -202,23 +285,57 @@ class UsersRoutes {
202
285
  }
203
286
  await (0, UsersData_1.UsersDataDelete)(context, req.params.id);
204
287
  await (0, UsersApiTokensData_1.UsersApiTokensDataDeleteByUser)(context, req.params.id);
205
- res.status(201).send({});
288
+ return res.status(200).send({});
206
289
  });
207
290
  fastify.post("/tokens", async (req, res) => {
291
+ var _a;
208
292
  const context = requestSpan(req);
293
+ const body = (_a = req.body) !== null && _a !== void 0 ? _a : {};
209
294
  const userSession = await (0, Auth_1.AuthGetUserSession)(req);
210
295
  if (!userSession.isAuthenticated) {
211
296
  return res.status(403).send({ error: "Access Denied" });
212
297
  }
213
- if (!req.body || !req.body.name) {
298
+ if (!body.name || typeof body.name !== "string") {
214
299
  return res.status(400).send({ error: "Missing: Name" });
215
300
  }
301
+ if (body.name.length > API_TOKEN_NAME_MAX_LENGTH) {
302
+ return res.status(400).send({
303
+ error: `Name Too Long (max ${API_TOKEN_NAME_MAX_LENGTH} characters)`,
304
+ });
305
+ }
306
+ let expiresAt = null;
307
+ if (body.expiresAt !== undefined && body.expiresAt !== null) {
308
+ const parsed = Date.parse(body.expiresAt);
309
+ if (!Number.isFinite(parsed)) {
310
+ return res
311
+ .status(400)
312
+ .send({ error: "Invalid: expiresAt (ISO 8601 date expected)" });
313
+ }
314
+ if (parsed <= Date.now()) {
315
+ return res
316
+ .status(400)
317
+ .send({ error: "Invalid: expiresAt must be in the future" });
318
+ }
319
+ if (!(await (0, UsersApiTokensData_1.UsersApiTokensDataSupportsOptionalColumns)(context))) {
320
+ return res.status(400).send({
321
+ error: "API token expiry requires the documented users_api_tokens migration",
322
+ });
323
+ }
324
+ expiresAt = new Date(parsed).toISOString();
325
+ }
326
+ const maxTokens = (0, Auth_1.AuthGetApiTokensMaxPerUser)();
327
+ if ((await (0, UsersApiTokensData_1.UsersApiTokensDataCountByUser)(context, userSession.userId)) >= maxTokens) {
328
+ return res
329
+ .status(400)
330
+ .send({ error: `Too many API tokens (max ${maxTokens})` });
331
+ }
216
332
  const apiToken = new UserApiToken_1.UserApiToken();
217
- apiToken.name = req.body.name;
333
+ apiToken.name = body.name;
218
334
  // isAuthenticated implies userId is set
219
335
  apiToken.userId = userSession.userId;
220
336
  apiToken.dateCreated = new Date().toISOString();
221
- const token = (0, uuid_1.v4)();
337
+ apiToken.expiresAt = expiresAt;
338
+ const token = (0, crypto_1.randomBytes)(32).toString("base64url");
222
339
  apiToken.tokenHash = (0, crypto_1.createHash)("sha256").update(token).digest("hex");
223
340
  await (0, UsersApiTokensData_1.UsersApiTokensDataAdd)(context, apiToken);
224
341
  // The plaintext token is returned once; only its hash is stored.
@@ -254,7 +371,7 @@ class UsersRoutes {
254
371
  return res.status(403).send({ error: "Access Denied" });
255
372
  }
256
373
  await (0, UsersApiTokensData_1.UsersApiTokensDataDelete)(context, apiToken.id);
257
- return res.status(201).send({});
374
+ return res.status(200).send({});
258
375
  });
259
376
  }
260
377
  }
@@ -0,0 +1,8 @@
1
+ export * from "./User";
2
+ export * from "./UserSession";
3
+ export * from "./UserApiToken";
4
+ export * from "./Auth";
5
+ export * from "./UserPassword";
6
+ export * from "./UsersData";
7
+ export * from "./UsersApiTokensData";
8
+ export * from "./UsersRoutes";
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./User"), exports);
18
+ __exportStar(require("./UserSession"), exports);
19
+ __exportStar(require("./UserApiToken"), exports);
20
+ __exportStar(require("./Auth"), exports);
21
+ __exportStar(require("./UserPassword"), exports);
22
+ __exportStar(require("./UsersData"), exports);
23
+ __exportStar(require("./UsersApiTokensData"), exports);
24
+ __exportStar(require("./UsersRoutes"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devopsplaybook.io/common-utils",
3
- "version": "1.10.1-beta.23.b1906d7",
3
+ "version": "1.11.0-beta.24.d8f9aef",
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",
@@ -20,6 +20,63 @@
20
20
  "type": "commonjs",
21
21
  "main": "dist/index.js",
22
22
  "types": "dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "./package.json": "./package.json",
29
+ "./otel": {
30
+ "types": "./dist/src/OTelContext.d.ts",
31
+ "default": "./dist/src/OTelContext.js"
32
+ },
33
+ "./config": {
34
+ "types": "./dist/src/ConfigBase.d.ts",
35
+ "default": "./dist/src/ConfigBase.js"
36
+ },
37
+ "./db": {
38
+ "types": "./dist/src/DbUtils.d.ts",
39
+ "default": "./dist/src/DbUtils.js"
40
+ },
41
+ "./db/sqlite": {
42
+ "types": "./dist/src/SqlDbUtils.d.ts",
43
+ "default": "./dist/src/SqlDbUtils.js"
44
+ },
45
+ "./db/postgres": {
46
+ "types": "./dist/src/PostgresDbUtils.d.ts",
47
+ "default": "./dist/src/PostgresDbUtils.js"
48
+ },
49
+ "./db/no-telemetry": {
50
+ "types": "./dist/src/DbUtilsNoTelemetry.d.ts",
51
+ "default": "./dist/src/DbUtilsNoTelemetry.js"
52
+ },
53
+ "./users": {
54
+ "types": "./dist/src/users/index.d.ts",
55
+ "default": "./dist/src/users/index.js"
56
+ },
57
+ "./notifications": {
58
+ "types": "./dist/src/Notifications.d.ts",
59
+ "default": "./dist/src/Notifications.js"
60
+ },
61
+ "./llm": {
62
+ "types": "./dist/src/LLM.d.ts",
63
+ "default": "./dist/src/LLM.js"
64
+ },
65
+ "./system": {
66
+ "types": "./dist/src/SystemCommand.d.ts",
67
+ "default": "./dist/src/SystemCommand.js"
68
+ },
69
+ "./timeout": {
70
+ "types": "./dist/src/Timeout.d.ts",
71
+ "default": "./dist/src/Timeout.js"
72
+ }
73
+ },
74
+ "files": [
75
+ "dist"
76
+ ],
77
+ "engines": {
78
+ "node": ">=22"
79
+ },
23
80
  "scripts": {
24
81
  "build": "tsc && tsc -p tsconfig.spec.json --noEmit",
25
82
  "lint": "oxlint src",
@@ -1,18 +0,0 @@
1
- name: Main Build
2
-
3
- on:
4
- push:
5
- branches: ["main"]
6
-
7
- workflow_dispatch:
8
-
9
- jobs:
10
- npm-merge:
11
- uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-merge.yml@main
12
- with:
13
- npm_package_name: "@devopsplaybook.io/common-utils"
14
- node_version: "22"
15
- secrets:
16
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
17
- QUALITY_DASHBOARD_URL: ${{ secrets.QUALITY_DASHBOARD_URL }}
18
- QUALITY_DASHBOARD_TOKEN: ${{ secrets.QUALITY_DASHBOARD_TOKEN }}
@@ -1,27 +0,0 @@
1
- name: PR Check
2
-
3
- on:
4
- pull_request:
5
- branches: ["main"]
6
-
7
- workflow_dispatch:
8
-
9
- concurrency:
10
- group: pr-${{ github.event.pull_request.number || github.ref }}
11
- cancel-in-progress: true
12
-
13
- permissions:
14
- contents: read
15
- pull-requests: write
16
- issues: write
17
-
18
- jobs:
19
- npm-pr:
20
- uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-pr.yml@main
21
- with:
22
- npm_package_name: "@devopsplaybook.io/common-utils"
23
- node_version: "22"
24
- secrets:
25
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
26
- QUALITY_DASHBOARD_URL: ${{ secrets.QUALITY_DASHBOARD_URL }}
27
- QUALITY_DASHBOARD_TOKEN: ${{ secrets.QUALITY_DASHBOARD_TOKEN }}