@getstrata/core 2.2.8 → 2.2.9
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 +4 -0
- package/dist/core/database/baseRepository.d.ts +6 -0
- package/dist/core/database/transaction.d.ts +6 -1
- package/dist/entries/audit/exportAuditLogs.js +22 -5
- package/dist/entries/auth/scimAuthMiddleware.js +22 -5
- package/dist/entries/jobs/exportAuditLogsJob.js +22 -5
- package/dist/entries/tenant/databaseTenantContext.js +22 -5
- package/dist/entries/tenant/tenantDatabaseScope.js +22 -5
- package/dist/framework/public-api.d.ts +1 -0
- package/dist/index.js +27 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,12 @@ type ExtendedQueryOptions<TEntity extends object> = QueryOptions<TEntity> & {
|
|
|
11
11
|
interface DatabaseConnection {
|
|
12
12
|
unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
|
|
13
13
|
begin?<T>(callback: (transaction: DatabaseConnection) => Promise<T>): Promise<T>;
|
|
14
|
+
/** Optional native cancellable pool checkout; absence must not be silently emulated. */
|
|
15
|
+
reserve?(options: {
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}): Promise<DatabaseConnection & {
|
|
18
|
+
release(): void | Promise<void>;
|
|
19
|
+
}>;
|
|
14
20
|
/** SQLite closes synchronously; pooled drivers return a promise. */
|
|
15
21
|
close?(): void | Promise<void>;
|
|
16
22
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { DatabaseConnection } from "./baseRepository.ts";
|
|
2
2
|
import { hasActiveTransaction, requestTransactionRollback } from "./transactionControl.ts";
|
|
3
|
-
|
|
3
|
+
interface TransactionOptions {
|
|
4
|
+
/** Cancel admission/pool checkout only. Does not cancel SQL or an admitted business callback. */
|
|
5
|
+
acquisitionSignal?: AbortSignal;
|
|
6
|
+
}
|
|
7
|
+
declare function runInTransaction<TValue>(operation: (connection: DatabaseConnection) => Promise<TValue>, options?: TransactionOptions): Promise<TValue>;
|
|
8
|
+
export type { TransactionOptions };
|
|
4
9
|
export { hasActiveTransaction, requestTransactionRollback, runInTransaction };
|
|
@@ -697,18 +697,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
697
697
|
function supportsTransactions(connection) {
|
|
698
698
|
return typeof connection.begin === "function";
|
|
699
699
|
}
|
|
700
|
-
async function runInTransaction(operation) {
|
|
700
|
+
async function runInTransaction(operation, options = {}) {
|
|
701
|
+
const signal = options.acquisitionSignal;
|
|
702
|
+
signal?.throwIfAborted();
|
|
703
|
+
const admittedOperation = (connection) => {
|
|
704
|
+
signal?.throwIfAborted();
|
|
705
|
+
return operation(connection);
|
|
706
|
+
};
|
|
701
707
|
const pool = resolveRepositoryConnection();
|
|
702
708
|
if (hasActiveDatabaseConnection()) {
|
|
703
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
709
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
704
710
|
}
|
|
705
711
|
if (!supportsTransactions(pool)) {
|
|
706
712
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
707
713
|
}
|
|
708
714
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
});
|
|
715
|
+
if (signal && !pool.reserve)
|
|
716
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
717
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
718
|
+
const connection = reserved ?? pool;
|
|
719
|
+
try {
|
|
720
|
+
signal?.throwIfAborted();
|
|
721
|
+
if (!supportsTransactions(connection))
|
|
722
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
723
|
+
return await connection.begin(async (transaction) => {
|
|
724
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
725
|
+
});
|
|
726
|
+
} finally {
|
|
727
|
+
await reserved?.release();
|
|
728
|
+
}
|
|
712
729
|
}));
|
|
713
730
|
}
|
|
714
731
|
var transactionFrame, outerFrames;
|
|
@@ -653,18 +653,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
653
653
|
function supportsTransactions(connection) {
|
|
654
654
|
return typeof connection.begin === "function";
|
|
655
655
|
}
|
|
656
|
-
async function runInTransaction(operation) {
|
|
656
|
+
async function runInTransaction(operation, options = {}) {
|
|
657
|
+
const signal = options.acquisitionSignal;
|
|
658
|
+
signal?.throwIfAborted();
|
|
659
|
+
const admittedOperation = (connection) => {
|
|
660
|
+
signal?.throwIfAborted();
|
|
661
|
+
return operation(connection);
|
|
662
|
+
};
|
|
657
663
|
const pool = resolveRepositoryConnection();
|
|
658
664
|
if (hasActiveDatabaseConnection()) {
|
|
659
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
665
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
660
666
|
}
|
|
661
667
|
if (!supportsTransactions(pool)) {
|
|
662
668
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
663
669
|
}
|
|
664
670
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
});
|
|
671
|
+
if (signal && !pool.reserve)
|
|
672
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
673
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
674
|
+
const connection = reserved ?? pool;
|
|
675
|
+
try {
|
|
676
|
+
signal?.throwIfAborted();
|
|
677
|
+
if (!supportsTransactions(connection))
|
|
678
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
679
|
+
return await connection.begin(async (transaction) => {
|
|
680
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
681
|
+
});
|
|
682
|
+
} finally {
|
|
683
|
+
await reserved?.release();
|
|
684
|
+
}
|
|
668
685
|
}));
|
|
669
686
|
}
|
|
670
687
|
var transactionFrame, outerFrames;
|
|
@@ -697,18 +697,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
697
697
|
function supportsTransactions(connection) {
|
|
698
698
|
return typeof connection.begin === "function";
|
|
699
699
|
}
|
|
700
|
-
async function runInTransaction(operation) {
|
|
700
|
+
async function runInTransaction(operation, options = {}) {
|
|
701
|
+
const signal = options.acquisitionSignal;
|
|
702
|
+
signal?.throwIfAborted();
|
|
703
|
+
const admittedOperation = (connection) => {
|
|
704
|
+
signal?.throwIfAborted();
|
|
705
|
+
return operation(connection);
|
|
706
|
+
};
|
|
701
707
|
const pool = resolveRepositoryConnection();
|
|
702
708
|
if (hasActiveDatabaseConnection()) {
|
|
703
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
709
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
704
710
|
}
|
|
705
711
|
if (!supportsTransactions(pool)) {
|
|
706
712
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
707
713
|
}
|
|
708
714
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
});
|
|
715
|
+
if (signal && !pool.reserve)
|
|
716
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
717
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
718
|
+
const connection = reserved ?? pool;
|
|
719
|
+
try {
|
|
720
|
+
signal?.throwIfAborted();
|
|
721
|
+
if (!supportsTransactions(connection))
|
|
722
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
723
|
+
return await connection.begin(async (transaction) => {
|
|
724
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
725
|
+
});
|
|
726
|
+
} finally {
|
|
727
|
+
await reserved?.release();
|
|
728
|
+
}
|
|
712
729
|
}));
|
|
713
730
|
}
|
|
714
731
|
var transactionFrame, outerFrames;
|
|
@@ -697,18 +697,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
697
697
|
function supportsTransactions(connection) {
|
|
698
698
|
return typeof connection.begin === "function";
|
|
699
699
|
}
|
|
700
|
-
async function runInTransaction(operation) {
|
|
700
|
+
async function runInTransaction(operation, options = {}) {
|
|
701
|
+
const signal = options.acquisitionSignal;
|
|
702
|
+
signal?.throwIfAborted();
|
|
703
|
+
const admittedOperation = (connection) => {
|
|
704
|
+
signal?.throwIfAborted();
|
|
705
|
+
return operation(connection);
|
|
706
|
+
};
|
|
701
707
|
const pool = resolveRepositoryConnection();
|
|
702
708
|
if (hasActiveDatabaseConnection()) {
|
|
703
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
709
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
704
710
|
}
|
|
705
711
|
if (!supportsTransactions(pool)) {
|
|
706
712
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
707
713
|
}
|
|
708
714
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
});
|
|
715
|
+
if (signal && !pool.reserve)
|
|
716
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
717
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
718
|
+
const connection = reserved ?? pool;
|
|
719
|
+
try {
|
|
720
|
+
signal?.throwIfAborted();
|
|
721
|
+
if (!supportsTransactions(connection))
|
|
722
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
723
|
+
return await connection.begin(async (transaction) => {
|
|
724
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
725
|
+
});
|
|
726
|
+
} finally {
|
|
727
|
+
await reserved?.release();
|
|
728
|
+
}
|
|
712
729
|
}));
|
|
713
730
|
}
|
|
714
731
|
var transactionFrame, outerFrames;
|
|
@@ -631,18 +631,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
631
631
|
function supportsTransactions(connection) {
|
|
632
632
|
return typeof connection.begin === "function";
|
|
633
633
|
}
|
|
634
|
-
async function runInTransaction(operation) {
|
|
634
|
+
async function runInTransaction(operation, options = {}) {
|
|
635
|
+
const signal = options.acquisitionSignal;
|
|
636
|
+
signal?.throwIfAborted();
|
|
637
|
+
const admittedOperation = (connection) => {
|
|
638
|
+
signal?.throwIfAborted();
|
|
639
|
+
return operation(connection);
|
|
640
|
+
};
|
|
635
641
|
const pool = resolveRepositoryConnection();
|
|
636
642
|
if (hasActiveDatabaseConnection()) {
|
|
637
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
643
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
638
644
|
}
|
|
639
645
|
if (!supportsTransactions(pool)) {
|
|
640
646
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
641
647
|
}
|
|
642
648
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
});
|
|
649
|
+
if (signal && !pool.reserve)
|
|
650
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
651
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
652
|
+
const connection = reserved ?? pool;
|
|
653
|
+
try {
|
|
654
|
+
signal?.throwIfAborted();
|
|
655
|
+
if (!supportsTransactions(connection))
|
|
656
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
657
|
+
return await connection.begin(async (transaction) => {
|
|
658
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
659
|
+
});
|
|
660
|
+
} finally {
|
|
661
|
+
await reserved?.release();
|
|
662
|
+
}
|
|
646
663
|
}));
|
|
647
664
|
}
|
|
648
665
|
var transactionFrame, outerFrames;
|
|
@@ -64,6 +64,7 @@ export { loadSeedersFromDirectory, runSeedersFromDirectory, } from "../core/data
|
|
|
64
64
|
export type { Seeder, SeederDatabase } from "../core/database/seeders/types.ts";
|
|
65
65
|
export { createSqliteConnection } from "../core/database/sqliteConnection.ts";
|
|
66
66
|
export { defineTable } from "../core/database/table.ts";
|
|
67
|
+
export type { TransactionOptions } from "../core/database/transaction.ts";
|
|
67
68
|
export { hasActiveTransaction, requestTransactionRollback, runInTransaction, } from "../core/database/transaction.ts";
|
|
68
69
|
export type { ModelWhere, ModelWriteValues, QueryJoin, QueryJoinOn, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, } from "../core/database/types.ts";
|
|
69
70
|
export type { WhereNode } from "../core/database/whereBuilder.ts";
|
package/dist/index.js
CHANGED
|
@@ -730,18 +730,35 @@ async function runInSavepoint(connection, operation) {
|
|
|
730
730
|
function supportsTransactions(connection) {
|
|
731
731
|
return typeof connection.begin === "function";
|
|
732
732
|
}
|
|
733
|
-
async function runInTransaction(operation) {
|
|
733
|
+
async function runInTransaction(operation, options = {}) {
|
|
734
|
+
const signal = options.acquisitionSignal;
|
|
735
|
+
signal?.throwIfAborted();
|
|
736
|
+
const admittedOperation = (connection) => {
|
|
737
|
+
signal?.throwIfAborted();
|
|
738
|
+
return operation(connection);
|
|
739
|
+
};
|
|
734
740
|
const pool = resolveRepositoryConnection();
|
|
735
741
|
if (hasActiveDatabaseConnection()) {
|
|
736
|
-
return await runInSavepoint(getActiveDatabaseConnection(pool),
|
|
742
|
+
return await runInSavepoint(getActiveDatabaseConnection(pool), admittedOperation);
|
|
737
743
|
}
|
|
738
744
|
if (!supportsTransactions(pool)) {
|
|
739
745
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
740
746
|
}
|
|
741
747
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
});
|
|
748
|
+
if (signal && !pool.reserve)
|
|
749
|
+
throw new Error("Active database connection does not support cancellable transaction acquisition.");
|
|
750
|
+
const reserved = signal ? await pool.reserve?.({ signal }) : undefined;
|
|
751
|
+
const connection = reserved ?? pool;
|
|
752
|
+
try {
|
|
753
|
+
signal?.throwIfAborted();
|
|
754
|
+
if (!supportsTransactions(connection))
|
|
755
|
+
throw new Error("Reserved database connection does not support transactions.");
|
|
756
|
+
return await connection.begin(async (transaction) => {
|
|
757
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(createDatabaseConnection(transaction))))));
|
|
758
|
+
});
|
|
759
|
+
} finally {
|
|
760
|
+
await reserved?.release();
|
|
761
|
+
}
|
|
745
762
|
}));
|
|
746
763
|
}
|
|
747
764
|
var transactionFrame, outerFrames;
|
|
@@ -9235,6 +9252,7 @@ function createOutboxMetricsCollector(options = {}) {
|
|
|
9235
9252
|
throw new Error("Outbox metrics collection is still settling.");
|
|
9236
9253
|
const deadline = performance.now() + timeoutMs;
|
|
9237
9254
|
let expired = false;
|
|
9255
|
+
const acquisition = new AbortController;
|
|
9238
9256
|
let timer;
|
|
9239
9257
|
const remaining = () => {
|
|
9240
9258
|
const value = Math.floor(deadline - performance.now());
|
|
@@ -9266,7 +9284,7 @@ function createOutboxMetricsCollector(options = {}) {
|
|
|
9266
9284
|
});
|
|
9267
9285
|
return { sampleLimit, states };
|
|
9268
9286
|
});
|
|
9269
|
-
});
|
|
9287
|
+
}, { acquisitionSignal: acquisition.signal });
|
|
9270
9288
|
active = work;
|
|
9271
9289
|
work.finally(() => {
|
|
9272
9290
|
if (active === work)
|
|
@@ -9278,7 +9296,9 @@ function createOutboxMetricsCollector(options = {}) {
|
|
|
9278
9296
|
new Promise((_, reject) => {
|
|
9279
9297
|
timer = setTimeout(() => {
|
|
9280
9298
|
expired = true;
|
|
9281
|
-
|
|
9299
|
+
const error = new Error("Outbox metrics collection timed out.");
|
|
9300
|
+
acquisition.abort(error);
|
|
9301
|
+
reject(error);
|
|
9282
9302
|
}, timeoutMs);
|
|
9283
9303
|
})
|
|
9284
9304
|
]);
|