@devxcrew/platform 0.1.2 → 0.1.6
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/README.md +7 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -2
- package/dist/modules/identity/audit/audit.controller.d.ts +17 -0
- package/dist/modules/identity/audit/audit.controller.js +12 -0
- package/dist/modules/identity/audit/audit.migration.d.ts +1 -0
- package/dist/modules/identity/audit/audit.migration.js +1 -0
- package/dist/modules/identity/audit/audit.provider.d.ts +24 -0
- package/dist/modules/identity/audit/audit.provider.js +14 -0
- package/dist/modules/identity/audit/audit.repository.d.ts +26 -0
- package/dist/modules/identity/audit/audit.repository.js +46 -0
- package/dist/modules/identity/audit/audit.routes.d.ts +5 -0
- package/dist/modules/identity/audit/audit.routes.js +2 -0
- package/dist/modules/identity/audit/audit.schema.d.ts +1 -0
- package/dist/modules/identity/audit/audit.schema.js +1 -0
- package/dist/modules/identity/audit/audit.seed.d.ts +1 -0
- package/dist/modules/identity/audit/audit.seed.js +1 -0
- package/dist/modules/identity/audit/audit.service.d.ts +23 -0
- package/dist/modules/identity/audit/audit.service.js +46 -0
- package/dist/modules/identity/audit/audit.types.d.ts +12 -0
- package/dist/modules/identity/audit/audit.types.js +1 -0
- package/dist/modules/identity/audit/index.d.ts +4 -0
- package/dist/modules/identity/audit/index.js +3 -0
- package/dist/modules/identity/{identity.administration-service.d.ts → composition/identity.composition.d.ts} +59 -27
- package/dist/modules/identity/composition/identity.composition.js +171 -0
- package/dist/modules/identity/composition/identity.seed.d.ts +3 -0
- package/dist/modules/identity/composition/identity.seed.js +16 -0
- package/dist/modules/identity/identity.controller.d.ts +8 -6
- package/dist/modules/identity/identity.controller.js +90 -70
- package/dist/modules/identity/identity.migration.d.ts +1 -2
- package/dist/modules/identity/identity.migration.js +1 -79
- package/dist/modules/identity/identity.provider.d.ts +39 -13
- package/dist/modules/identity/identity.provider.js +19 -73
- package/dist/modules/identity/identity.public-schemas.d.ts +9 -3
- package/dist/modules/identity/identity.public-schemas.js +9 -3
- package/dist/modules/identity/identity.repository.d.ts +1 -40
- package/dist/modules/identity/identity.repository.js +1 -196
- package/dist/modules/identity/identity.routes.d.ts +2 -5
- package/dist/modules/identity/identity.routes.js +3 -11
- package/dist/modules/identity/identity.schema.d.ts +1 -27
- package/dist/modules/identity/identity.schema.js +1 -34
- package/dist/modules/identity/identity.seed.d.ts +1 -3
- package/dist/modules/identity/identity.seed.js +1 -81
- package/dist/modules/identity/identity.service.d.ts +1 -32
- package/dist/modules/identity/identity.service.js +1 -83
- package/dist/modules/identity/identity.types.d.ts +13 -106
- package/dist/modules/identity/index.d.ts +18 -11
- package/dist/modules/identity/index.js +14 -8
- package/dist/modules/identity/{identity.administration-migration.js → legacy/identity.administration-migration.js} +3 -11
- package/dist/modules/identity/legacy/identity.migration.d.ts +2 -0
- package/dist/modules/identity/legacy/identity.migration.js +72 -0
- package/dist/modules/identity/organization/index.d.ts +6 -0
- package/dist/modules/identity/organization/index.js +5 -0
- package/dist/modules/identity/organization/organization.controller.d.ts +35 -0
- package/dist/modules/identity/organization/organization.controller.js +18 -0
- package/dist/modules/identity/organization/organization.migration.d.ts +1 -0
- package/dist/modules/identity/organization/organization.migration.js +1 -0
- package/dist/modules/identity/organization/organization.provider.d.ts +46 -0
- package/dist/modules/identity/organization/organization.provider.js +33 -0
- package/dist/modules/identity/organization/organization.repository.d.ts +58 -0
- package/dist/modules/identity/organization/organization.repository.js +101 -0
- package/dist/modules/identity/organization/organization.routes.d.ts +5 -0
- package/dist/modules/identity/organization/organization.routes.js +2 -0
- package/dist/modules/identity/organization/organization.schema.d.ts +11 -0
- package/dist/modules/identity/organization/organization.schema.js +18 -0
- package/dist/modules/identity/organization/organization.seed.d.ts +3 -0
- package/dist/modules/identity/organization/organization.seed.js +11 -0
- package/dist/modules/identity/organization/organization.service.d.ts +39 -0
- package/dist/modules/identity/organization/organization.service.js +55 -0
- package/dist/modules/identity/organization/organization.types.d.ts +19 -0
- package/dist/modules/identity/organization/organization.types.js +1 -0
- package/dist/modules/identity/permission/index.d.ts +9 -0
- package/dist/modules/identity/permission/index.js +6 -0
- package/dist/modules/identity/permission/permission.controller.d.ts +21 -0
- package/dist/modules/identity/permission/permission.controller.js +12 -0
- package/dist/modules/identity/{identity.permission-declarations-migration.js → permission/permission.declarations.migration.js} +9 -4
- package/dist/modules/identity/{identity.permission-labels-migration.js → permission/permission.labels.migration.js} +5 -2
- package/dist/modules/identity/permission/permission.migration.d.ts +2 -0
- package/dist/modules/identity/permission/permission.migration.js +2 -0
- package/dist/modules/identity/permission/permission.provider.d.ts +19 -0
- package/dist/modules/identity/permission/permission.provider.js +14 -0
- package/dist/modules/identity/permission/permission.repository.d.ts +51 -0
- package/dist/modules/identity/permission/permission.repository.js +84 -0
- package/dist/modules/identity/permission/permission.routes.d.ts +5 -0
- package/dist/modules/identity/permission/permission.routes.js +2 -0
- package/dist/modules/identity/permission/permission.schema.d.ts +14 -0
- package/dist/modules/identity/permission/permission.schema.js +29 -0
- package/dist/modules/identity/permission/permission.seed.d.ts +4 -0
- package/dist/modules/identity/permission/permission.seed.js +17 -0
- package/dist/modules/identity/permission/permission.service.d.ts +31 -0
- package/dist/modules/identity/permission/permission.service.js +77 -0
- package/dist/modules/identity/permission/permission.types.d.ts +15 -0
- package/dist/modules/identity/permission/permission.types.js +1 -0
- package/dist/modules/identity/role/index.d.ts +10 -0
- package/dist/modules/identity/role/index.js +6 -0
- package/dist/modules/identity/role/role.controller.d.ts +42 -0
- package/dist/modules/identity/role/role.controller.js +25 -0
- package/dist/modules/identity/{identity.roles-migration.js → role/role.migration.js} +5 -18
- package/dist/modules/identity/role/role.provider.d.ts +14 -0
- package/dist/modules/identity/role/role.provider.js +30 -0
- package/dist/modules/identity/role/role.repository.d.ts +38 -0
- package/dist/modules/identity/role/role.repository.js +46 -0
- package/dist/modules/identity/role/role.routes.d.ts +5 -0
- package/dist/modules/identity/role/role.routes.js +2 -0
- package/dist/modules/identity/role/role.schema.d.ts +16 -0
- package/dist/modules/identity/role/role.schema.js +27 -0
- package/dist/modules/identity/role/role.seed.d.ts +3 -0
- package/dist/modules/identity/role/role.seed.js +8 -0
- package/dist/modules/identity/role/role.service.d.ts +69 -0
- package/dist/modules/identity/role/role.service.js +192 -0
- package/dist/modules/identity/role/role.types.d.ts +17 -0
- package/dist/modules/identity/role/role.types.js +1 -0
- package/dist/modules/identity/role-permission/index.d.ts +6 -0
- package/dist/modules/identity/role-permission/index.js +4 -0
- package/dist/modules/identity/role-permission/role-permission.controller.d.ts +1 -0
- package/dist/modules/identity/role-permission/role-permission.controller.js +1 -0
- package/dist/modules/identity/role-permission/role-permission.migration.d.ts +1 -0
- package/dist/modules/identity/role-permission/role-permission.migration.js +1 -0
- package/dist/modules/identity/role-permission/role-permission.provider.d.ts +14 -0
- package/dist/modules/identity/role-permission/role-permission.provider.js +15 -0
- package/dist/modules/identity/role-permission/role-permission.repository.d.ts +12 -0
- package/dist/modules/identity/role-permission/role-permission.repository.js +51 -0
- package/dist/modules/identity/role-permission/role-permission.routes.d.ts +1 -0
- package/dist/modules/identity/role-permission/role-permission.routes.js +2 -0
- package/dist/modules/identity/role-permission/role-permission.schema.d.ts +2 -0
- package/dist/modules/identity/role-permission/role-permission.schema.js +3 -0
- package/dist/modules/identity/role-permission/role-permission.seed.d.ts +3 -0
- package/dist/modules/identity/role-permission/role-permission.seed.js +10 -0
- package/dist/modules/identity/role-permission/role-permission.service.d.ts +13 -0
- package/dist/modules/identity/role-permission/role-permission.service.js +35 -0
- package/dist/modules/identity/role-permission/role-permission.types.d.ts +12 -0
- package/dist/modules/identity/role-permission/role-permission.types.js +1 -0
- package/dist/modules/identity/session/index.d.ts +6 -0
- package/dist/modules/identity/session/index.js +5 -0
- package/dist/modules/identity/session/session.authentication.controller.d.ts +30 -0
- package/dist/modules/identity/session/session.authentication.controller.js +37 -0
- package/dist/modules/identity/session/session.controller.d.ts +18 -0
- package/dist/modules/identity/session/session.controller.js +15 -0
- package/dist/modules/identity/session/session.migration.d.ts +1 -0
- package/dist/modules/identity/session/session.migration.js +1 -0
- package/dist/modules/identity/session/session.provider.d.ts +34 -0
- package/dist/modules/identity/session/session.provider.js +23 -0
- package/dist/modules/identity/session/session.repository.d.ts +36 -0
- package/dist/modules/identity/session/session.repository.js +128 -0
- package/dist/modules/identity/session/session.routes.d.ts +27 -0
- package/dist/modules/identity/session/session.routes.js +13 -0
- package/dist/modules/identity/session/session.schema.d.ts +6 -0
- package/dist/modules/identity/session/session.schema.js +12 -0
- package/dist/modules/identity/session/session.seed.d.ts +1 -0
- package/dist/modules/identity/session/session.seed.js +1 -0
- package/dist/modules/identity/session/session.service.d.ts +20 -0
- package/dist/modules/identity/session/session.service.js +27 -0
- package/dist/modules/identity/session/session.types.d.ts +17 -0
- package/dist/modules/identity/session/session.types.js +1 -0
- package/dist/modules/identity/settings/index.d.ts +5 -0
- package/dist/modules/identity/settings/index.js +4 -0
- package/dist/modules/identity/settings/settings.controller.d.ts +35 -0
- package/dist/modules/identity/settings/settings.controller.js +18 -0
- package/dist/modules/identity/settings/settings.migration.d.ts +1 -0
- package/dist/modules/identity/settings/settings.migration.js +1 -0
- package/dist/modules/identity/settings/settings.provider.d.ts +35 -0
- package/dist/modules/identity/settings/settings.provider.js +14 -0
- package/dist/modules/identity/settings/settings.repository.d.ts +49 -0
- package/dist/modules/identity/settings/settings.repository.js +75 -0
- package/dist/modules/identity/settings/settings.routes.d.ts +1 -0
- package/dist/modules/identity/settings/settings.routes.js +7 -0
- package/dist/modules/identity/settings/settings.schema.d.ts +15 -0
- package/dist/modules/identity/settings/settings.schema.js +27 -0
- package/dist/modules/identity/settings/settings.seed.d.ts +1 -0
- package/dist/modules/identity/settings/settings.seed.js +1 -0
- package/dist/modules/identity/settings/settings.service.d.ts +40 -0
- package/dist/modules/identity/settings/settings.service.js +101 -0
- package/dist/modules/identity/settings/settings.types.d.ts +20 -0
- package/dist/modules/identity/settings/settings.types.js +1 -0
- package/dist/modules/identity/support/identity.schema.d.ts +8 -0
- package/dist/modules/identity/support/identity.schema.js +10 -0
- package/dist/modules/identity/support/pagination.d.ts +13 -0
- package/dist/modules/identity/support/pagination.js +27 -0
- package/dist/modules/identity/support/pagination.schema.d.ts +43 -0
- package/dist/modules/identity/support/pagination.schema.js +15 -0
- package/dist/modules/identity/support/resource-controller.d.ts +14 -0
- package/dist/modules/identity/support/resource-controller.js +1 -0
- package/dist/modules/identity/user/index.d.ts +13 -0
- package/dist/modules/identity/user/index.js +11 -0
- package/dist/modules/identity/user/user.administration.service.d.ts +59 -0
- package/dist/modules/identity/user/user.administration.service.js +159 -0
- package/dist/modules/identity/user/user.controller.d.ts +44 -0
- package/dist/modules/identity/user/user.controller.js +21 -0
- package/dist/modules/identity/user/user.lifecycle.controller.d.ts +58 -0
- package/dist/modules/identity/user/user.lifecycle.controller.js +27 -0
- package/dist/modules/identity/{identity.lifecycle-schema.js → user/user.lifecycle.schema.js} +5 -5
- package/dist/modules/identity/{identity.lifecycle-service.d.ts → user/user.lifecycle.service.d.ts} +8 -4
- package/dist/modules/identity/{identity.lifecycle-service.js → user/user.lifecycle.service.js} +66 -118
- package/dist/modules/identity/user/user.migration.d.ts +1 -0
- package/dist/modules/identity/user/user.migration.js +1 -0
- package/dist/modules/identity/{identity.password.js → user/user.password.js} +1 -1
- package/dist/modules/identity/user/user.provider.d.ts +80 -0
- package/dist/modules/identity/user/user.provider.js +22 -0
- package/dist/modules/identity/user/user.repository.d.ts +64 -0
- package/dist/modules/identity/user/user.repository.js +129 -0
- package/dist/modules/identity/user/user.routes.d.ts +12 -0
- package/dist/modules/identity/user/user.routes.js +9 -0
- package/dist/modules/identity/user/user.schema.d.ts +34 -0
- package/dist/modules/identity/user/user.schema.js +46 -0
- package/dist/modules/identity/user/user.seed.d.ts +14 -0
- package/dist/modules/identity/user/user.seed.js +47 -0
- package/dist/modules/identity/user/user.service.d.ts +33 -0
- package/dist/modules/identity/user/user.service.js +76 -0
- package/dist/modules/identity/user/user.types.d.ts +27 -0
- package/dist/modules/identity/user/user.types.js +1 -0
- package/dist/modules/identity/user-role/index.d.ts +8 -0
- package/dist/modules/identity/user-role/index.js +6 -0
- package/dist/modules/identity/user-role/user-role.controller.d.ts +42 -0
- package/dist/modules/identity/user-role/user-role.controller.js +21 -0
- package/dist/modules/identity/user-role/user-role.migration.d.ts +1 -0
- package/dist/modules/identity/user-role/user-role.migration.js +1 -0
- package/dist/modules/identity/user-role/user-role.policy.d.ts +3 -0
- package/dist/modules/identity/user-role/user-role.policy.js +25 -0
- package/dist/modules/identity/user-role/user-role.provider.d.ts +18 -0
- package/dist/modules/identity/user-role/user-role.provider.js +23 -0
- package/dist/modules/identity/user-role/user-role.repository.d.ts +34 -0
- package/dist/modules/identity/user-role/user-role.repository.js +87 -0
- package/dist/modules/identity/user-role/user-role.routes.d.ts +5 -0
- package/dist/modules/identity/user-role/user-role.routes.js +2 -0
- package/dist/modules/identity/user-role/user-role.schema.d.ts +14 -0
- package/dist/modules/identity/user-role/user-role.schema.js +25 -0
- package/dist/modules/identity/user-role/user-role.seed.d.ts +7 -0
- package/dist/modules/identity/user-role/user-role.seed.js +11 -0
- package/dist/modules/identity/user-role/user-role.service.d.ts +60 -0
- package/dist/modules/identity/user-role/user-role.service.js +216 -0
- package/dist/modules/identity/user-role/user-role.types.d.ts +12 -0
- package/dist/modules/identity/user-role/user-role.types.js +1 -0
- package/dist/modules/tenant/index.d.ts +6 -0
- package/dist/modules/tenant/index.js +5 -0
- package/dist/modules/tenant/tenant.command.d.ts +3 -0
- package/dist/modules/tenant/tenant.command.js +43 -0
- package/dist/modules/tenant/tenant.controller.d.ts +4 -0
- package/dist/modules/tenant/tenant.controller.js +12 -0
- package/dist/modules/tenant/tenant.migration.d.ts +5 -0
- package/dist/modules/tenant/tenant.migration.js +46 -0
- package/dist/modules/tenant/tenant.provider.d.ts +3 -0
- package/dist/modules/tenant/tenant.provider.js +44 -0
- package/dist/modules/tenant/tenant.readiness.d.ts +6 -0
- package/dist/modules/tenant/tenant.readiness.js +45 -0
- package/dist/modules/tenant/tenant.repository.d.ts +15 -0
- package/dist/modules/tenant/tenant.repository.js +23 -0
- package/dist/modules/tenant/tenant.routes.d.ts +4 -0
- package/dist/modules/tenant/tenant.routes.js +7 -0
- package/dist/modules/tenant/tenant.schema.d.ts +20 -0
- package/dist/modules/tenant/tenant.schema.js +31 -0
- package/dist/modules/tenant/tenant.seed.d.ts +8 -0
- package/dist/modules/tenant/tenant.seed.js +40 -0
- package/dist/modules/tenant/tenant.service.d.ts +16 -0
- package/dist/modules/tenant/tenant.service.js +72 -0
- package/dist/modules/tenant/tenant.types.d.ts +39 -0
- package/dist/modules/tenant/tenant.types.js +1 -0
- package/package.json +9 -5
- package/dist/modules/identity/identity.administration-repository.d.ts +0 -19
- package/dist/modules/identity/identity.administration-repository.js +0 -102
- package/dist/modules/identity/identity.administration-schema.d.ts +0 -113
- package/dist/modules/identity/identity.administration-schema.js +0 -121
- package/dist/modules/identity/identity.administration-service.js +0 -517
- package/dist/modules/identity/identity.membership-policy.d.ts +0 -3
- package/dist/modules/identity/identity.membership-policy.js +0 -27
- package/dist/modules/identity/identity.permission-declarations.d.ts +0 -23
- package/dist/modules/identity/identity.permission-declarations.js +0 -57
- package/dist/modules/identity/identity.presentation-service.d.ts +0 -23
- package/dist/modules/identity/identity.presentation-service.js +0 -51
- package/dist/modules/identity/identity.roles-service.d.ts +0 -49
- package/dist/modules/identity/identity.roles-service.js +0 -327
- /package/dist/modules/identity/{identity.administration-migration.d.ts → legacy/identity.administration-migration.d.ts} +0 -0
- /package/dist/modules/identity/{identity.permission-declarations-migration.d.ts → permission/permission.declarations.migration.d.ts} +0 -0
- /package/dist/modules/identity/{identity.permission-labels-migration.d.ts → permission/permission.labels.migration.d.ts} +0 -0
- /package/dist/modules/identity/{identity.roles-migration.d.ts → role/role.migration.d.ts} +0 -0
- /package/dist/modules/identity/{identity.error.d.ts → support/identity.error.d.ts} +0 -0
- /package/dist/modules/identity/{identity.error.js → support/identity.error.js} +0 -0
- /package/dist/modules/identity/{identity.request-context.d.ts → support/identity.request-context.d.ts} +0 -0
- /package/dist/modules/identity/{identity.request-context.js → support/identity.request-context.js} +0 -0
- /package/dist/modules/identity/{identity.lifecycle-schema.d.ts → user/user.lifecycle.schema.d.ts} +0 -0
- /package/dist/modules/identity/{identity.password.d.ts → user/user.password.d.ts} +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const tenantRequestSchema = z.strictObject({
|
|
3
|
+
portal: z.enum(["user", "admin", "super-admin"]).default("user"),
|
|
4
|
+
tenantId: z.string().trim().min(1).max(255).optional()
|
|
5
|
+
});
|
|
6
|
+
export const tenantMappingSchema = z
|
|
7
|
+
.strictObject({
|
|
8
|
+
tenantId: z.string().min(1),
|
|
9
|
+
driver: z.enum(["sqlite", "mariadb"]),
|
|
10
|
+
databaseName: z
|
|
11
|
+
.string()
|
|
12
|
+
.regex(/^[a-zA-Z][a-zA-Z0-9_]{0,63}$/)
|
|
13
|
+
.nullable(),
|
|
14
|
+
sqlitePath: z.string().trim().min(1).nullable(),
|
|
15
|
+
active: z.number().int().min(0).max(1),
|
|
16
|
+
version: z.number().int().min(1)
|
|
17
|
+
})
|
|
18
|
+
.superRefine((value, context) => {
|
|
19
|
+
if (value.driver === "mariadb" && !value.databaseName)
|
|
20
|
+
context.addIssue({
|
|
21
|
+
code: "custom",
|
|
22
|
+
path: ["databaseName"],
|
|
23
|
+
message: "Database name is required."
|
|
24
|
+
});
|
|
25
|
+
if (value.driver === "sqlite" && !value.sqlitePath)
|
|
26
|
+
context.addIssue({
|
|
27
|
+
code: "custom",
|
|
28
|
+
path: ["sqlitePath"],
|
|
29
|
+
message: "Database path is required."
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TenantDatabase } from "./tenant.types.js";
|
|
2
|
+
import type { ConnectionTarget } from "@devxcrew/framework";
|
|
3
|
+
export declare function provisionTenant(database: TenantDatabase & {
|
|
4
|
+
provisionConnection(target: ConnectionTarget): Promise<unknown>;
|
|
5
|
+
}, environment: NodeJS.ProcessEnv): Promise<{
|
|
6
|
+
tenantId: string;
|
|
7
|
+
status: string;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { HttpError, readDatabaseConfiguration } from "@devxcrew/framework";
|
|
4
|
+
import { createIdentityTenantDirectory } from "../identity/index.js";
|
|
5
|
+
export async function provisionTenant(database, environment) {
|
|
6
|
+
const id = environment.IDENTITY_TENANT_ID ?? "default";
|
|
7
|
+
const tenant = await createIdentityTenantDirectory(database.database).active(id);
|
|
8
|
+
if (!tenant)
|
|
9
|
+
throw new HttpError(422, "tenant_missing", "Seed an active tenant before provisioning.");
|
|
10
|
+
const existing = await database.database
|
|
11
|
+
.selectFrom("tenant_connections")
|
|
12
|
+
.selectAll()
|
|
13
|
+
.where("tenant_id", "=", id)
|
|
14
|
+
.executeTakeFirst();
|
|
15
|
+
if (existing)
|
|
16
|
+
return { tenantId: id, status: "existing" };
|
|
17
|
+
const fingerprint = createHash("sha256").update(id).digest("hex").slice(0, 16);
|
|
18
|
+
const { driver } = readDatabaseConfiguration(environment);
|
|
19
|
+
const databaseName = driver === "mariadb"
|
|
20
|
+
? `${(environment.DB_MASTER_NAME ?? "master").slice(0, 30)}_tenant_${fingerprint}`
|
|
21
|
+
: null;
|
|
22
|
+
const sqlitePath = driver === "sqlite"
|
|
23
|
+
? join(dirname(resolve(environment.DB_SQLITE_PATH ?? "storage/private/data/identity.sqlite")), `tenant-${fingerprint}.sqlite`)
|
|
24
|
+
: null;
|
|
25
|
+
const target = { key: id, driver, databaseName, sqlitePath, version: 1 };
|
|
26
|
+
await database.provisionConnection(target);
|
|
27
|
+
// Register only after storage migrations succeed. Reruns preserve the existing mapping.
|
|
28
|
+
await database.database
|
|
29
|
+
.insertInto("tenant_connections")
|
|
30
|
+
.values({
|
|
31
|
+
tenant_id: id,
|
|
32
|
+
driver,
|
|
33
|
+
database_name: databaseName,
|
|
34
|
+
sqlite_path: sqlitePath,
|
|
35
|
+
active: 1
|
|
36
|
+
})
|
|
37
|
+
.onConflict((conflict) => conflict.column("tenant_id").doNothing())
|
|
38
|
+
.execute();
|
|
39
|
+
return { tenantId: id, status: "provisioned" };
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IdentityTenantDirectory } from "../identity/index.js";
|
|
2
|
+
import { type DatabaseInfrastructureSchema } from "@devxcrew/framework";
|
|
3
|
+
import { TenantRepository } from "./tenant.repository.js";
|
|
4
|
+
import type { TenantDatabase, TenantPrincipal, TenantScope } from "./tenant.types.js";
|
|
5
|
+
export declare class TenantService<Schema extends DatabaseInfrastructureSchema = DatabaseInfrastructureSchema> {
|
|
6
|
+
private readonly repository;
|
|
7
|
+
private readonly directory;
|
|
8
|
+
private readonly connections;
|
|
9
|
+
private readonly mode;
|
|
10
|
+
private readonly clientId;
|
|
11
|
+
private readonly context;
|
|
12
|
+
constructor(repository: TenantRepository, directory: IdentityTenantDirectory, connections: TenantDatabase<Schema>, mode: "single-client" | "multi-tenant", clientId: string);
|
|
13
|
+
current(): TenantScope<Schema>;
|
|
14
|
+
verify(): Promise<void>;
|
|
15
|
+
withPrincipal<T>(principal: TenantPrincipal, requested: string | undefined, work: () => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { HttpError } from "@devxcrew/framework";
|
|
3
|
+
import { DatabaseCapacityError, ResumableTransfer, DatabaseExecution } from "@devxcrew/framework";
|
|
4
|
+
import { tenantMappingSchema } from "./tenant.schema.js";
|
|
5
|
+
export class TenantService {
|
|
6
|
+
repository;
|
|
7
|
+
directory;
|
|
8
|
+
connections;
|
|
9
|
+
mode;
|
|
10
|
+
clientId;
|
|
11
|
+
context = new AsyncLocalStorage();
|
|
12
|
+
constructor(repository, directory, connections, mode, clientId) {
|
|
13
|
+
this.repository = repository;
|
|
14
|
+
this.directory = directory;
|
|
15
|
+
this.connections = connections;
|
|
16
|
+
this.mode = mode;
|
|
17
|
+
this.clientId = clientId;
|
|
18
|
+
}
|
|
19
|
+
current() {
|
|
20
|
+
const scope = this.context.getStore();
|
|
21
|
+
if (!scope)
|
|
22
|
+
throw new HttpError(401, "tenant_context_required", "An authenticated tenant context is required.");
|
|
23
|
+
return scope;
|
|
24
|
+
}
|
|
25
|
+
verify() {
|
|
26
|
+
return this.repository.verify();
|
|
27
|
+
}
|
|
28
|
+
async withPrincipal(principal, requested, work, signal) {
|
|
29
|
+
signal?.throwIfAborted();
|
|
30
|
+
const id = principal.tenant.id;
|
|
31
|
+
if (!id ||
|
|
32
|
+
(requested && requested !== id) ||
|
|
33
|
+
(this.mode === "single-client" && id !== this.clientId))
|
|
34
|
+
throw new HttpError(403, "tenant_denied", "The session does not authorize this tenant.");
|
|
35
|
+
const activeTenant = await this.directory.active(id);
|
|
36
|
+
const mapping = await this.repository.find(id);
|
|
37
|
+
if (!activeTenant || !mapping || Number(mapping.active) !== 1)
|
|
38
|
+
throw new HttpError(403, "tenant_unavailable", "No active tenant database is available.");
|
|
39
|
+
const target = tenantMappingSchema.safeParse({
|
|
40
|
+
tenantId: id,
|
|
41
|
+
driver: mapping.driver,
|
|
42
|
+
databaseName: mapping.databaseName,
|
|
43
|
+
sqlitePath: mapping.sqlitePath,
|
|
44
|
+
active: Number(mapping.active),
|
|
45
|
+
version: Number(mapping.version)
|
|
46
|
+
});
|
|
47
|
+
if (!target.success)
|
|
48
|
+
throw new HttpError(503, "tenant_mapping_invalid", "Tenant database configuration is invalid.");
|
|
49
|
+
return this.connections
|
|
50
|
+
.withConnection({
|
|
51
|
+
key: id,
|
|
52
|
+
driver: target.data.driver,
|
|
53
|
+
databaseName: target.data.databaseName,
|
|
54
|
+
sqlitePath: target.data.sqlitePath,
|
|
55
|
+
version: target.data.version
|
|
56
|
+
}, async (database) => {
|
|
57
|
+
signal?.throwIfAborted();
|
|
58
|
+
return this.context.run({
|
|
59
|
+
tenantId: id,
|
|
60
|
+
principal,
|
|
61
|
+
database,
|
|
62
|
+
data: new DatabaseExecution(database),
|
|
63
|
+
transfers: new ResumableTransfer(database)
|
|
64
|
+
}, work);
|
|
65
|
+
})
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
if (error instanceof DatabaseCapacityError)
|
|
68
|
+
throw new HttpError(503, "tenant_busy", "Tenant connection capacity is currently busy.");
|
|
69
|
+
throw error;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ResumableTransfer } from "@devxcrew/framework";
|
|
2
|
+
import type { Principal, Portal, IdentitySchema } from "../identity/index.js";
|
|
3
|
+
import type { Generated, Kysely } from "kysely";
|
|
4
|
+
import type { IncomingMessage } from "node:http";
|
|
5
|
+
import type { DatabaseInfrastructureSchema, ConnectionTarget, DatabaseExecution } from "@devxcrew/framework";
|
|
6
|
+
export type TenantPrincipal = Principal;
|
|
7
|
+
export interface TenantIdentity {
|
|
8
|
+
authenticateRequest(request: IncomingMessage, portal: Portal, signal?: AbortSignal): Promise<Principal>;
|
|
9
|
+
}
|
|
10
|
+
export interface TenantRegistrySchema {
|
|
11
|
+
tenant_connections: {
|
|
12
|
+
tenant_id: string;
|
|
13
|
+
driver: "sqlite" | "mariadb";
|
|
14
|
+
database_name: string | null;
|
|
15
|
+
sqlite_path: string | null;
|
|
16
|
+
active: number;
|
|
17
|
+
version: Generated<number>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface TenantMasterSchema extends IdentitySchema, TenantRegistrySchema, DatabaseInfrastructureSchema {
|
|
21
|
+
}
|
|
22
|
+
export interface TenantScope<Schema extends DatabaseInfrastructureSchema = DatabaseInfrastructureSchema> {
|
|
23
|
+
tenantId: string;
|
|
24
|
+
principal: Principal;
|
|
25
|
+
database: Kysely<Schema>;
|
|
26
|
+
data: DatabaseExecution<Schema>;
|
|
27
|
+
transfers: ResumableTransfer<Schema>;
|
|
28
|
+
}
|
|
29
|
+
export interface TenantProvider<Schema extends DatabaseInfrastructureSchema = DatabaseInfrastructureSchema> {
|
|
30
|
+
handle(request: IncomingMessage, response: import("node:http").ServerResponse, signal?: AbortSignal): boolean | Promise<boolean>;
|
|
31
|
+
verify(): Promise<void>;
|
|
32
|
+
runRequest<T>(request: IncomingMessage, work: () => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
33
|
+
withPrincipal<T>(principal: Principal, requestedTenant: string | undefined, work: () => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
34
|
+
current(): TenantScope<Schema>;
|
|
35
|
+
}
|
|
36
|
+
export interface TenantDatabase<Schema extends DatabaseInfrastructureSchema = DatabaseInfrastructureSchema> {
|
|
37
|
+
database: Kysely<TenantMasterSchema>;
|
|
38
|
+
withConnection<T>(target: ConnectionTarget, work: (database: Kysely<Schema>) => Promise<T>): Promise<T>;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devxcrew/platform",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/devxcrew/platform.git"
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"node": ">=26.10.0"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
28
28
|
"prepack": "npm run build",
|
|
29
|
-
"test": "tsx --test src/modules/identity/*.test.ts",
|
|
29
|
+
"test": "tsx --test src/modules/identity/composition/tests/*.test.ts src/modules/tenant/tests/*.test.ts",
|
|
30
30
|
"mcp:connect": "node agent/connect.mjs",
|
|
31
31
|
"mcp:verify": "node agent/connect.mjs --strict",
|
|
32
32
|
"version-bump": "devxcrew-tools version:bump",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"zod": "^4.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@devxcrew/
|
|
52
|
+
"@devxcrew/framework": "0.1.12",
|
|
53
|
+
"@devxcrew/tools": "0.1.8",
|
|
53
54
|
"@types/node": "^26.0.0",
|
|
54
55
|
"tsx": "^4.23.12",
|
|
55
56
|
"typescript": "7.0.2"
|
|
@@ -58,5 +59,8 @@
|
|
|
58
59
|
"access": "public",
|
|
59
60
|
"registry": "https://registry.npmjs.org/"
|
|
60
61
|
},
|
|
61
|
-
"license": "MIT"
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@devxcrew/framework": ">=0.1.12 <1"
|
|
65
|
+
}
|
|
62
66
|
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type Kysely } from "kysely";
|
|
2
|
-
import type { IdentitySchema, Principal } from "./identity.types.js";
|
|
3
|
-
import type { IdentityListQuery, IdentityResource } from "./identity.administration-schema.js";
|
|
4
|
-
export declare class IdentityAdministrationRepository {
|
|
5
|
-
private readonly db;
|
|
6
|
-
constructor(db: Kysely<IdentitySchema>);
|
|
7
|
-
list(actor: Principal, resource: IdentityResource, query: IdentityListQuery): Promise<{
|
|
8
|
-
data: Record<string, unknown>[];
|
|
9
|
-
meta: {
|
|
10
|
-
page: number;
|
|
11
|
-
perPage: number;
|
|
12
|
-
total: number;
|
|
13
|
-
lastPage: number;
|
|
14
|
-
};
|
|
15
|
-
}>;
|
|
16
|
-
show(actor: Principal, resource: IdentityResource, id: string): Promise<Record<string, unknown> | undefined>;
|
|
17
|
-
private source;
|
|
18
|
-
private present;
|
|
19
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { sql } from "kysely";
|
|
2
|
-
import { IdentityError } from "./identity.error.js";
|
|
3
|
-
export class IdentityAdministrationRepository {
|
|
4
|
-
db;
|
|
5
|
-
constructor(db) {
|
|
6
|
-
this.db = db;
|
|
7
|
-
}
|
|
8
|
-
async list(actor, resource, query) {
|
|
9
|
-
const source = this.source(actor, resource);
|
|
10
|
-
const fields = resource === "users"
|
|
11
|
-
? ["id", "name", "email"]
|
|
12
|
-
: resource === "organizations" || resource === "roles"
|
|
13
|
-
? ["id", "name"]
|
|
14
|
-
: resource === "memberships"
|
|
15
|
-
? ["id", "userName", "organizationName", "roleName"]
|
|
16
|
-
: ["id"];
|
|
17
|
-
if (!fields.includes(query.sort))
|
|
18
|
-
throw new IdentityError(422, "This sort field is not supported for this resource.");
|
|
19
|
-
const search = query.search
|
|
20
|
-
? sql `where ${sql.join(fields.map((field) => sql `lower(cast(${sql.ref(field)} as text)) like ${`%${query.search.toLowerCase()}%`}`), sql ` or `)}`
|
|
21
|
-
: sql ``;
|
|
22
|
-
const count = await sql `select count(*) as total from (${source}) as resources ${search}`.execute(this.db);
|
|
23
|
-
const sort = query.sort;
|
|
24
|
-
const rows = await sql `select * from (${source}) as resources ${search}
|
|
25
|
-
order by ${sql.ref(sort)} ${query.direction === "asc" ? sql `asc` : sql `desc`}, id asc
|
|
26
|
-
limit ${query.perPage} offset ${(query.page - 1) * query.perPage}`.execute(this.db);
|
|
27
|
-
const total = Number(count.rows[0].total);
|
|
28
|
-
return {
|
|
29
|
-
data: rows.rows.map((row) => this.present(resource, row)),
|
|
30
|
-
meta: {
|
|
31
|
-
page: query.page,
|
|
32
|
-
perPage: query.perPage,
|
|
33
|
-
total,
|
|
34
|
-
lastPage: Math.max(1, Math.ceil(total / query.perPage)),
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
async show(actor, resource, id) {
|
|
39
|
-
const result = await sql `select * from (${this.source(actor, resource)}) as resources where id = ${id} limit 1`.execute(this.db);
|
|
40
|
-
return result.rows[0] ? this.present(resource, result.rows[0]) : undefined;
|
|
41
|
-
}
|
|
42
|
-
source(actor, resource) {
|
|
43
|
-
const global = actor.portal === "super-admin";
|
|
44
|
-
if (resource === "users")
|
|
45
|
-
return sql `select u.id,u.name,u.email,u.active,u.version from identity_users u
|
|
46
|
-
where exists (select 1 from identity_memberships m left join identity_custom_roles c on c.id=m.custom_role_id
|
|
47
|
-
where m.user_id=u.id and (m.custom_role_id is null or c.app_id=${actor.appId})
|
|
48
|
-
${global ? sql `` : sql `and m.tenant_id=${actor.tenant.id}`})
|
|
49
|
-
${global ? sql `or not exists(select 1 from identity_memberships m where m.user_id=u.id)` : sql ``}`;
|
|
50
|
-
if (resource === "organizations")
|
|
51
|
-
return sql `select id,name,active,version from identity_tenants ${global ? sql `` : sql `where id=${actor.tenant.id}`}`;
|
|
52
|
-
if (resource === "memberships")
|
|
53
|
-
return sql `select m.user_id||'~'||m.tenant_id||'~'||m.role_id as id,m.user_id as userId,m.tenant_id as tenantId,
|
|
54
|
-
coalesce(m.custom_role_id,m.role_id) as roleId,m.role_id as portal,m.active,m.version,u.name as userName,t.name as organizationName,
|
|
55
|
-
coalesce(c.name,m.role_id) as roleName from identity_memberships m
|
|
56
|
-
join identity_users u on u.id=m.user_id join identity_tenants t on t.id=m.tenant_id
|
|
57
|
-
left join identity_custom_roles c on c.id=m.custom_role_id
|
|
58
|
-
where (m.custom_role_id is null or c.app_id=${actor.appId}) ${global ? sql `` : sql `and m.tenant_id=${actor.tenant.id}`}`;
|
|
59
|
-
if (resource === "roles")
|
|
60
|
-
return sql `select r.id,r.id as name,r.id as portal,1 as system,null as tenantId,1 as active,r.version,(select json_group_array(permission_id) from identity_role_permissions p where p.role_id=r.id) as permissionIds from identity_roles r
|
|
61
|
-
union all select c.id,c.name,'user' as portal,0 as system,c.tenant_id as tenantId,c.active,c.version,
|
|
62
|
-
(select json_group_array(permission_id) from identity_custom_role_permissions p where p.role_id=c.id) as permissionIds
|
|
63
|
-
from identity_custom_roles c where c.app_id=${actor.appId} ${global ? sql `` : sql `and c.tenant_id=${actor.tenant.id}`}`;
|
|
64
|
-
if (resource === "permissions")
|
|
65
|
-
return sql `select p.id,coalesce(d.label,p.id) as label,
|
|
66
|
-
coalesce(d.owner,case when p.id like 'desk.%' then 'desk' else 'identity' end) as owner,
|
|
67
|
-
d.app_id as appId,
|
|
68
|
-
coalesce(d.portals,case when p.id='desk.user' then '["user"]' when p.id='desk.admin' then '["admin"]'
|
|
69
|
-
when p.id='desk.super-admin' then '["super-admin"]' when p.id='identity.manage' then '["admin","super-admin"]'
|
|
70
|
-
else '["user","admin","super-admin"]' end) as portals
|
|
71
|
-
from identity_permissions p left join identity_permission_declarations d on d.permission_id=p.id
|
|
72
|
-
where d.permission_id is null or d.app_id=${actor.appId}`;
|
|
73
|
-
if (resource === "sessions")
|
|
74
|
-
return sql `select token_hash as id,user_id as userId,tenant_id as tenantId,portal,expires_at as expiresAt from identity_sessions
|
|
75
|
-
where app_id=${actor.appId} and expires_at>${new Date().toISOString()}
|
|
76
|
-
${global ? sql `` : sql `and tenant_id=${actor.tenant.id}`}
|
|
77
|
-
${actor.portal === "user" ? sql `and user_id=${actor.user.id}` : sql ``}`;
|
|
78
|
-
return sql `select id,actor_id as actorId,tenant_id as tenantId,action,resource_id as resourceId,created_at as createdAt
|
|
79
|
-
from identity_audit_events where app_id=${actor.appId} ${global ? sql `` : sql `and tenant_id=${actor.tenant.id}`}`;
|
|
80
|
-
}
|
|
81
|
-
present(resource, row) {
|
|
82
|
-
if (resource === "permissions")
|
|
83
|
-
return { ...row, portals: JSON.parse(String(row.portals)) };
|
|
84
|
-
if (resource === "roles")
|
|
85
|
-
return {
|
|
86
|
-
...row,
|
|
87
|
-
version: Number(row.version),
|
|
88
|
-
active: Boolean(row.active),
|
|
89
|
-
system: Boolean(row.system),
|
|
90
|
-
permissionIds: JSON.parse(String(row.permissionIds)),
|
|
91
|
-
};
|
|
92
|
-
if (resource === "users" ||
|
|
93
|
-
resource === "organizations" ||
|
|
94
|
-
resource === "memberships")
|
|
95
|
-
return {
|
|
96
|
-
...row,
|
|
97
|
-
active: Boolean(row.active),
|
|
98
|
-
version: Number(row.version),
|
|
99
|
-
};
|
|
100
|
-
return row;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export declare const resourceIdSchema: z.ZodString;
|
|
3
|
-
export declare const listSchema: z.ZodObject<{
|
|
4
|
-
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
5
|
-
perPage: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
6
|
-
search: z.ZodDefault<z.ZodString>;
|
|
7
|
-
sort: z.ZodDefault<z.ZodEnum<{
|
|
8
|
-
email: "email";
|
|
9
|
-
id: "id";
|
|
10
|
-
name: "name";
|
|
11
|
-
}>>;
|
|
12
|
-
direction: z.ZodDefault<z.ZodEnum<{
|
|
13
|
-
asc: "asc";
|
|
14
|
-
desc: "desc";
|
|
15
|
-
}>>;
|
|
16
|
-
}, z.core.$strict>;
|
|
17
|
-
export declare const resourceListQuerySchema: z.ZodPipe<z.ZodObject<{
|
|
18
|
-
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
19
|
-
search: z.ZodDefault<z.ZodString>;
|
|
20
|
-
sort: z.ZodDefault<z.ZodEnum<{
|
|
21
|
-
email: "email";
|
|
22
|
-
id: "id";
|
|
23
|
-
name: "name";
|
|
24
|
-
}>>;
|
|
25
|
-
direction: z.ZodDefault<z.ZodEnum<{
|
|
26
|
-
asc: "asc";
|
|
27
|
-
desc: "desc";
|
|
28
|
-
}>>;
|
|
29
|
-
per_page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
30
|
-
}, z.core.$strict>, z.ZodTransform<{
|
|
31
|
-
page: number;
|
|
32
|
-
search: string;
|
|
33
|
-
sort: "email" | "id" | "name";
|
|
34
|
-
direction: "asc" | "desc";
|
|
35
|
-
perPage: number;
|
|
36
|
-
}, {
|
|
37
|
-
page: number;
|
|
38
|
-
search: string;
|
|
39
|
-
sort: "email" | "id" | "name";
|
|
40
|
-
direction: "asc" | "desc";
|
|
41
|
-
per_page: number;
|
|
42
|
-
}>>;
|
|
43
|
-
export declare const membershipDeleteQuerySchema: z.ZodObject<{
|
|
44
|
-
expectedVersion: z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>;
|
|
45
|
-
}, z.core.$strict>;
|
|
46
|
-
export declare const userCreateSchema: z.ZodObject<{
|
|
47
|
-
name: z.ZodString;
|
|
48
|
-
email: z.ZodPipe<z.ZodEmail, z.ZodTransform<string, string>>;
|
|
49
|
-
password: z.ZodString;
|
|
50
|
-
roleId: z.ZodDefault<z.ZodString>;
|
|
51
|
-
tenantId: z.ZodOptional<z.ZodString>;
|
|
52
|
-
}, z.core.$strict>;
|
|
53
|
-
export declare const userUpdateSchema: z.ZodObject<{
|
|
54
|
-
name: z.ZodOptional<z.ZodString>;
|
|
55
|
-
email: z.ZodOptional<z.ZodPipe<z.ZodEmail, z.ZodTransform<string, string>>>;
|
|
56
|
-
active: z.ZodOptional<z.ZodBoolean>;
|
|
57
|
-
expectedVersion: z.ZodNumber;
|
|
58
|
-
}, z.core.$strict>;
|
|
59
|
-
export declare const organizationCreateSchema: z.ZodObject<{
|
|
60
|
-
id: z.ZodString;
|
|
61
|
-
name: z.ZodString;
|
|
62
|
-
active: z.ZodDefault<z.ZodBoolean>;
|
|
63
|
-
}, z.core.$strict>;
|
|
64
|
-
export declare const organizationUpdateSchema: z.ZodObject<{
|
|
65
|
-
name: z.ZodOptional<z.ZodString>;
|
|
66
|
-
active: z.ZodOptional<z.ZodBoolean>;
|
|
67
|
-
expectedVersion: z.ZodNumber;
|
|
68
|
-
}, z.core.$strict>;
|
|
69
|
-
export declare const membershipSchema: z.ZodObject<{
|
|
70
|
-
userId: z.ZodString;
|
|
71
|
-
tenantId: z.ZodOptional<z.ZodString>;
|
|
72
|
-
roleId: z.ZodString;
|
|
73
|
-
}, z.core.$strict>;
|
|
74
|
-
export declare const roleUpdateSchema: z.ZodObject<{
|
|
75
|
-
permissionIds: z.ZodArray<z.ZodString>;
|
|
76
|
-
expectedVersion: z.ZodNumber;
|
|
77
|
-
}, z.core.$strict>;
|
|
78
|
-
export declare const profileSchema: z.ZodObject<{
|
|
79
|
-
name: z.ZodString;
|
|
80
|
-
expectedVersion: z.ZodNumber;
|
|
81
|
-
}, z.core.$strict>;
|
|
82
|
-
export declare const customRoleCreateSchema: z.ZodObject<{
|
|
83
|
-
name: z.ZodString;
|
|
84
|
-
permissionIds: z.ZodArray<z.ZodString>;
|
|
85
|
-
tenantId: z.ZodOptional<z.ZodString>;
|
|
86
|
-
}, z.core.$strict>;
|
|
87
|
-
export declare const customRoleUpdateSchema: z.ZodObject<{
|
|
88
|
-
name: z.ZodOptional<z.ZodString>;
|
|
89
|
-
permissionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
90
|
-
active: z.ZodOptional<z.ZodBoolean>;
|
|
91
|
-
expectedVersion: z.ZodNumber;
|
|
92
|
-
}, z.core.$strict>;
|
|
93
|
-
export declare const membershipUpdateSchema: z.ZodObject<{
|
|
94
|
-
roleId: z.ZodString;
|
|
95
|
-
active: z.ZodBoolean;
|
|
96
|
-
expectedVersion: z.ZodNumber;
|
|
97
|
-
}, z.core.$strict>;
|
|
98
|
-
export declare const settingsSchema: z.ZodObject<{
|
|
99
|
-
displayName: z.ZodString;
|
|
100
|
-
expectedVersion: z.ZodNumber;
|
|
101
|
-
locale: z.ZodEnum<{
|
|
102
|
-
en: "en";
|
|
103
|
-
"en-GB": "en-GB";
|
|
104
|
-
"en-US": "en-US";
|
|
105
|
-
}>;
|
|
106
|
-
timeZone: z.ZodString;
|
|
107
|
-
}, z.core.$strict>;
|
|
108
|
-
export declare const securitySettingsSchema: z.ZodObject<{
|
|
109
|
-
sessionSeconds: z.ZodNumber;
|
|
110
|
-
expectedVersion: z.ZodNumber;
|
|
111
|
-
}, z.core.$strict>;
|
|
112
|
-
export type IdentityListQuery = z.infer<typeof listSchema>;
|
|
113
|
-
export type IdentityResource = "users" | "organizations" | "memberships" | "roles" | "permissions" | "sessions" | "audit-events";
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { identityKeySchema } from "./identity.schema.js";
|
|
3
|
-
export const resourceIdSchema = z
|
|
4
|
-
.string()
|
|
5
|
-
.regex(/^[a-zA-Z0-9._~-]{1,300}$/)
|
|
6
|
-
.refine((value) => !/^\.+$/.test(value), "Use an identifier with a letter or number.");
|
|
7
|
-
export const listSchema = z
|
|
8
|
-
.object({
|
|
9
|
-
page: z.coerce.number().int().min(1).max(100000).default(1),
|
|
10
|
-
perPage: z.coerce.number().int().min(1).max(100).default(20),
|
|
11
|
-
search: z.string().trim().max(100).default(""),
|
|
12
|
-
sort: z.enum(["id", "name", "email"]).default("id"),
|
|
13
|
-
direction: z.enum(["asc", "desc"]).default("asc"),
|
|
14
|
-
})
|
|
15
|
-
.strict();
|
|
16
|
-
export const resourceListQuerySchema = listSchema
|
|
17
|
-
.omit({ perPage: true })
|
|
18
|
-
.extend({ per_page: listSchema.shape.perPage })
|
|
19
|
-
.strict()
|
|
20
|
-
.transform(({ per_page, ...input }) => ({ ...input, perPage: per_page }));
|
|
21
|
-
export const membershipDeleteQuerySchema = z
|
|
22
|
-
.object({
|
|
23
|
-
expectedVersion: z
|
|
24
|
-
.string()
|
|
25
|
-
.regex(/^(0|[1-9][0-9]{0,9})$/)
|
|
26
|
-
.transform(Number),
|
|
27
|
-
})
|
|
28
|
-
.strict();
|
|
29
|
-
const name = z.string().trim().min(1).max(100);
|
|
30
|
-
const email = z
|
|
31
|
-
.email()
|
|
32
|
-
.max(254)
|
|
33
|
-
.transform((v) => v.trim().toLowerCase());
|
|
34
|
-
export const userCreateSchema = z
|
|
35
|
-
.object({
|
|
36
|
-
name,
|
|
37
|
-
email,
|
|
38
|
-
password: z.string().min(12).max(256),
|
|
39
|
-
roleId: resourceIdSchema.default("user"),
|
|
40
|
-
tenantId: identityKeySchema.optional(),
|
|
41
|
-
})
|
|
42
|
-
.strict();
|
|
43
|
-
const expectedVersion = z.number().int().min(0);
|
|
44
|
-
export const userUpdateSchema = z
|
|
45
|
-
.object({
|
|
46
|
-
name: name.optional(),
|
|
47
|
-
email: email.optional(),
|
|
48
|
-
active: z.boolean().optional(),
|
|
49
|
-
expectedVersion,
|
|
50
|
-
})
|
|
51
|
-
.strict()
|
|
52
|
-
.refine((v) => Object.keys(v).length > 1, "Provide a changed field.");
|
|
53
|
-
export const organizationCreateSchema = z
|
|
54
|
-
.object({ id: identityKeySchema, name, active: z.boolean().default(true) })
|
|
55
|
-
.strict();
|
|
56
|
-
export const organizationUpdateSchema = z
|
|
57
|
-
.object({
|
|
58
|
-
name: name.optional(),
|
|
59
|
-
active: z.boolean().optional(),
|
|
60
|
-
expectedVersion,
|
|
61
|
-
})
|
|
62
|
-
.strict()
|
|
63
|
-
.refine((v) => Object.keys(v).length > 1, "Provide a changed field.");
|
|
64
|
-
export const membershipSchema = z
|
|
65
|
-
.object({
|
|
66
|
-
userId: identityKeySchema,
|
|
67
|
-
tenantId: identityKeySchema.optional(),
|
|
68
|
-
roleId: resourceIdSchema,
|
|
69
|
-
})
|
|
70
|
-
.strict();
|
|
71
|
-
export const roleUpdateSchema = z
|
|
72
|
-
.object({
|
|
73
|
-
permissionIds: z.array(resourceIdSchema).max(100),
|
|
74
|
-
expectedVersion,
|
|
75
|
-
})
|
|
76
|
-
.strict();
|
|
77
|
-
export const profileSchema = z.object({ name, expectedVersion }).strict();
|
|
78
|
-
export const customRoleCreateSchema = z
|
|
79
|
-
.object({
|
|
80
|
-
name,
|
|
81
|
-
permissionIds: z.array(resourceIdSchema).max(100),
|
|
82
|
-
tenantId: identityKeySchema.optional(),
|
|
83
|
-
})
|
|
84
|
-
.strict();
|
|
85
|
-
export const customRoleUpdateSchema = z
|
|
86
|
-
.object({
|
|
87
|
-
name: name.optional(),
|
|
88
|
-
permissionIds: z.array(resourceIdSchema).max(100).optional(),
|
|
89
|
-
active: z.boolean().optional(),
|
|
90
|
-
expectedVersion,
|
|
91
|
-
})
|
|
92
|
-
.strict()
|
|
93
|
-
.refine((input) => Object.keys(input).length > 1, "Provide a changed field.");
|
|
94
|
-
export const membershipUpdateSchema = z
|
|
95
|
-
.object({ roleId: resourceIdSchema, active: z.boolean(), expectedVersion })
|
|
96
|
-
.strict();
|
|
97
|
-
export const settingsSchema = z
|
|
98
|
-
.object({
|
|
99
|
-
displayName: name,
|
|
100
|
-
expectedVersion,
|
|
101
|
-
locale: z.enum(["en", "en-US", "en-GB"]),
|
|
102
|
-
timeZone: z
|
|
103
|
-
.string()
|
|
104
|
-
.max(100)
|
|
105
|
-
.refine((v) => {
|
|
106
|
-
try {
|
|
107
|
-
new Intl.DateTimeFormat("en", { timeZone: v });
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}, "Use a supported IANA time zone."),
|
|
114
|
-
})
|
|
115
|
-
.strict();
|
|
116
|
-
export const securitySettingsSchema = z
|
|
117
|
-
.object({
|
|
118
|
-
sessionSeconds: z.number().int().min(300).max(86400),
|
|
119
|
-
expectedVersion,
|
|
120
|
-
})
|
|
121
|
-
.strict();
|