@getstrata/core 2.2.10 → 2.2.12
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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/core/crypto/fieldEncryption.d.ts +29 -0
- package/dist/core/crypto/fieldEncryptionRotation.d.ts +34 -0
- package/dist/core/database/baseRepository.d.ts +5 -0
- package/dist/core/database/isolatedReadOnlyObservation.d.ts +15 -0
- package/dist/core/database/mysqlConnection.d.ts +3 -0
- package/dist/core/database/readOnlyCollector.d.ts +7 -0
- package/dist/core/database/sqliteConnection.d.ts +3 -0
- package/dist/core/events/outbox/metrics.d.ts +1 -1
- package/dist/entries/auth/basicAuthGuard.js +154 -1
- package/dist/entries/auth/passwordLogin.js +154 -1
- package/dist/entries/crypto/fieldEncryption.js +145 -1
- package/dist/entries/crypto/fieldEncryptionRotation.js +1 -0
- package/dist/entries/crypto/mfaSecret.js +154 -1
- package/dist/entries/database/schema.js +2 -2
- package/dist/entries/database/sqliteConnection.js +137 -1
- package/dist/entries/queue/queueMetrics.js +61 -27
- package/dist/framework/public-api.d.ts +2 -0
- package/dist/index.js +3178 -2601
- package/package.json +8 -3
- package/dist/core/database/postgresReadOnlyCollector.d.ts +0 -7
|
@@ -26,22 +26,6 @@ function createAsyncContextStore(key) {
|
|
|
26
26
|
}
|
|
27
27
|
var init_asyncContextStore = () => {};
|
|
28
28
|
|
|
29
|
-
// ../../src/core/database/connectionContext.ts
|
|
30
|
-
function runWithDatabaseConnection(connection, callback) {
|
|
31
|
-
return activeConnection.run(connection, callback);
|
|
32
|
-
}
|
|
33
|
-
function getActiveDatabaseConnection(fallback) {
|
|
34
|
-
return activeConnection.getStore() ?? fallback;
|
|
35
|
-
}
|
|
36
|
-
function hasActiveDatabaseConnection() {
|
|
37
|
-
return activeConnection.getStore() !== undefined;
|
|
38
|
-
}
|
|
39
|
-
var activeConnection;
|
|
40
|
-
var init_connectionContext = __esm(() => {
|
|
41
|
-
init_asyncContextStore();
|
|
42
|
-
activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
|
|
43
|
-
});
|
|
44
|
-
|
|
45
29
|
// ../../src/core/database/schema/driver.ts
|
|
46
30
|
function normalizeConnectionName(connection) {
|
|
47
31
|
const normalized = connection.trim().toLowerCase();
|
|
@@ -243,6 +227,22 @@ var init_dialect = __esm(() => {
|
|
|
243
227
|
dialectContext = createAsyncContextStore("@getstrata/sqlDialect");
|
|
244
228
|
});
|
|
245
229
|
|
|
230
|
+
// ../../src/core/database/connectionContext.ts
|
|
231
|
+
function runWithDatabaseConnection(connection, callback) {
|
|
232
|
+
return activeConnection.run(connection, callback);
|
|
233
|
+
}
|
|
234
|
+
function getActiveDatabaseConnection(fallback) {
|
|
235
|
+
return activeConnection.getStore() ?? fallback;
|
|
236
|
+
}
|
|
237
|
+
function hasActiveDatabaseConnection() {
|
|
238
|
+
return activeConnection.getStore() !== undefined;
|
|
239
|
+
}
|
|
240
|
+
var activeConnection;
|
|
241
|
+
var init_connectionContext = __esm(() => {
|
|
242
|
+
init_asyncContextStore();
|
|
243
|
+
activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
246
|
// ../../src/core/database/boundConnection.ts
|
|
247
247
|
function boundConnectionState() {
|
|
248
248
|
const globalRecord = globalThis;
|
|
@@ -2192,12 +2192,15 @@ function createAppQueue(driver, redisUrl, failedJobs = createFailedJobService(),
|
|
|
2192
2192
|
});
|
|
2193
2193
|
}
|
|
2194
2194
|
|
|
2195
|
-
// ../../src/core/
|
|
2195
|
+
// ../../src/core/queue/failedJobMetrics.ts
|
|
2196
|
+
init_dialect();
|
|
2197
|
+
|
|
2198
|
+
// ../../src/core/database/readOnlyCollector.ts
|
|
2196
2199
|
init_connectionContext();
|
|
2197
2200
|
init_dialect();
|
|
2198
2201
|
init_repositoryConnection();
|
|
2199
2202
|
init_transaction();
|
|
2200
|
-
function
|
|
2203
|
+
function createReadOnlyCollector(name, timeoutMs, collect) {
|
|
2201
2204
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 5000)
|
|
2202
2205
|
throw new TypeError(`${name} timeout must be between 1 and 5000 milliseconds.`);
|
|
2203
2206
|
let active;
|
|
@@ -2208,8 +2211,10 @@ function createPostgresReadOnlyCollector(name, timeoutMs, collect) {
|
|
|
2208
2211
|
throw new Error(`${name} collector is closed.`);
|
|
2209
2212
|
if (hasActiveTransaction() || hasActiveDatabaseConnection())
|
|
2210
2213
|
throw new Error(`${name} require an independent transaction.`);
|
|
2211
|
-
|
|
2212
|
-
|
|
2214
|
+
const driver = currentSqlDialect().driver;
|
|
2215
|
+
const pool = resolveRepositoryConnection();
|
|
2216
|
+
if (driver !== "pgsql" && driver !== "sqlite" && driver !== "mysql")
|
|
2217
|
+
throw new Error(`${name} require Postgres or an interruptible SQLite/MySQL adapter.`);
|
|
2213
2218
|
if (active)
|
|
2214
2219
|
throw new Error(`${name} collection is still settling.`);
|
|
2215
2220
|
const deadline = performance.now() + timeoutMs;
|
|
@@ -2222,14 +2227,25 @@ function createPostgresReadOnlyCollector(name, timeoutMs, collect) {
|
|
|
2222
2227
|
throw new Error(`${name} collection timed out.`);
|
|
2223
2228
|
return value;
|
|
2224
2229
|
};
|
|
2225
|
-
const work = runInTransaction(async () => {
|
|
2226
|
-
await repositoryConnection.unsafe("SELECT set_config('statement_timeout', $1, true)", [
|
|
2230
|
+
const work = driver === "pgsql" ? runInTransaction(async () => {
|
|
2231
|
+
await repositoryConnection.unsafe("SELECT set_config('statement_timeout', $1, true)", [
|
|
2232
|
+
`${remaining()}ms`
|
|
2233
|
+
]);
|
|
2227
2234
|
await repositoryConnection.unsafe("SET TRANSACTION READ ONLY");
|
|
2228
2235
|
remaining();
|
|
2229
2236
|
const result = await collect(remaining);
|
|
2230
2237
|
remaining();
|
|
2231
2238
|
return result;
|
|
2232
|
-
}, { acquisitionSignal: acquisition.signal })
|
|
2239
|
+
}, { acquisitionSignal: acquisition.signal }) : (async () => {
|
|
2240
|
+
if (!pool.observeReadOnly)
|
|
2241
|
+
throw new Error(`${name} require Postgres or an interruptible SQLite/MySQL adapter.`);
|
|
2242
|
+
return pool.observeReadOnly(async (connection) => await runWithDatabaseConnection(connection, async () => {
|
|
2243
|
+
remaining();
|
|
2244
|
+
const result = await collect(remaining);
|
|
2245
|
+
remaining();
|
|
2246
|
+
return result;
|
|
2247
|
+
}), { signal: acquisition.signal, timeoutMs: remaining() });
|
|
2248
|
+
})();
|
|
2233
2249
|
active = work;
|
|
2234
2250
|
work.finally(() => {
|
|
2235
2251
|
if (active === work)
|
|
@@ -2267,15 +2283,33 @@ var schemaQuery = `SELECT c.relkind = 'r' AND c.relpersistence = 'p' AND NOT c.r
|
|
|
2267
2283
|
AND i.indnkeyatts = 1 AND a.attname = 'id' AND NOT a.attisdropped
|
|
2268
2284
|
AND a.atttypid IN ('int2'::regtype, 'int4'::regtype, 'int8'::regtype)
|
|
2269
2285
|
) AS supported FROM pg_class c WHERE c.oid = 'failed_job'::regclass`;
|
|
2286
|
+
var sqliteSchemaQuery = `SELECT 1 AS supported FROM main.sqlite_schema
|
|
2287
|
+
WHERE name='failed_job' AND type='table' AND rootpage > 0
|
|
2288
|
+
AND (SELECT COUNT(*) FROM pragma_table_xinfo('failed_job', 'main') WHERE pk > 0) = 1
|
|
2289
|
+
AND EXISTS (SELECT 1 FROM pragma_table_xinfo('failed_job', 'main')
|
|
2290
|
+
WHERE name='id' AND pk=1 AND upper(type)='INTEGER' AND hidden=0) LIMIT 1`;
|
|
2291
|
+
var mysqlSchemaQuery = `SELECT 1 AS supported FROM information_schema.TABLES t
|
|
2292
|
+
WHERE t.TABLE_SCHEMA=DATABASE() AND t.TABLE_NAME='failed_job' AND t.TABLE_TYPE='BASE TABLE' AND t.ENGINE='InnoDB'
|
|
2293
|
+
AND (SELECT COUNT(*) FROM information_schema.STATISTICS i WHERE i.TABLE_SCHEMA=t.TABLE_SCHEMA
|
|
2294
|
+
AND i.TABLE_NAME=t.TABLE_NAME AND i.INDEX_NAME='PRIMARY')=1
|
|
2295
|
+
AND EXISTS(SELECT 1 FROM information_schema.STATISTICS i JOIN information_schema.COLUMNS c
|
|
2296
|
+
ON c.TABLE_SCHEMA=i.TABLE_SCHEMA AND c.TABLE_NAME=i.TABLE_NAME AND c.COLUMN_NAME=i.COLUMN_NAME
|
|
2297
|
+
WHERE i.TABLE_SCHEMA=t.TABLE_SCHEMA AND i.TABLE_NAME=t.TABLE_NAME AND i.INDEX_NAME='PRIMARY'
|
|
2298
|
+
AND i.SEQ_IN_INDEX=1 AND i.COLUMN_NAME='id' AND c.DATA_TYPE IN ('tinyint','smallint','mediumint','int','bigint')) LIMIT 1`;
|
|
2270
2299
|
function createFailedJobMetricsCollector(options = {}) {
|
|
2271
2300
|
const sampleLimit = options.sampleLimit ?? 500;
|
|
2272
2301
|
if (!Number.isSafeInteger(sampleLimit) || sampleLimit < 1 || sampleLimit > 1000)
|
|
2273
2302
|
throw new TypeError("Failed-job metrics sample limit must be between 1 and 1000.");
|
|
2274
2303
|
const repository = new failedJobRepository_default;
|
|
2275
|
-
return
|
|
2276
|
-
|
|
2277
|
-
const
|
|
2278
|
-
if (
|
|
2304
|
+
return createReadOnlyCollector("Failed-job metrics", options.timeoutMs ?? 1000, async (remaining) => {
|
|
2305
|
+
const driver = currentSqlDialect().driver;
|
|
2306
|
+
const postgres = driver === "pgsql";
|
|
2307
|
+
if (postgres)
|
|
2308
|
+
await repositoryConnection.unsafe('LOCK TABLE "failed_job" IN ACCESS SHARE MODE');
|
|
2309
|
+
if (driver === "mysql")
|
|
2310
|
+
await repositoryConnection.unsafe("SELECT id FROM failed_job LIMIT 0");
|
|
2311
|
+
const schema = await repositoryConnection.unsafe(postgres ? schemaQuery : driver === "mysql" ? mysqlSchemaQuery : sqliteSchemaQuery);
|
|
2312
|
+
if (schema.length !== 1 || schema[0]?.supported !== (postgres ? true : 1))
|
|
2279
2313
|
throw new Error("Failed-job metrics require the standard global table with an ID primary key and no RLS.");
|
|
2280
2314
|
remaining();
|
|
2281
2315
|
const rows = await repository.query().orderBy({ column: "id", direction: "ASC" }).project(["id"], sampleLimit + 1);
|
|
@@ -32,6 +32,8 @@ export { CACHE_TAGS } from "../core/cache/tags.ts";
|
|
|
32
32
|
export { ConfigStore, createServiceToken, ServiceContainer, type ServiceToken, } from "../core/contracts/container.ts";
|
|
33
33
|
export type { ServiceProvider } from "../core/contracts/di.ts";
|
|
34
34
|
export { resolveService } from "../core/contracts/di.ts";
|
|
35
|
+
export type { FieldEncryptionRotationBatch, FieldEncryptionRotationOptions, } from "../core/crypto/fieldEncryptionRotation";
|
|
36
|
+
export { createFieldEncryptionRotationMigration, runFieldEncryptionRotationBatch, } from "../core/crypto/fieldEncryptionRotation";
|
|
35
37
|
export type { TransactionAcquisitionMetrics, TransactionAcquisitionSnapshot, } from "../core/database/acquisitionMetrics.ts";
|
|
36
38
|
export { createTransactionAcquisitionMetrics, renderTransactionAcquisitionMetrics, } from "../core/database/acquisitionMetrics.ts";
|
|
37
39
|
export type { DatabaseConnection } from "../core/database/baseRepository.ts";
|