@xemahq/biome-database-nest 0.12.1 → 0.13.0
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/package.json +9 -10
- package/src/index.ts +0 -115
- package/src/lib/adapter.ts +0 -117
- package/src/lib/bootstrap.ts +0 -428
- package/src/lib/config.ts +0 -183
- package/src/lib/control-plane-client.ts +0 -124
- package/src/lib/control-plane-discovery.ts +0 -42
- package/src/lib/identifier.ts +0 -177
- package/src/lib/migration-mode.ts +0 -25
- package/src/lib/nest/biome-database.module.ts +0 -174
- package/src/lib/nest/org-erasure.module.ts +0 -158
- package/src/lib/nest/prisma-service-factory.ts +0 -377
- package/src/lib/role-names.ts +0 -77
- package/src/lib/schema-name.ts +0 -62
- package/src/lib/tenant-isolation/org-erasure.ts +0 -235
- package/src/lib/tenant-isolation/org-scope.ts +0 -305
- package/src/lib/tenant-isolation/tenant-isolation-error.ts +0 -79
- package/src/lib/tenant-isolation/tenant-isolation-mode.ts +0 -55
- package/src/lib/tenant-isolation/tenant-isolation.extension.ts +0 -203
- package/src/lib/tenant-isolation/unscoped-models.ts +0 -272
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/biome-database-nest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Explicit database migration ownership, least-privilege runtime verification, and schema-qualified Prisma wiring for Xema biome services.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
|
|
@@ -18,25 +18,24 @@
|
|
|
18
18
|
"main": "dist/index.js",
|
|
19
19
|
"types": "dist/index.d.ts",
|
|
20
20
|
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
"src"
|
|
21
|
+
"dist"
|
|
23
22
|
],
|
|
24
23
|
"devDependencies": {
|
|
25
|
-
"@nestjs/common": "11.1.
|
|
26
|
-
"@nestjs/core": "11.1.
|
|
24
|
+
"@nestjs/common": "11.1.18",
|
|
25
|
+
"@nestjs/core": "11.1.18",
|
|
27
26
|
"@nestjs/swagger": "11.2.6",
|
|
28
27
|
"@types/jest": "^30.0.0",
|
|
29
28
|
"@types/node": "25.2.3",
|
|
30
29
|
"@types/pg": "^8.16.0",
|
|
31
30
|
"@xemahq/identity-client": "^0.9.1",
|
|
32
|
-
"@xemahq/kernel-contracts": "^
|
|
31
|
+
"@xemahq/kernel-contracts": "^10.0.0",
|
|
33
32
|
"jest": "^30.3.0",
|
|
34
33
|
"prettier": "3.6.2",
|
|
35
34
|
"ts-jest": "^29.4.9",
|
|
36
35
|
"typescript": "5.9.3",
|
|
37
|
-
"@xemahq/platform-common": "^0.
|
|
38
|
-
"@xemahq/
|
|
39
|
-
"@xemahq/
|
|
36
|
+
"@xemahq/platform-common": "^0.9.0",
|
|
37
|
+
"@xemahq/service-registry-nest": "0.7.1",
|
|
38
|
+
"@xemahq/xema-decorators": "0.5.4"
|
|
40
39
|
},
|
|
41
40
|
"peerDependencies": {
|
|
42
41
|
"@nestjs/common": "^10 || ^11",
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
"@xemahq/kernel-contracts": ">=0.13.0",
|
|
49
48
|
"@xemahq/service-registry-nest": ">=0.2.0",
|
|
50
49
|
"@xemahq/xema-decorators": ">=0.2.0",
|
|
51
|
-
"@xemahq/platform-common": "^0.
|
|
50
|
+
"@xemahq/platform-common": "^0.9.0"
|
|
52
51
|
},
|
|
53
52
|
"dependencies": {
|
|
54
53
|
"@xemahq/migration-runner-prisma": "^0.1.2",
|
package/src/index.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
export { DEFAULT_BIOME_DB_KEY, deriveBiomeSchemaName } from './lib/schema-name';
|
|
2
|
-
export {
|
|
3
|
-
composeIdentifier,
|
|
4
|
-
fitIdentifier,
|
|
5
|
-
IDENTIFIER_HASH_LENGTH,
|
|
6
|
-
POSTGRES_MAX_IDENTIFIER_LENGTH,
|
|
7
|
-
sanitizeIdentifierChars,
|
|
8
|
-
sanitizeIdentifierSegment,
|
|
9
|
-
type ComposeIdentifierInput,
|
|
10
|
-
type FitIdentifierInput,
|
|
11
|
-
} from './lib/identifier';
|
|
12
|
-
export {
|
|
13
|
-
rolesForSchema,
|
|
14
|
-
schemaRoleBase,
|
|
15
|
-
schemaRoleName,
|
|
16
|
-
SchemaRoleKind,
|
|
17
|
-
SCHEMA_ROLE_BASE_MAX_LENGTH,
|
|
18
|
-
SCHEMA_ROLE_SUFFIX_LENGTH,
|
|
19
|
-
type SchemaRoleNames,
|
|
20
|
-
} from './lib/role-names';
|
|
21
|
-
export {
|
|
22
|
-
resolveBiomeDatabaseConfigFromEnv,
|
|
23
|
-
type BiomeDatabaseConfig,
|
|
24
|
-
} from './lib/config';
|
|
25
|
-
export {
|
|
26
|
-
createBiomePrismaAdapter,
|
|
27
|
-
createBiomePrismaAdapterFromEnv,
|
|
28
|
-
} from './lib/adapter';
|
|
29
|
-
export {
|
|
30
|
-
fetchSystemDatabaseConfig,
|
|
31
|
-
type SystemDatabaseConfigRequest,
|
|
32
|
-
} from './lib/control-plane-client';
|
|
33
|
-
export {
|
|
34
|
-
resolveControlPlaneBaseUrl,
|
|
35
|
-
ORG_DATABASE_POOL_SERVICE_NAME,
|
|
36
|
-
type ControlPlaneDiscoveryOptions,
|
|
37
|
-
} from './lib/control-plane-discovery';
|
|
38
|
-
export {
|
|
39
|
-
bootstrapBiomeDatabases,
|
|
40
|
-
type BiomeDatabaseDeclaration,
|
|
41
|
-
type BootstrapBiomeDatabasesOptions,
|
|
42
|
-
} from './lib/bootstrap';
|
|
43
|
-
export { BiomeDatabaseMigrationMode } from './lib/migration-mode';
|
|
44
|
-
export {
|
|
45
|
-
BiomeDatabaseModule,
|
|
46
|
-
BIOME_DATABASE_READY,
|
|
47
|
-
type ApplicationManagedBiomeDatabaseModuleOptions,
|
|
48
|
-
type BiomeDatabaseModuleOptions,
|
|
49
|
-
} from './lib/nest/biome-database.module';
|
|
50
|
-
export {
|
|
51
|
-
createBiomePrismaService,
|
|
52
|
-
type BiomePrismaClient,
|
|
53
|
-
type BiomePrismaClientCtor,
|
|
54
|
-
type BiomePrismaServiceInstance,
|
|
55
|
-
type CreateBiomePrismaServiceOptions,
|
|
56
|
-
type TenantIsolationServiceOptions,
|
|
57
|
-
type TenantScopedApi,
|
|
58
|
-
} from './lib/nest/prisma-service-factory';
|
|
59
|
-
export {
|
|
60
|
-
TenantIsolationMode,
|
|
61
|
-
TENANT_ISOLATION_MODE_ENV_VAR,
|
|
62
|
-
resolveTenantIsolationMode,
|
|
63
|
-
} from './lib/tenant-isolation/tenant-isolation-mode';
|
|
64
|
-
export {
|
|
65
|
-
TenantIsolationError,
|
|
66
|
-
TenantIsolationViolationKind,
|
|
67
|
-
formatTenantIsolationViolation,
|
|
68
|
-
type TenantIsolationViolation,
|
|
69
|
-
} from './lib/tenant-isolation/tenant-isolation-error';
|
|
70
|
-
export {
|
|
71
|
-
PrismaModelOperation,
|
|
72
|
-
scopeArgsToOrg,
|
|
73
|
-
type OrgScopeOutcome,
|
|
74
|
-
type OrgScopeRequest,
|
|
75
|
-
} from './lib/tenant-isolation/org-scope';
|
|
76
|
-
export {
|
|
77
|
-
DEFAULT_ORG_FIELD,
|
|
78
|
-
collectOrgScopedModels,
|
|
79
|
-
createTenantIsolationExtension,
|
|
80
|
-
readRuntimeModels,
|
|
81
|
-
type CreateTenantIsolationExtensionOptions,
|
|
82
|
-
type RuntimeDataModelField,
|
|
83
|
-
type RuntimeDataModelModel,
|
|
84
|
-
type TenantIsolationExtensionDefinition,
|
|
85
|
-
type TenantIsolationLogger,
|
|
86
|
-
type TenantIsolationQueryContext,
|
|
87
|
-
} from './lib/tenant-isolation/tenant-isolation.extension';
|
|
88
|
-
export {
|
|
89
|
-
assertUnscopedModelsDeclared,
|
|
90
|
-
collectUnscopableModels,
|
|
91
|
-
formatUnscopedModelReport,
|
|
92
|
-
normalizeUnscopedModelDeclarations,
|
|
93
|
-
UndeclaredUnscopedModelsError,
|
|
94
|
-
type AssertUnscopedModelsOptions,
|
|
95
|
-
type NormalizedUnscopedModelDeclaration,
|
|
96
|
-
type UnscopedModelDeclaration,
|
|
97
|
-
type UnscopedModelDeclarations,
|
|
98
|
-
} from './lib/tenant-isolation/unscoped-models';
|
|
99
|
-
export {
|
|
100
|
-
assertOrgErasureMatchesModels,
|
|
101
|
-
eraseOrgData,
|
|
102
|
-
OrgErasureBlockedError,
|
|
103
|
-
OrgErasureMatchesNothingError,
|
|
104
|
-
type EraseOrgDataOptions,
|
|
105
|
-
type OrgErasureReport,
|
|
106
|
-
} from './lib/tenant-isolation/org-erasure';
|
|
107
|
-
export {
|
|
108
|
-
OrgErasureModule,
|
|
109
|
-
OrgErasureController,
|
|
110
|
-
ORG_ERASURE_RUNNER,
|
|
111
|
-
ORG_DATA_ERASURE_CAPABILITY,
|
|
112
|
-
ORG_ERASURE_ROUTE_PATH,
|
|
113
|
-
type OrgErasureModuleOptions,
|
|
114
|
-
type OrgErasureRunner,
|
|
115
|
-
} from './lib/nest/org-erasure.module';
|
package/src/lib/adapter.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { PrismaPg } from '@prisma/adapter-pg';
|
|
2
|
-
import {
|
|
3
|
-
composeBiomeDatabaseUrl,
|
|
4
|
-
ensureBiomeDbSearchPath,
|
|
5
|
-
} from '@xemahq/platform-common';
|
|
6
|
-
|
|
7
|
-
import { resolveBiomeDatabaseConfigFromEnv } from './config';
|
|
8
|
-
|
|
9
|
-
import type { BiomeDatabaseConfig } from './config';
|
|
10
|
-
|
|
11
|
-
const DEFAULT_POOL_MAX = 3;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Build a connection string from a {@link BiomeDatabaseConfig}, with `?schema=`
|
|
15
|
-
* when a per-biome schema is set and the libpq `search_path` option applied so
|
|
16
|
-
* RAW queries also resolve to the biome schema.
|
|
17
|
-
*
|
|
18
|
-
* @throws if the config is missing a part required to form a URL.
|
|
19
|
-
*/
|
|
20
|
-
function buildBiomeConnectionString(config: BiomeDatabaseConfig): string {
|
|
21
|
-
const url = composeBiomeDatabaseUrl({
|
|
22
|
-
user: config.username,
|
|
23
|
-
password: config.password,
|
|
24
|
-
host: config.host,
|
|
25
|
-
port: String(config.port),
|
|
26
|
-
database: config.database,
|
|
27
|
-
...(config.schema !== undefined ? { schema: config.schema } : {}),
|
|
28
|
-
...(config.sslParams !== undefined ? { sslParams: config.sslParams } : {}),
|
|
29
|
-
});
|
|
30
|
-
if (url === null) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
'createBiomePrismaAdapter: incomplete BiomeDatabaseConfig — ' +
|
|
33
|
-
'host/port/database/username/password are all required.',
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
return ensureBiomeDbSearchPath(url);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Construct a {@link PrismaPg} driver-adapter pool whose Prisma Client qualifies
|
|
41
|
-
* ORM table names with the biome schema.
|
|
42
|
-
*
|
|
43
|
-
* THIS IS THE CENTRALIZED FIX. `@prisma/adapter-pg` (Prisma 7) ignores BOTH the
|
|
44
|
-
* URL `?schema=` and the connection `search_path` when qualifying ORM-emitted
|
|
45
|
-
* SQL — it falls back to `public.<table>` unless the schema is passed as the
|
|
46
|
-
* SECOND constructor argument. Passing `{ schema }` here makes Prisma emit
|
|
47
|
-
* `biome_<id>.<table>`. `ensureBiomeDbSearchPath` separately fixes RAW queries.
|
|
48
|
-
* Constructing the adapter correctly is the ONLY thing this function does, so
|
|
49
|
-
* the correct construction is the only construction a biome can perform.
|
|
50
|
-
*/
|
|
51
|
-
export function createBiomePrismaAdapter(
|
|
52
|
-
config: BiomeDatabaseConfig,
|
|
53
|
-
): PrismaPg {
|
|
54
|
-
const connectionString = buildBiomeConnectionString(config);
|
|
55
|
-
return new PrismaPg(
|
|
56
|
-
{
|
|
57
|
-
connectionString,
|
|
58
|
-
min: 1,
|
|
59
|
-
max: config.poolMax ?? DEFAULT_POOL_MAX,
|
|
60
|
-
idleTimeoutMillis: 30_000,
|
|
61
|
-
},
|
|
62
|
-
config.schema !== undefined ? { schema: config.schema } : undefined,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Construct the schema-qualified adapter from the environment — the path the
|
|
68
|
-
* unchanged-shape `PrismaService` calls at construction time (post-bootstrap,
|
|
69
|
-
* where `DATABASE_URL`/`DB_*` are guaranteed set).
|
|
70
|
-
*
|
|
71
|
-
* Resolution order:
|
|
72
|
-
* 1. If `DATABASE_URL` (or `DATABASE_URL_<KEY>` for a non-default key) is set,
|
|
73
|
-
* use it directly as the connection string (still applying
|
|
74
|
-
* `ensureBiomeDbSearchPath` + the `{ schema }` second-arg from `DB_SCHEMA`).
|
|
75
|
-
* 2. Otherwise compose from the discrete `DB_*` vars.
|
|
76
|
-
*
|
|
77
|
-
* @throws if neither a `DATABASE_URL` nor a complete `DB_*` set is present.
|
|
78
|
-
*/
|
|
79
|
-
export function createBiomePrismaAdapterFromEnv(
|
|
80
|
-
env: NodeJS.ProcessEnv = process.env,
|
|
81
|
-
dbKey?: string,
|
|
82
|
-
): PrismaPg {
|
|
83
|
-
const isDefault = dbKey === undefined || dbKey === '' || dbKey === 'primary';
|
|
84
|
-
const upperSuffix = isDefault
|
|
85
|
-
? ''
|
|
86
|
-
: `_${dbKey.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;
|
|
87
|
-
|
|
88
|
-
const directUrl = env[`DATABASE_URL${upperSuffix}`];
|
|
89
|
-
const schema = env[`DB_SCHEMA${upperSuffix}`];
|
|
90
|
-
const poolMaxRaw = env[`DB_POOL_MAX${upperSuffix}`] ?? env.DB_POOL_MAX;
|
|
91
|
-
const poolMax =
|
|
92
|
-
poolMaxRaw !== undefined && poolMaxRaw !== ''
|
|
93
|
-
? Number.parseInt(poolMaxRaw, 10)
|
|
94
|
-
: DEFAULT_POOL_MAX;
|
|
95
|
-
|
|
96
|
-
if (directUrl !== undefined && directUrl !== '') {
|
|
97
|
-
const connectionString = ensureBiomeDbSearchPath(directUrl);
|
|
98
|
-
return new PrismaPg(
|
|
99
|
-
{
|
|
100
|
-
connectionString,
|
|
101
|
-
min: 1,
|
|
102
|
-
max: poolMax,
|
|
103
|
-
idleTimeoutMillis: 30_000,
|
|
104
|
-
},
|
|
105
|
-
schema !== undefined && schema !== '' ? { schema } : undefined,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const config = resolveBiomeDatabaseConfigFromEnv(env, dbKey);
|
|
110
|
-
if (config === null) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`createBiomePrismaAdapterFromEnv: no DATABASE_URL${upperSuffix} and no ` +
|
|
113
|
-
`DB_HOST${upperSuffix}/DB_HOST in the environment — cannot construct an adapter.`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
return createBiomePrismaAdapter(config);
|
|
117
|
-
}
|