@astram/identity 0.9.0 → 0.9.1
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/dist/features/user/user.controller.d.ts +1 -0
- package/dist/features/user/user.controller.d.ts.map +1 -1
- package/dist/features/user/user.controller.js +2 -0
- package/dist/features/user/user.service.d.ts +7 -2
- package/dist/features/user/user.service.d.ts.map +1 -1
- package/dist/features/user/user.service.js +15 -4
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.controller.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.controller.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAOvD,qBAEa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAE/C;;;;OAIG;IAGG,SAAS,CAAU,KAAK,EAAE,YAAY;;;;;;IAM5C;;;OAGG;IAGG,UAAU,CACP,GAAG,EAAE,aAAa,EACjB,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;;;
|
|
1
|
+
{"version":3,"file":"user.controller.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.controller.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAOvD,qBAEa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAE/C;;;;OAIG;IAGG,SAAS,CAAU,KAAK,EAAE,YAAY;;;;;;IAM5C;;;OAGG;IAGG,UAAU,CACP,GAAG,EAAE,aAAa,EACjB,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;;;IAY3E;0CACsC;IAGtC,OAAO,CAA0B,IAAI,EAAE,MAAM;IAI7C,iGAAiG;IAG3F,UAAU,CACP,GAAG,EAAE,aAAa,EACA,IAAI,EAAE,MAAM,EAC7B,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;;;IAUtE,0FAA0F;IAGpF,UAAU,CAAQ,GAAG,EAAE,aAAa,EAA2B,IAAI,EAAE,MAAM;;;CAIlF"}
|
|
@@ -45,6 +45,8 @@ let UserController = class UserController {
|
|
|
45
45
|
const companyUuid = (0, guard_1.optionalUuidField)(body?.companyUuid, 'companyUuid');
|
|
46
46
|
const id = await this.users.createUser(req.principal, {
|
|
47
47
|
username: body?.username ?? 'Untitled',
|
|
48
|
+
// KI #94: the template form sends it; the service canonicalises and validates it.
|
|
49
|
+
...(typeof body?.email === 'string' ? { email: body.email } : {}),
|
|
48
50
|
...(companyUuid !== undefined ? { companyUuid } : {}),
|
|
49
51
|
});
|
|
50
52
|
return { id };
|
|
@@ -45,11 +45,16 @@ export declare class UserService {
|
|
|
45
45
|
* Create a user. With `companyUuid`, the user is created AND attached (one active membership) in
|
|
46
46
|
* ONE transaction — the onboarding path for a non-root admin, whose membership create is checked
|
|
47
47
|
* by the engine's create wall (a company outside the caller's subtree ⇒ 403, nothing persists).
|
|
48
|
-
* A username already taken (KI #87: also a concurrent create of the same one; the unique
|
|
49
|
-
*
|
|
48
|
+
* A username or email already taken (KI #87: also a concurrent create of the same one; the unique
|
|
49
|
+
* indexes decide) ⇒ {@link IdentityConflictError} (409), nothing persists.
|
|
50
|
+
*
|
|
51
|
+
* KI #94: an `email` is stored canonical (the ONE address rule, as the email-change flow); a
|
|
52
|
+
* malformed one ⇒ {@link IdentityBadRequestError} (400) before any write; a blank one is no email.
|
|
53
|
+
* A new user has no credential yet, so no login hint moves.
|
|
50
54
|
*/
|
|
51
55
|
createUser(actor: Principal, input: {
|
|
52
56
|
username: string;
|
|
57
|
+
email?: string | undefined;
|
|
53
58
|
companyUuid?: string | undefined;
|
|
54
59
|
}): Promise<RecordId>;
|
|
55
60
|
/** List users (tenant-scoped by the pipe), with paging/search/sort. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAOL,KAAK,mBAAmB,EAExB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAqCzD,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAGxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IACY,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAMtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAK1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAzBlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;gBAGpC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAGrB,WAAW,CAAC,GAAE,eAAe,GAAG,IAAI,aAAA,EACK,WAAW,CAAC,GAAE,WAAW,GAAG,IAAI,aAAA,EAMzE,QAAQ,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAKhC,WAAW,CAAC,GAAE,kBAAkB,GAAG,IAAI,aAAA,EAIvC,cAAc,CAAC,GAAE,mBAAmB,GAAG,IAAI,aAAA;IAG9D
|
|
1
|
+
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../src/features/user/user.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAOL,KAAK,mBAAmB,EAExB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAqCzD,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAGxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IACY,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAMtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAK1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAzBlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;gBAGpC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAGrB,WAAW,CAAC,GAAE,eAAe,GAAG,IAAI,aAAA,EACK,WAAW,CAAC,GAAE,WAAW,GAAG,IAAI,aAAA,EAMzE,QAAQ,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAKhC,WAAW,CAAC,GAAE,kBAAkB,GAAG,IAAI,aAAA,EAIvC,cAAc,CAAC,GAAE,mBAAmB,GAAG,IAAI,aAAA;IAG9D;;;;;;;;;;OAUG;IACG,UAAU,CACd,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GACxF,OAAO,CAAC,QAAQ,CAAC;IAsBpB,uEAAuE;IACvE,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU;IAI7B,0BAA0B;IAC1B,OAAO,CAAC,IAAI,EAAE,MAAM;IAIpB,mGAAmG;IAC7F,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCjF;;;;;;OAMG;YACW,WAAW;IAyBzB,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IA8BxB;;;;;;;;;OASG;YACW,iBAAiB;IAY/B,uDAAuD;IACjD,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/D,6FAA6F;YAC/E,kBAAkB;CAkBjC"}
|
|
@@ -92,16 +92,27 @@ let UserService = UserService_1 = class UserService {
|
|
|
92
92
|
* Create a user. With `companyUuid`, the user is created AND attached (one active membership) in
|
|
93
93
|
* ONE transaction — the onboarding path for a non-root admin, whose membership create is checked
|
|
94
94
|
* by the engine's create wall (a company outside the caller's subtree ⇒ 403, nothing persists).
|
|
95
|
-
* A username already taken (KI #87: also a concurrent create of the same one; the unique
|
|
96
|
-
*
|
|
95
|
+
* A username or email already taken (KI #87: also a concurrent create of the same one; the unique
|
|
96
|
+
* indexes decide) ⇒ {@link IdentityConflictError} (409), nothing persists.
|
|
97
|
+
*
|
|
98
|
+
* KI #94: an `email` is stored canonical (the ONE address rule, as the email-change flow); a
|
|
99
|
+
* malformed one ⇒ {@link IdentityBadRequestError} (400) before any write; a blank one is no email.
|
|
100
|
+
* A new user has no credential yet, so no login hint moves.
|
|
97
101
|
*/
|
|
98
102
|
async createUser(actor, input) {
|
|
103
|
+
const fields = { username: input.username };
|
|
104
|
+
const email = typeof input.email === 'string' ? (0, guard_1.canonicalEmail)(input.email) : '';
|
|
105
|
+
if (email !== '') {
|
|
106
|
+
if (!(0, guard_1.isEmailShaped)(email))
|
|
107
|
+
throw new identity_errors_js_1.IdentityBadRequestError('Enter a valid email address.');
|
|
108
|
+
fields.email = email;
|
|
109
|
+
}
|
|
99
110
|
if (!input.companyUuid) {
|
|
100
|
-
return mappingDuplicates(() => this.records.create('user', { fields
|
|
111
|
+
return mappingDuplicates(() => this.records.create('user', { fields }));
|
|
101
112
|
}
|
|
102
113
|
const companyUuid = input.companyUuid;
|
|
103
114
|
return mappingDuplicates(() => this.records.transaction(async (tx) => {
|
|
104
|
-
const id = await tx.create('user', { fields
|
|
115
|
+
const id = await tx.create('user', { fields });
|
|
105
116
|
await tx.create('company_membership', {
|
|
106
117
|
fields: { userUuid: id, companyUuid, isActive: true, status: 'active' },
|
|
107
118
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astram/identity",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Astram framework — the framework-owned identity + tenancy model. Hosts the identity @ObjectType classes (user, company, membership, posting), framework-authored identity migrations, and the identity resolver. Top of the dependency graph: depends on @astram/engine (for @ObjectType/@Field decorators) + @astram/guard / @astram/core (for the auth ports).",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"mariadb": "^3.5.4",
|
|
39
39
|
"@astram/core": "1.4.0",
|
|
40
40
|
"@astram/engine": "0.5.2",
|
|
41
|
-
"@astram/guard": "0.11.
|
|
41
|
+
"@astram/guard": "0.11.3"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@nestjs/common": "^11",
|