@devopsplaybook.io/common-utils 1.10.1 → 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
@@ -6,6 +6,33 @@ exports.DbUtilsNoTelemetryExecSQL = DbUtilsNoTelemetryExecSQL;
6
6
  exports.DbUtilsNoTelemetryQuerySQL = DbUtilsNoTelemetryQuerySQL;
7
7
  const DbUtils_1 = require("./DbUtils");
8
8
  let logger;
9
+ /**
10
+ * Compiled SQLite statements are cached per database handle: `better-sqlite3`
11
+ * has no internal cache and `prepare()` dominates the ingestion hot path.
12
+ */
13
+ const PREPARED_STATEMENT_CACHE_MAX = 100;
14
+ const statementCaches = new WeakMap();
15
+ function prepareCached(db, sql) {
16
+ let cache = statementCaches.get(db);
17
+ if (!cache) {
18
+ cache = new Map();
19
+ statementCaches.set(db, cache);
20
+ }
21
+ let statement = cache.get(sql);
22
+ if (!statement) {
23
+ if (cache.size >= PREPARED_STATEMENT_CACHE_MAX) {
24
+ const oldest = cache.keys().next().value;
25
+ if (oldest !== undefined) {
26
+ cache.delete(oldest);
27
+ }
28
+ }
29
+ statement = db.prepare(sql);
30
+ cache.set(sql, statement);
31
+ }
32
+ return statement;
33
+ }
34
+ /** Maximum number of bound parameters per statement on each backend. */
35
+ const PARAMS_PER_STATEMENT = { postgres: 65535, sqlite: 32766 };
9
36
  /**
10
37
  * Injects the OTel logger instance used by no-telemetry DB operations.
11
38
  * Must be called once at startup.
@@ -17,15 +44,43 @@ function DbUtilsNoTelemetrySetLogger(loggerIn) {
17
44
  * Execute a multi-row INSERT with a flat parameter array.
18
45
  * Builds: INSERT INTO <tableCols> VALUES (?,?...),(?,?...),...
19
46
  *
20
- * @returns Number of rows inserted.
47
+ * Large inputs are chunked so the statement never exceeds the backend's
48
+ * bound-parameter limit (65535 on Postgres, 32766 on SQLite).
49
+ *
50
+ * @returns Number of rows inserted (summed across chunks).
21
51
  */
22
52
  function DbUtilsNoTelemetryBatchInsert(tableCols, numCols, rows) {
23
53
  if (rows.length === 0)
24
54
  return 0;
55
+ const dbType = (0, DbUtils_1.DbUtilsGetType)();
56
+ const maxRowsPerChunk = Math.max(1, Math.floor(PARAMS_PER_STATEMENT[dbType] / Math.max(1, numCols)));
57
+ if (rows.length <= maxRowsPerChunk) {
58
+ return DbUtilsNoTelemetryExecSQL(buildBatchInsertSQL(tableCols, numCols, rows.length), rows.flat());
59
+ }
60
+ const chunks = [];
61
+ for (let i = 0; i < rows.length; i += maxRowsPerChunk) {
62
+ chunks.push(rows.slice(i, i + maxRowsPerChunk));
63
+ }
64
+ if (dbType === "postgres") {
65
+ return execChunksSequentially(chunks, tableCols, numCols);
66
+ }
67
+ let total = 0;
68
+ for (const chunk of chunks) {
69
+ total += DbUtilsNoTelemetryExecSQL(buildBatchInsertSQL(tableCols, numCols, chunk.length), chunk.flat());
70
+ }
71
+ return total;
72
+ }
73
+ function buildBatchInsertSQL(tableCols, numCols, rowCount) {
25
74
  const rowSQL = `(${Array.from({ length: numCols }, () => "?").join(",")})`;
26
- const multiValues = Array.from({ length: rows.length }, () => rowSQL).join(",");
27
- const sql = `INSERT ${tableCols} VALUES ${multiValues}`;
28
- return DbUtilsNoTelemetryExecSQL(sql, rows.flat());
75
+ const multiValues = Array.from({ length: rowCount }, () => rowSQL).join(",");
76
+ return `INSERT ${tableCols} VALUES ${multiValues}`;
77
+ }
78
+ async function execChunksSequentially(chunks, tableCols, numCols) {
79
+ let total = 0;
80
+ for (const chunk of chunks) {
81
+ total += (await DbUtilsNoTelemetryExecSQL(buildBatchInsertSQL(tableCols, numCols, chunk.length), chunk.flat()));
82
+ }
83
+ return total;
29
84
  }
30
85
  /**
31
86
  * Execute a write SQL statement **without** creating an OTel span.
@@ -50,7 +105,8 @@ function DbUtilsNoTelemetryExecSQL(sql, params = []) {
50
105
  });
51
106
  }
52
107
  // SQLite (better-sqlite3) – synchronous
53
- const stmt = (0, DbUtils_1.DbUtilsGetDatabase)().prepare(sql);
108
+ const db = (0, DbUtils_1.DbUtilsGetDatabase)();
109
+ const stmt = prepareCached(db, sql);
54
110
  const result = stmt.run(params);
55
111
  return result.changes;
56
112
  }
@@ -80,6 +136,6 @@ function DbUtilsNoTelemetryQuerySQL(sql, params = [], debug = false) {
80
136
  });
81
137
  }
82
138
  // SQLite (better-sqlite3) – synchronous
83
- const stmt = (0, DbUtils_1.DbUtilsGetDatabase)().prepare(sql);
139
+ const stmt = prepareCached((0, DbUtils_1.DbUtilsGetDatabase)(), sql);
84
140
  return stmt.all(params);
85
141
  }
@@ -10,7 +10,24 @@ export interface PostgresDbConfig {
10
10
  DATABASE_POSTGRES_USER: string;
11
11
  DATABASE_POSTGRES_PASSWORD: string;
12
12
  DATABASE_POSTGRES_DATABASE: string;
13
+ /**
14
+ * Optional per-session `statement_timeout` (milliseconds) applied to every
15
+ * pool. Disabled when absent or 0 (backward-compatible default).
16
+ */
17
+ DATABASE_POSTGRES_STATEMENT_TIMEOUT_MS?: number;
18
+ /**
19
+ * Optional per-session `idle_in_transaction_session_timeout` (milliseconds)
20
+ * applied to every pool. Disabled when absent or 0.
21
+ */
22
+ DATABASE_POSTGRES_IDLE_IN_TRANSACTION_TIMEOUT_MS?: number;
13
23
  }
24
+ /**
25
+ * Named advisory-lock purposes. Each name maps to a fixed 32-bit key (the
26
+ * first four ASCII characters of the purpose) so that every replica of every
27
+ * service booting against the same database serialises the same operation.
28
+ */
29
+ export type PostgresLockName = "migration" | "auth_token" | "users_bootstrap";
30
+ export declare const POSTGRES_LOCK_KEYS: Record<PostgresLockName, number>;
14
31
  /**
15
32
  * Class-based PostgreSQL utility that manages a schema-specific pool (used
16
33
  * during migrations) and an optional shared runtime pool (used for
@@ -45,7 +62,10 @@ export declare class PostgresSchemaDbUtils {
45
62
  * @returns Number of rows changed.
46
63
  */
47
64
  execSQL(context: Span, sql: string, params?: any[], useSchemaPool?: boolean): Promise<number>;
48
- /** Execute an entire SQL file (used for migrations). */
65
+ /**
66
+ * Execute an entire SQL file (used for migrations).
67
+ * Migration files must not contain their own transaction control statements.
68
+ */
49
69
  execSQLFile(context: Span, filename: string, useSchemaPool?: boolean): Promise<void>;
50
70
  /**
51
71
  * Execute a read SQL query with OTel tracing.
@@ -58,9 +78,6 @@ export declare class PostgresSchemaDbUtils {
58
78
  transaction(context: Span, callback: (client: any) => Promise<void>, useSchemaPool?: boolean): Promise<void>;
59
79
  /** Close both the schema pool and the runtime pool. */
60
80
  closeAll(): Promise<void>;
61
- private execSQLForSchema;
62
- private execSQLFileForSchema;
63
- private querySQLForSchema;
64
81
  }
65
82
  /**
66
83
  * Injects the OTel tracer and logger instances used by all Postgres operations.
@@ -70,23 +87,37 @@ export declare function PostgresDbUtilsSetOTel(tracerIn: StandardTracer, loggerI
70
87
  /**
71
88
  * Creates the Postgres connection pool and applies pending migration files
72
89
  * from `sqlDir`.
90
+ *
91
+ * Migrations are applied under a session-level advisory lock (concurrently
92
+ * booting replicas serialise instead of double-applying) and each file plus
93
+ * its `db_version` row runs in its own transaction: a failing migration is
94
+ * rolled back and never recorded.
73
95
  */
74
96
  export declare function PostgresDbUtilsInit(context: Span, config: PostgresDbConfig, sqlDir: string): Promise<void>;
97
+ /**
98
+ * Run a callback while holding a Postgres advisory lock, serialising the
99
+ * callback across every replica of every service booting against the same
100
+ * database (used for the `auth_token` and first-user bootstrap races).
101
+ */
102
+ export declare function PostgresDbUtilsWithAdvisoryLock<T>(lock: PostgresLockName, callback: () => Promise<T>): Promise<T>;
75
103
  /** Returns the underlying `pg.Pool` instance. */
76
104
  export declare function PostgresDbUtilsGetPool(): Pool;
77
105
  /**
78
106
  * Execute a write SQL statement with OTel tracing.
79
107
  * @returns Number of rows changed.
80
108
  */
81
- export declare function PostgresDbUtilsExecSQL(context: Span, sql: string, params?: unknown[]): Promise<number>;
82
- /** Execute an entire SQL file (used for migrations). */
83
- export declare function PostgresDbUtilsExecSQLFile(context: Span, filename: string): Promise<void>;
109
+ export declare function PostgresDbUtilsExecSQL(context: Span | undefined, sql: string, params?: unknown[]): Promise<number>;
110
+ /**
111
+ * Execute an entire SQL file (used for migrations).
112
+ * Migration files must not contain their own transaction control statements.
113
+ */
114
+ export declare function PostgresDbUtilsExecSQLFile(context: Span | undefined, filename: string): Promise<void>;
84
115
  /**
85
116
  * Execute a read SQL query with OTel tracing.
86
117
  * @returns Array of row objects.
87
118
  */
88
- export declare function PostgresDbUtilsQuerySQL(context: Span, sql: string, params?: unknown[], debug?: boolean): Promise<any[]>;
119
+ export declare function PostgresDbUtilsQuerySQL(context: Span | undefined, sql: string, params?: unknown[], debug?: boolean): Promise<any[]>;
89
120
  /** Start a transaction. */
90
- export declare function PostgresDbUtilsTransactionStart(context: Span): Promise<void>;
121
+ export declare function PostgresDbUtilsTransactionStart(context: Span | undefined): Promise<void>;
91
122
  /** Commit a transaction. */
92
- export declare function PostgresDbUtilsTransactionCommit(context: Span): Promise<void>;
123
+ export declare function PostgresDbUtilsTransactionCommit(context: Span | undefined): Promise<void>;