@getstrata/core 2.2.36 → 2.2.38
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 +8 -0
- package/dist/core/auth/saml/samlServiceProvider.d.ts +23 -7
- package/dist/core/database/baseRepository.d.ts +4 -0
- package/dist/core/database/index.d.ts +1 -1
- package/dist/core/database/transaction.d.ts +5 -1
- package/dist/entries/audit/exportAuditLogs.js +22 -5
- package/dist/entries/auth/basicAuthGuard.js +22 -5
- package/dist/entries/auth/oauth/samlProvider.js +725 -79
- package/dist/entries/auth/saml/samlServiceProvider.js +725 -79
- package/dist/entries/auth/scimAuthMiddleware.js +121 -8
- package/dist/entries/jobs/exportAuditLogsJob.js +22 -5
- package/dist/entries/queue/queueMetrics.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 -1
- package/dist/index.js +168 -14
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @getstrata/core changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.38
|
|
4
|
+
|
|
5
|
+
Qualify packed OIDC and SAML callbacks across Postgres, SQLite and MySQL. Fix explicitly non-migrating local bootstrap provisioning, dialect-safe transactional SAML replay, verified bearer ACS recipient binding, and independent SAML Response Destination validation through a maintained parser. Fix owned listener/client address mismatches with typed generated native options and optional CLI HOST, retaining default production binding. Preserve existing generated auth, production guards, compiler/runtime assertions and coverage gates; live provider and deployment qualification remain separate.
|
|
6
|
+
|
|
7
|
+
## 2.2.37
|
|
8
|
+
|
|
9
|
+
Fix MySQL repository entity-returning mutations with transaction-pinned readback, persisted keys/defaults, honest null and deletion outcomes, complete model event payloads and injected connection ownership. Preserve native Postgres/SQLite RETURNING and conditional affected-row metadata. Close owned generated OpenAPI and failed-job command applications on success and failure before exit; retain both command and cleanup errors. Add mandatory packaged MySQL production column-tenancy CLI and HTTP auth/SCIM acceptance with an owned DML-only account, unchanged route/spec/SDK contracts, native ORM regressions and cleanup tests. Records dogfood issues #232 and #233 without application SQL workarounds.
|
|
10
|
+
|
|
3
11
|
## 2.2.36
|
|
4
12
|
|
|
5
13
|
Add a mandatory installed-package SQLite column-tenancy CLI/OpenAPI/HTTP profile, including cookie/token/JWT/Basic and repeated SCIM isolation, while preserving existing Postgres security, route inventories, compiler combinations and Docker gates. Reconcile observability/rotation trackers against shipped capabilities and remaining operational qualification.
|
|
@@ -10,6 +10,27 @@ interface SamlServiceProviderOptions {
|
|
|
10
10
|
wantAuthnResponseSigned?: boolean;
|
|
11
11
|
disableRequestedAuthnContext?: boolean;
|
|
12
12
|
}
|
|
13
|
+
interface VerifiedSamlAssertion {
|
|
14
|
+
Assertion?: {
|
|
15
|
+
$?: {
|
|
16
|
+
ID?: string;
|
|
17
|
+
};
|
|
18
|
+
Subject?: Array<{
|
|
19
|
+
SubjectConfirmation?: Array<{
|
|
20
|
+
$?: {
|
|
21
|
+
Method?: string;
|
|
22
|
+
};
|
|
23
|
+
SubjectConfirmationData?: Array<{
|
|
24
|
+
$?: {
|
|
25
|
+
Recipient?: string;
|
|
26
|
+
NotBefore?: string;
|
|
27
|
+
NotOnOrAfter?: string;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
}>;
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
13
34
|
interface NodeSamlProfile {
|
|
14
35
|
ID?: string;
|
|
15
36
|
nameID?: string;
|
|
@@ -17,13 +38,8 @@ interface NodeSamlProfile {
|
|
|
17
38
|
name?: string;
|
|
18
39
|
issuer?: string;
|
|
19
40
|
sessionIndex?: string | string[];
|
|
20
|
-
getAssertion?: () =>
|
|
21
|
-
|
|
22
|
-
$?: {
|
|
23
|
-
ID?: string;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
};
|
|
41
|
+
getAssertion?: () => VerifiedSamlAssertion;
|
|
42
|
+
getSamlResponseXml?: () => string;
|
|
27
43
|
[key: string]: unknown;
|
|
28
44
|
}
|
|
29
45
|
type NodeSamlClient = {
|
|
@@ -35,6 +35,10 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
35
35
|
constructor(table: TableDefinition<TEntity, PrimaryKey>, connection?: DatabaseConnection);
|
|
36
36
|
private assertTransactionalEvent;
|
|
37
37
|
private runModelMutation;
|
|
38
|
+
private mysqlMutation;
|
|
39
|
+
private mysqlRow;
|
|
40
|
+
private mysqlAffected;
|
|
41
|
+
private mysqlWriteById;
|
|
38
42
|
count(options?: ExtendedQueryOptions<TEntity>): Promise<number>;
|
|
39
43
|
findAll(options?: ExtendedQueryOptions<TEntity>): Promise<TEntity[]>;
|
|
40
44
|
paginate(options: {
|
|
@@ -24,7 +24,7 @@ export { Blueprint, ColumnDefinition, compileBlueprint, createSchemaBuilder, For
|
|
|
24
24
|
export { createSqliteConnection } from "./sqliteConnection.ts";
|
|
25
25
|
export type { TableDefinition } from "./table.ts";
|
|
26
26
|
export { defineTable } from "./table.ts";
|
|
27
|
-
export { runInTransaction } from "./transaction.ts";
|
|
27
|
+
export { isActiveTransactionConnection, runInTransaction } from "./transaction.ts";
|
|
28
28
|
export type { DatabaseComparable, DatabaseScalar, MutationValues, QueryFilterValue, QueryJoin, QueryJoinOn, QueryOperator, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, UpdateValues, } from "./types.ts";
|
|
29
29
|
export type { WhereNode } from "./whereBuilder.ts";
|
|
30
30
|
export { WhereBuilder } from "./whereBuilder.ts";
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type TransactionAcquisitionMetrics } from "./acquisitionMetrics.ts";
|
|
2
2
|
import type { DatabaseConnection } from "./baseRepository.ts";
|
|
3
3
|
import { hasActiveTransaction, requestTransactionRollback } from "./transactionControl.ts";
|
|
4
|
+
/** Recognizes the callback handle without admitting an unrelated pool. */
|
|
5
|
+
declare function isActiveTransactionConnection(connection: DatabaseConnection): boolean;
|
|
4
6
|
interface TransactionOptions {
|
|
7
|
+
/** Explicit root pool for injected repositories; cannot switch an active transaction's owner. */
|
|
8
|
+
connection?: DatabaseConnection;
|
|
5
9
|
/** Cancel admission/pool checkout only. Does not cancel SQL or an admitted business callback. */
|
|
6
10
|
acquisitionSignal?: AbortSignal;
|
|
7
11
|
/** Observe native checkout only; requires a reserve-capable adapter. */
|
|
@@ -11,4 +15,4 @@ declare function runInTransaction<TValue>(operation: (connection: DatabaseConnec
|
|
|
11
15
|
export type { TransactionAcquisitionMetrics, TransactionAcquisitionSnapshot, } from "./acquisitionMetrics.ts";
|
|
12
16
|
export { createTransactionAcquisitionMetrics, renderTransactionAcquisitionMetrics, } from "./acquisitionMetrics.ts";
|
|
13
17
|
export type { TransactionOptions };
|
|
14
|
-
export { hasActiveTransaction, requestTransactionRollback, runInTransaction };
|
|
18
|
+
export { hasActiveTransaction, isActiveTransactionConnection, requestTransactionRollback, runInTransaction, };
|
|
@@ -733,6 +733,17 @@ var init_repositoryConnection = __esm(() => {
|
|
|
733
733
|
|
|
734
734
|
// ../../src/core/database/transaction.ts
|
|
735
735
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
736
|
+
function scopedConnection(source) {
|
|
737
|
+
const connection = createDatabaseConnection(source);
|
|
738
|
+
transactionAliases.set(connection, source);
|
|
739
|
+
return connection;
|
|
740
|
+
}
|
|
741
|
+
function isActiveTransactionConnection(connection) {
|
|
742
|
+
if (!hasActiveTransaction() || !hasActiveDatabaseConnection())
|
|
743
|
+
return false;
|
|
744
|
+
const active = getActiveDatabaseConnection(connection);
|
|
745
|
+
return connection === active || transactionAliases.get(connection) === active;
|
|
746
|
+
}
|
|
736
747
|
async function runInSavepoint(connection, operation) {
|
|
737
748
|
const inherited = transactionFrame.getStore();
|
|
738
749
|
let parent = inherited?.connection === connection ? inherited : outerFrames.get(connection);
|
|
@@ -749,7 +760,7 @@ async function runInSavepoint(connection, operation) {
|
|
|
749
760
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
750
761
|
await connection.unsafe(`SAVEPOINT ${name}`);
|
|
751
762
|
try {
|
|
752
|
-
const result = await transactionFrame.run({ connection, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await operation(
|
|
763
|
+
const result = await transactionFrame.run({ connection, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await operation(scopedConnection(connection)))));
|
|
753
764
|
await connection.unsafe(`RELEASE SAVEPOINT ${name}`);
|
|
754
765
|
return result;
|
|
755
766
|
} catch (error) {
|
|
@@ -772,9 +783,12 @@ async function runInTransaction(operation, options = {}) {
|
|
|
772
783
|
signal?.throwIfAborted();
|
|
773
784
|
return operation(connection);
|
|
774
785
|
};
|
|
775
|
-
const pool = resolveRepositoryConnection();
|
|
786
|
+
const pool = options.connection ?? resolveRepositoryConnection();
|
|
776
787
|
if (hasActiveDatabaseConnection()) {
|
|
777
|
-
|
|
788
|
+
const active = getActiveDatabaseConnection(pool);
|
|
789
|
+
if (options.connection && options.connection !== active && options.connection !== transactionRoots.get(active) && transactionAliases.get(options.connection) !== active)
|
|
790
|
+
throw new Error("Cannot switch database connections within an active transaction.");
|
|
791
|
+
return await runInSavepoint(active, admittedOperation);
|
|
778
792
|
}
|
|
779
793
|
if (!supportsTransactions(pool)) {
|
|
780
794
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
@@ -793,14 +807,15 @@ async function runInTransaction(operation, options = {}) {
|
|
|
793
807
|
if (!supportsTransactions(connection))
|
|
794
808
|
throw new Error("Reserved database connection does not support transactions.");
|
|
795
809
|
return await connection.begin(AsyncLocalStorage3.bind(async (transaction) => {
|
|
796
|
-
|
|
810
|
+
transactionRoots.set(transaction, pool);
|
|
811
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(scopedConnection(transaction))))));
|
|
797
812
|
}));
|
|
798
813
|
} finally {
|
|
799
814
|
await reserved?.release();
|
|
800
815
|
}
|
|
801
816
|
}));
|
|
802
817
|
}
|
|
803
|
-
var transactionFrame, outerFrames;
|
|
818
|
+
var transactionFrame, outerFrames, transactionRoots, transactionAliases;
|
|
804
819
|
var init_transaction = __esm(() => {
|
|
805
820
|
init_deferredModelEvents();
|
|
806
821
|
init_asyncContextStore();
|
|
@@ -812,6 +827,8 @@ var init_transaction = __esm(() => {
|
|
|
812
827
|
init_acquisitionMetrics();
|
|
813
828
|
transactionFrame = createAsyncContextStore("@getstrata/transactionFrame");
|
|
814
829
|
outerFrames = new WeakMap;
|
|
830
|
+
transactionRoots = new WeakMap;
|
|
831
|
+
transactionAliases = new WeakMap;
|
|
815
832
|
});
|
|
816
833
|
|
|
817
834
|
// ../../src/core/tenant/databaseTenantContext.ts
|
|
@@ -733,6 +733,17 @@ var init_repositoryConnection = __esm(() => {
|
|
|
733
733
|
|
|
734
734
|
// ../../src/core/database/transaction.ts
|
|
735
735
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
736
|
+
function scopedConnection(source) {
|
|
737
|
+
const connection = createDatabaseConnection(source);
|
|
738
|
+
transactionAliases.set(connection, source);
|
|
739
|
+
return connection;
|
|
740
|
+
}
|
|
741
|
+
function isActiveTransactionConnection(connection) {
|
|
742
|
+
if (!hasActiveTransaction() || !hasActiveDatabaseConnection())
|
|
743
|
+
return false;
|
|
744
|
+
const active = getActiveDatabaseConnection(connection);
|
|
745
|
+
return connection === active || transactionAliases.get(connection) === active;
|
|
746
|
+
}
|
|
736
747
|
async function runInSavepoint(connection, operation) {
|
|
737
748
|
const inherited = transactionFrame.getStore();
|
|
738
749
|
let parent = inherited?.connection === connection ? inherited : outerFrames.get(connection);
|
|
@@ -749,7 +760,7 @@ async function runInSavepoint(connection, operation) {
|
|
|
749
760
|
return await settleTransaction(() => runWithDeferredModelEvents(async () => {
|
|
750
761
|
await connection.unsafe(`SAVEPOINT ${name}`);
|
|
751
762
|
try {
|
|
752
|
-
const result = await transactionFrame.run({ connection, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await operation(
|
|
763
|
+
const result = await transactionFrame.run({ connection, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await operation(scopedConnection(connection)))));
|
|
753
764
|
await connection.unsafe(`RELEASE SAVEPOINT ${name}`);
|
|
754
765
|
return result;
|
|
755
766
|
} catch (error) {
|
|
@@ -772,9 +783,12 @@ async function runInTransaction(operation, options = {}) {
|
|
|
772
783
|
signal?.throwIfAborted();
|
|
773
784
|
return operation(connection);
|
|
774
785
|
};
|
|
775
|
-
const pool = resolveRepositoryConnection();
|
|
786
|
+
const pool = options.connection ?? resolveRepositoryConnection();
|
|
776
787
|
if (hasActiveDatabaseConnection()) {
|
|
777
|
-
|
|
788
|
+
const active = getActiveDatabaseConnection(pool);
|
|
789
|
+
if (options.connection && options.connection !== active && options.connection !== transactionRoots.get(active) && transactionAliases.get(options.connection) !== active)
|
|
790
|
+
throw new Error("Cannot switch database connections within an active transaction.");
|
|
791
|
+
return await runInSavepoint(active, admittedOperation);
|
|
778
792
|
}
|
|
779
793
|
if (!supportsTransactions(pool)) {
|
|
780
794
|
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
@@ -793,14 +807,15 @@ async function runInTransaction(operation, options = {}) {
|
|
|
793
807
|
if (!supportsTransactions(connection))
|
|
794
808
|
throw new Error("Reserved database connection does not support transactions.");
|
|
795
809
|
return await connection.begin(AsyncLocalStorage3.bind(async (transaction) => {
|
|
796
|
-
|
|
810
|
+
transactionRoots.set(transaction, pool);
|
|
811
|
+
return await runWithDatabaseConnection(transaction, () => transactionFrame.run({ connection: transaction, childActive: false }, () => runWithTransactionScope(async () => commitOrRollbackScope(await admittedOperation(scopedConnection(transaction))))));
|
|
797
812
|
}));
|
|
798
813
|
} finally {
|
|
799
814
|
await reserved?.release();
|
|
800
815
|
}
|
|
801
816
|
}));
|
|
802
817
|
}
|
|
803
|
-
var transactionFrame, outerFrames;
|
|
818
|
+
var transactionFrame, outerFrames, transactionRoots, transactionAliases;
|
|
804
819
|
var init_transaction = __esm(() => {
|
|
805
820
|
init_deferredModelEvents();
|
|
806
821
|
init_asyncContextStore();
|
|
@@ -812,6 +827,8 @@ var init_transaction = __esm(() => {
|
|
|
812
827
|
init_acquisitionMetrics();
|
|
813
828
|
transactionFrame = createAsyncContextStore("@getstrata/transactionFrame");
|
|
814
829
|
outerFrames = new WeakMap;
|
|
830
|
+
transactionRoots = new WeakMap;
|
|
831
|
+
transactionAliases = new WeakMap;
|
|
815
832
|
});
|
|
816
833
|
|
|
817
834
|
// ../../src/core/tenant/databaseTenantContext.ts
|