@temboplus/tembo-dashboard 0.7.1 → 0.8.0-rc.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.
@@ -0,0 +1,6 @@
1
+ export * from "./team.api-contract.js";
2
+ export * from "./team.query.js";
3
+ export * from "./team.repository.js";
4
+ export * from "./team.types.js";
5
+ export * from "./team-member.model.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/team/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { USER_ROLE } from "../auth/auth.dtos.js";
2
+ export interface TeamMemberRoleInfo {
3
+ label: string;
4
+ /** Human-readable summary of what the role can do. */
5
+ description: string;
6
+ }
7
+ export declare const TEAM_MEMBER_ROLE_INFO: Record<USER_ROLE, TeamMemberRoleInfo>;
8
+ /**
9
+ * Raw team member data as returned by the API.
10
+ */
11
+ export interface TeamMemberData {
12
+ id: string;
13
+ name: string;
14
+ identity: string;
15
+ vendorId: string;
16
+ role: USER_ROLE;
17
+ createdAt: string;
18
+ updatedAt: string;
19
+ }
20
+ /**
21
+ * A team member — a login belonging to the signed-in admin's organisation.
22
+ * `identity` is the member's email and login username, and cannot change.
23
+ */
24
+ export declare class TeamMember {
25
+ readonly id: string;
26
+ readonly name: string;
27
+ readonly identity: string;
28
+ readonly vendorId: string;
29
+ readonly role: USER_ROLE;
30
+ readonly createdAt?: Date;
31
+ readonly updatedAt?: Date;
32
+ private readonly _originalData;
33
+ private constructor();
34
+ /**
35
+ * Create a TeamMember from unknown data, validated against the API schema.
36
+ * Returns `undefined` (and logs) when the data is invalid.
37
+ */
38
+ static from(data: unknown): TeamMember | undefined;
39
+ /**
40
+ * Create TeamMembers from an array, skipping invalid entries.
41
+ */
42
+ static createMany(dataArray: unknown[]): TeamMember[];
43
+ /**
44
+ * Create a TeamMember from its JSON representation.
45
+ */
46
+ static fromJSON(json: TeamMemberData): TeamMember | undefined;
47
+ /**
48
+ * Type guard for TeamMember instances.
49
+ */
50
+ static is(obj: unknown): obj is TeamMember;
51
+ /** The member's email (their identity). */
52
+ get email(): string;
53
+ /** Display information for the member's role. */
54
+ get roleInfo(): TeamMemberRoleInfo;
55
+ /**
56
+ * Display name, falling back to identity when the name is blank.
57
+ */
58
+ getDisplayName(): string;
59
+ /**
60
+ * Up to two initials from the display name (for avatars).
61
+ */
62
+ getInitials(): string;
63
+ hasRole(role: USER_ROLE): boolean;
64
+ isAdmin(): boolean;
65
+ /**
66
+ * Whether this member is the signed-in user, compared by identity
67
+ * (unique and immutable). Use it to lock the role field on the admin's
68
+ * own row — the API rejects an admin changing their own role.
69
+ *
70
+ * @param identity - The signed-in user's identity (email).
71
+ */
72
+ isSelf(identity: string | null | undefined): boolean;
73
+ /**
74
+ * Convert to JSON representation (same shape as TeamMemberData).
75
+ */
76
+ toJSON(): TeamMemberData;
77
+ }
78
+ //# sourceMappingURL=team-member.model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-member.model.d.ts","sourceRoot":"","sources":["../../../src/modules/team/team-member.model.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAKjD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;CACrB;AAKD,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,SAAS,EAAE,kBAAkB,CAmBvE,CAAC;AAyBF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;GAGG;AACH,qBAAa,UAAU;IACrB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAChC,SAAgB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjC,SAAgB,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiB;IAE/C,OAAO;IAaP;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS;IASlD;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE;IAWrD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,GAAG,SAAS;IAI7D;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU;IAM1C,2CAA2C;IAC3C,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,iDAAiD;IACjD,IAAI,QAAQ,IAAI,kBAAkB,CAEjC;IAID;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,WAAW,IAAI,MAAM;IASrB,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO;IAIjC,OAAO,IAAI,OAAO;IAIlB;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAOpD;;OAEG;IACH,MAAM,IAAI,cAAc;CAGzB"}
@@ -0,0 +1,261 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Team management endpoints (the API's `/user` endpoints). All of them are
4
+ * Admin-only (403 for any other role) and scoped server-side to the
5
+ * signed-in admin's organisation — no organisation/vendor id is ever sent.
6
+ */
7
+ export declare const teamContract: {
8
+ getTeamMembers: {
9
+ query: z.ZodObject<{
10
+ id: z.ZodOptional<z.ZodString>;
11
+ name: z.ZodOptional<z.ZodString>;
12
+ identity: z.ZodOptional<z.ZodString>;
13
+ role: z.ZodOptional<z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>>;
14
+ "name:like": z.ZodOptional<z.ZodString>;
15
+ "identity:like": z.ZodOptional<z.ZodString>;
16
+ orderBy: z.ZodOptional<z.ZodString>;
17
+ range: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$strip>;
19
+ summary: "List team members";
20
+ description: string;
21
+ method: "GET";
22
+ path: "";
23
+ responses: {
24
+ 200: z.ZodArray<z.ZodObject<{
25
+ id: z.ZodString;
26
+ name: z.ZodString;
27
+ identity: z.ZodString;
28
+ vendorId: z.ZodString;
29
+ role: z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>;
30
+ createdAt: z.ZodString;
31
+ updatedAt: z.ZodString;
32
+ }, z.core.$strip>>;
33
+ 401: z.ZodObject<{
34
+ reason: z.ZodOptional<z.ZodString>;
35
+ error: z.ZodOptional<z.ZodString>;
36
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
37
+ message: z.ZodOptional<z.ZodString>;
38
+ statusCode: z.ZodLiteral<401>;
39
+ }, z.core.$strip>;
40
+ 403: z.ZodObject<{
41
+ reason: z.ZodOptional<z.ZodString>;
42
+ error: z.ZodOptional<z.ZodString>;
43
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
44
+ message: z.ZodOptional<z.ZodString>;
45
+ statusCode: z.ZodLiteral<403>;
46
+ }, z.core.$strip>;
47
+ 500: z.ZodObject<{
48
+ reason: z.ZodOptional<z.ZodString>;
49
+ error: z.ZodOptional<z.ZodString>;
50
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
51
+ message: z.ZodOptional<z.ZodString>;
52
+ statusCode: z.ZodLiteral<500>;
53
+ }, z.core.$strip>;
54
+ };
55
+ };
56
+ getTeamMember: {
57
+ pathParams: z.ZodObject<{
58
+ id: z.ZodString;
59
+ }, z.core.$strip>;
60
+ summary: "Get team member";
61
+ description: "Retrieve a team member. 404 if it doesn't exist or belongs to another organisation";
62
+ method: "GET";
63
+ path: "/:id";
64
+ responses: {
65
+ 200: z.ZodObject<{
66
+ id: z.ZodString;
67
+ name: z.ZodString;
68
+ identity: z.ZodString;
69
+ vendorId: z.ZodString;
70
+ role: z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>;
71
+ createdAt: z.ZodString;
72
+ updatedAt: z.ZodString;
73
+ }, z.core.$strip>;
74
+ 401: z.ZodObject<{
75
+ reason: z.ZodOptional<z.ZodString>;
76
+ error: z.ZodOptional<z.ZodString>;
77
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
78
+ message: z.ZodOptional<z.ZodString>;
79
+ statusCode: z.ZodLiteral<401>;
80
+ }, z.core.$strip>;
81
+ 403: z.ZodObject<{
82
+ reason: z.ZodOptional<z.ZodString>;
83
+ error: z.ZodOptional<z.ZodString>;
84
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
85
+ message: z.ZodOptional<z.ZodString>;
86
+ statusCode: z.ZodLiteral<403>;
87
+ }, z.core.$strip>;
88
+ 404: z.ZodObject<{
89
+ reason: z.ZodOptional<z.ZodString>;
90
+ error: z.ZodOptional<z.ZodString>;
91
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
92
+ message: z.ZodOptional<z.ZodString>;
93
+ statusCode: z.ZodLiteral<404>;
94
+ }, z.core.$strip>;
95
+ 500: z.ZodObject<{
96
+ reason: z.ZodOptional<z.ZodString>;
97
+ error: z.ZodOptional<z.ZodString>;
98
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
99
+ message: z.ZodOptional<z.ZodString>;
100
+ statusCode: z.ZodLiteral<500>;
101
+ }, z.core.$strip>;
102
+ };
103
+ };
104
+ createTeamMember: {
105
+ summary: "Create team member";
106
+ description: string;
107
+ method: "POST";
108
+ body: z.ZodObject<{
109
+ name: z.ZodString;
110
+ identity: z.ZodEmail;
111
+ password: z.ZodString;
112
+ role: z.ZodOptional<z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>>;
113
+ }, z.core.$strip>;
114
+ path: "";
115
+ responses: {
116
+ 201: z.ZodObject<{
117
+ id: z.ZodString;
118
+ name: z.ZodString;
119
+ identity: z.ZodString;
120
+ vendorId: z.ZodString;
121
+ role: z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>;
122
+ createdAt: z.ZodString;
123
+ updatedAt: z.ZodString;
124
+ }, z.core.$strip>;
125
+ 400: z.ZodObject<{
126
+ reason: z.ZodOptional<z.ZodString>;
127
+ error: z.ZodOptional<z.ZodString>;
128
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
129
+ message: z.ZodOptional<z.ZodString>;
130
+ statusCode: z.ZodLiteral<400>;
131
+ }, z.core.$strip>;
132
+ 401: z.ZodObject<{
133
+ reason: z.ZodOptional<z.ZodString>;
134
+ error: z.ZodOptional<z.ZodString>;
135
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
136
+ message: z.ZodOptional<z.ZodString>;
137
+ statusCode: z.ZodLiteral<401>;
138
+ }, z.core.$strip>;
139
+ 403: z.ZodObject<{
140
+ reason: z.ZodOptional<z.ZodString>;
141
+ error: z.ZodOptional<z.ZodString>;
142
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
143
+ message: z.ZodOptional<z.ZodString>;
144
+ statusCode: z.ZodLiteral<403>;
145
+ }, z.core.$strip>;
146
+ 500: z.ZodObject<{
147
+ reason: z.ZodOptional<z.ZodString>;
148
+ error: z.ZodOptional<z.ZodString>;
149
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
150
+ message: z.ZodOptional<z.ZodString>;
151
+ statusCode: z.ZodLiteral<500>;
152
+ }, z.core.$strip>;
153
+ };
154
+ };
155
+ updateTeamMember: {
156
+ pathParams: z.ZodObject<{
157
+ id: z.ZodString;
158
+ }, z.core.$strip>;
159
+ summary: "Update team member";
160
+ description: string;
161
+ method: "PATCH";
162
+ body: z.ZodObject<{
163
+ name: z.ZodOptional<z.ZodString>;
164
+ role: z.ZodOptional<z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>>;
165
+ password: z.ZodOptional<z.ZodString>;
166
+ sendEmail: z.ZodOptional<z.ZodBoolean>;
167
+ }, z.core.$strip>;
168
+ path: "/:id";
169
+ responses: {
170
+ 200: z.ZodObject<{
171
+ id: z.ZodString;
172
+ name: z.ZodString;
173
+ identity: z.ZodString;
174
+ vendorId: z.ZodString;
175
+ role: z.ZodEnum<typeof import("../auth/auth.dtos.js").USER_ROLE>;
176
+ createdAt: z.ZodString;
177
+ updatedAt: z.ZodString;
178
+ }, z.core.$strip>;
179
+ 400: z.ZodObject<{
180
+ reason: z.ZodOptional<z.ZodString>;
181
+ error: z.ZodOptional<z.ZodString>;
182
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
183
+ message: z.ZodOptional<z.ZodString>;
184
+ statusCode: z.ZodLiteral<400>;
185
+ }, z.core.$strip>;
186
+ 401: z.ZodObject<{
187
+ reason: z.ZodOptional<z.ZodString>;
188
+ error: z.ZodOptional<z.ZodString>;
189
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
190
+ message: z.ZodOptional<z.ZodString>;
191
+ statusCode: z.ZodLiteral<401>;
192
+ }, z.core.$strip>;
193
+ 403: z.ZodObject<{
194
+ reason: z.ZodOptional<z.ZodString>;
195
+ error: z.ZodOptional<z.ZodString>;
196
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
197
+ message: z.ZodOptional<z.ZodString>;
198
+ statusCode: z.ZodLiteral<403>;
199
+ }, z.core.$strip>;
200
+ 404: z.ZodObject<{
201
+ reason: z.ZodOptional<z.ZodString>;
202
+ error: z.ZodOptional<z.ZodString>;
203
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
204
+ message: z.ZodOptional<z.ZodString>;
205
+ statusCode: z.ZodLiteral<404>;
206
+ }, z.core.$strip>;
207
+ 500: z.ZodObject<{
208
+ reason: z.ZodOptional<z.ZodString>;
209
+ error: z.ZodOptional<z.ZodString>;
210
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
211
+ message: z.ZodOptional<z.ZodString>;
212
+ statusCode: z.ZodLiteral<500>;
213
+ }, z.core.$strip>;
214
+ };
215
+ };
216
+ resetTeamMemberPassword: {
217
+ pathParams: z.ZodObject<{
218
+ id: z.ZodString;
219
+ }, z.core.$strip>;
220
+ summary: "Reset team member password";
221
+ description: string;
222
+ method: "POST";
223
+ body: typeof import("@ts-rest/core").ContractNoBody;
224
+ path: "/:id/reset-password";
225
+ responses: {
226
+ 201: z.ZodObject<{
227
+ id: z.ZodString;
228
+ }, z.core.$strip>;
229
+ 401: z.ZodObject<{
230
+ reason: z.ZodOptional<z.ZodString>;
231
+ error: z.ZodOptional<z.ZodString>;
232
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
233
+ message: z.ZodOptional<z.ZodString>;
234
+ statusCode: z.ZodLiteral<401>;
235
+ }, z.core.$strip>;
236
+ 403: z.ZodObject<{
237
+ reason: z.ZodOptional<z.ZodString>;
238
+ error: z.ZodOptional<z.ZodString>;
239
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
240
+ message: z.ZodOptional<z.ZodString>;
241
+ statusCode: z.ZodLiteral<403>;
242
+ }, z.core.$strip>;
243
+ 404: z.ZodObject<{
244
+ reason: z.ZodOptional<z.ZodString>;
245
+ error: z.ZodOptional<z.ZodString>;
246
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
247
+ message: z.ZodOptional<z.ZodString>;
248
+ statusCode: z.ZodLiteral<404>;
249
+ }, z.core.$strip>;
250
+ 500: z.ZodObject<{
251
+ reason: z.ZodOptional<z.ZodString>;
252
+ error: z.ZodOptional<z.ZodString>;
253
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
254
+ message: z.ZodOptional<z.ZodString>;
255
+ statusCode: z.ZodLiteral<500>;
256
+ }, z.core.$strip>;
257
+ };
258
+ };
259
+ };
260
+ export type TeamContract = typeof teamContract;
261
+ //# sourceMappingURL=team.api-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.api-contract.d.ts","sourceRoot":"","sources":["../../../src/modules/team/team.api-contract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGvB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC"}
@@ -0,0 +1,111 @@
1
+ import type { USER_ROLE } from "../auth/auth.dtos.js";
2
+ import { type TeamMemberFilters, type TeamMemberListQueryDTO, type TeamMemberSortField } from "./team.types.js";
3
+ /**
4
+ * Query builder for the team member list endpoint (`GET /user`).
5
+ *
6
+ * The endpoint takes exact filters (`id`, `name`, `identity`, `role`),
7
+ * LIKE filters (`name:like`, `identity:like`), a single `orderBy` field and
8
+ * `range=first,last` row pagination. The shared {@link QueryBuilder}
9
+ * serializes pagination as `rangeStart`/`rangeEnd`, which this endpoint
10
+ * does not understand, so this builder keeps a typed filters object and
11
+ * serializes it to the endpoint's exact params in {@link build}.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const query = TeamQuery.create().whereRole(USER_ROLE.APPROVER).searchName("jane").orderBy("name").page(1, 20);
16
+ * query.build(); // { role: "Approver", "name:like": "%jane%", orderBy: "name", range: "0,19" }
17
+ * ```
18
+ */
19
+ export declare class TeamQuery {
20
+ private filters;
21
+ constructor(filters?: TeamMemberFilters);
22
+ /**
23
+ * Create an empty team query
24
+ */
25
+ static create(): TeamQuery;
26
+ /**
27
+ * Create from a typed filters object (validated)
28
+ */
29
+ static fromFilters(filters: TeamMemberFilters): TeamQuery;
30
+ /**
31
+ * Create from URLSearchParams using the API's own param names
32
+ * (`role`, `name:like`, `range=0,19`, …). Unsupported and empty params
33
+ * are ignored.
34
+ */
35
+ static fromSearchParams(searchParams: URLSearchParams): TeamQuery;
36
+ /**
37
+ * Create from a Request object (reads its URL query string)
38
+ */
39
+ static fromRequest(request: Request): TeamQuery;
40
+ /**
41
+ * Create from any supported input type
42
+ */
43
+ static from(input: TeamQuery | TeamMemberFilters | URLSearchParams | null | undefined): TeamQuery;
44
+ /**
45
+ * Type guard for TeamQuery instances
46
+ */
47
+ static is(obj: unknown): obj is TeamQuery;
48
+ private static dropUndefined;
49
+ /**
50
+ * Escape LIKE wildcards in a user-typed search term so `%` and `_` match
51
+ * literally.
52
+ */
53
+ private static escapeLike;
54
+ whereId(id: string): this;
55
+ /** Exact name match */
56
+ whereName(name: string): this;
57
+ /** Exact identity (email) match */
58
+ whereIdentity(identity: string): this;
59
+ whereRole(role: USER_ROLE): this;
60
+ /** Raw LIKE pattern on name, e.g. `Jane%` */
61
+ whereNameLike(pattern: string): this;
62
+ /** Raw LIKE pattern on identity, e.g. `%@example.com` */
63
+ whereIdentityLike(pattern: string): this;
64
+ /** Partial name search — matches names containing `term` */
65
+ searchName(term: string): this;
66
+ /** Partial identity (email) search — matches identities containing `term` */
67
+ searchIdentity(term: string): this;
68
+ orderBy(field: TeamMemberSortField): this;
69
+ /**
70
+ * Request rows `start` to `end` (zero-based, both inclusive).
71
+ */
72
+ range(start: number, end: number): this;
73
+ /**
74
+ * Request a page of results.
75
+ *
76
+ * @param page - One-based page number
77
+ * @param pageSize - Rows per page
78
+ */
79
+ page(page: number, pageSize: number): this;
80
+ clone(): TeamQuery;
81
+ withRole(role?: USER_ROLE): TeamQuery;
82
+ withNameSearch(term?: string): TeamQuery;
83
+ withIdentitySearch(term?: string): TeamQuery;
84
+ withPage(page: number, pageSize: number): TeamQuery;
85
+ /**
86
+ * Convert to a typed TeamMemberFilters DTO (only defined filters).
87
+ */
88
+ toFilters(): TeamMemberFilters;
89
+ /**
90
+ * Params to send to the team member list endpoint, using the API's
91
+ * exact param names.
92
+ */
93
+ build(): TeamMemberListQueryDTO;
94
+ /**
95
+ * Convert to URL-safe string parameters (the API's param names).
96
+ */
97
+ toUrlParams(): Record<string, string>;
98
+ /**
99
+ * Convert to URLSearchParams
100
+ */
101
+ toSearchParams(): URLSearchParams;
102
+ /**
103
+ * Convert to query string
104
+ */
105
+ toQueryString(): string;
106
+ /**
107
+ * Check if any filters (excluding sorting and pagination) are applied
108
+ */
109
+ hasFilters(): boolean;
110
+ }
111
+ //# sourceMappingURL=team.query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.query.d.ts","sourceRoot":"","sources":["../../../src/modules/team/team.query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,GAAE,iBAAsB;IAM3C;;OAEG;IACH,MAAM,CAAC,MAAM,IAAI,SAAS;IAI1B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS;IAIzD;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,eAAe,GAAG,SAAS;IA2BjE;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS;IAK/C;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS;IAgBjG;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,SAAS;IAIzC,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IAMzB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKzB,uBAAuB;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK7B,mCAAmC;IACnC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKrC,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAKhC,6CAA6C;IAC7C,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKpC,yDAAyD;IACzD,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKxC,4DAA4D;IAC5D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM9B,6EAA6E;IAC7E,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMlC,OAAO,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAKzC;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IASvC;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU1C,KAAK,IAAI,SAAS;IAIlB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS;IAMrC,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS;IAMxC,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS;IAM5C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS;IAMnD;;OAEG;IACH,SAAS,IAAI,iBAAiB;IAI9B;;;OAGG;IACH,KAAK,IAAI,sBAAsB;IAkB/B;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQrC;;OAEG;IACH,cAAc,IAAI,eAAe;IAIjC;;OAEG;IACH,aAAa,IAAI,MAAM;IAMvB;;OAEG;IACH,UAAU,IAAI,OAAO;CAItB"}
@@ -0,0 +1,73 @@
1
+ import { BaseRepository } from "../../lib/api/index.js";
2
+ import { teamContract } from "./team.api-contract.js";
3
+ import { TeamQuery } from "./team.query.js";
4
+ import { type CreateTeamMemberRequestDTO, type ResetTeamMemberPasswordResponseDTO, type TeamMemberFilters, type UpdateTeamMemberRequestDTO } from "./team.types.js";
5
+ import { TeamMember } from "./team-member.model.js";
6
+ /**
7
+ * Flexible query input for listing team members — a TeamQuery instance,
8
+ * a typed filters object, or URLSearchParams using the API's param names.
9
+ */
10
+ export type TeamQueryInput = TeamQuery | TeamMemberFilters | URLSearchParams | null | undefined;
11
+ /**
12
+ * Input for creating a team member. `role` defaults to `ReadOnly` on the
13
+ * API when omitted.
14
+ */
15
+ export type CreateTeamMemberInput = CreateTeamMemberRequestDTO;
16
+ /**
17
+ * Input for updating a team member — only the fields that change, at least
18
+ * one of `name`, `role` or `password`.
19
+ */
20
+ export type UpdateTeamMemberInput = UpdateTeamMemberRequestDTO;
21
+ /**
22
+ * Repository for managing the organisation's team members through the
23
+ * API's `/user` endpoints.
24
+ *
25
+ * All endpoints are Admin-only: any other role gets a 403 `APIError`.
26
+ * Validation failures are thrown as a 400 `APIError` whose `details` map
27
+ * field names (e.g. `identity`, `role`) to server messages — map them onto
28
+ * form fields, but don't match on the text.
29
+ *
30
+ * Side effects: creating a member, changing a password (unless
31
+ * `sendEmail: false`) and resetting a password email the member; changing
32
+ * or resetting a password ends that member's sessions.
33
+ */
34
+ export declare class TeamRepository extends BaseRepository<typeof teamContract> {
35
+ constructor(options?: {
36
+ token?: string;
37
+ root?: string;
38
+ });
39
+ /**
40
+ * List the organisation's team members.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const all = await repo.getTeamMembers();
45
+ * const approvers = await repo.getTeamMembers({ role: USER_ROLE.APPROVER });
46
+ * const page = await repo.getTeamMembers(TeamQuery.create().searchName("jane").page(1, 20));
47
+ * ```
48
+ */
49
+ getTeamMembers(query?: TeamQueryInput): Promise<TeamMember[]>;
50
+ /**
51
+ * Get a team member by ID. Throws a 404 `APIError` if the member doesn't
52
+ * exist or belongs to another organisation.
53
+ */
54
+ getTeamMember(id: string): Promise<TeamMember>;
55
+ /**
56
+ * Create a team member. The API emails them their credentials and the
57
+ * login link.
58
+ */
59
+ createTeamMember(input: CreateTeamMemberInput): Promise<TeamMember>;
60
+ /**
61
+ * Update a team member's name, role and/or password. Throws a 400
62
+ * `APIError` without calling the API when no field is given. An admin
63
+ * cannot change their own role (400, `details.role`).
64
+ */
65
+ updateTeamMember(id: string, input: UpdateTeamMemberInput): Promise<TeamMember>;
66
+ /**
67
+ * Reset a team member's password. The API generates a new random password
68
+ * and emails it to the member; the admin never sees it.
69
+ */
70
+ resetTeamMemberPassword(id: string): Promise<ResetTeamMemberPasswordResponseDTO>;
71
+ private static toTeamMember;
72
+ }
73
+ //# sourceMappingURL=team.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.repository.d.ts","sourceRoot":"","sources":["../../../src/modules/team/team.repository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EAEvC,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAChC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAuB,MAAM,wBAAwB,CAAC;AAEzE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,iBAAiB,GAAG,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC;AAEhG;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAAC,OAAO,YAAY,CAAC;gBACzD,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAIvD;;;;;;;;;OASG;IACG,cAAc,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAOnE;;;OAGG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAMpD;;;OAGG;IACG,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC;IAMzE;;;;OAIG;IACG,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC;IAerF;;;OAGG;IACG,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kCAAkC,CAAC;IAKtF,OAAO,CAAC,MAAM,CAAC,YAAY;CAO5B"}
@@ -0,0 +1,75 @@
1
+ import { z } from "zod";
2
+ import { USER_ROLE } from "../auth/auth.dtos.js";
3
+ /**
4
+ * Max length the API accepts for a team member's name, identity and password.
5
+ */
6
+ export declare const TEAM_MEMBER_FIELD_MAX_LENGTH = 255;
7
+ export declare const TeamDTOSchemas: {
8
+ teamMember: z.ZodObject<{
9
+ id: z.ZodString;
10
+ name: z.ZodString;
11
+ identity: z.ZodString;
12
+ vendorId: z.ZodString;
13
+ role: z.ZodEnum<typeof USER_ROLE>;
14
+ createdAt: z.ZodString;
15
+ updatedAt: z.ZodString;
16
+ }, z.core.$strip>;
17
+ teamMemberRole: z.ZodEnum<typeof USER_ROLE>;
18
+ teamMemberSortField: z.ZodEnum<{
19
+ createdAt: "createdAt";
20
+ role: "role";
21
+ identity: "identity";
22
+ name: "name";
23
+ updatedAt: "updatedAt";
24
+ }>;
25
+ createTeamMemberRequest: z.ZodObject<{
26
+ name: z.ZodString;
27
+ identity: z.ZodEmail;
28
+ password: z.ZodString;
29
+ role: z.ZodOptional<z.ZodEnum<typeof USER_ROLE>>;
30
+ }, z.core.$strip>;
31
+ updateTeamMemberRequest: z.ZodObject<{
32
+ name: z.ZodOptional<z.ZodString>;
33
+ role: z.ZodOptional<z.ZodEnum<typeof USER_ROLE>>;
34
+ password: z.ZodOptional<z.ZodString>;
35
+ sendEmail: z.ZodOptional<z.ZodBoolean>;
36
+ }, z.core.$strip>;
37
+ resetTeamMemberPasswordResponse: z.ZodObject<{
38
+ id: z.ZodString;
39
+ }, z.core.$strip>;
40
+ teamMemberListQuery: z.ZodObject<{
41
+ id: z.ZodOptional<z.ZodString>;
42
+ name: z.ZodOptional<z.ZodString>;
43
+ identity: z.ZodOptional<z.ZodString>;
44
+ role: z.ZodOptional<z.ZodEnum<typeof USER_ROLE>>;
45
+ "name:like": z.ZodOptional<z.ZodString>;
46
+ "identity:like": z.ZodOptional<z.ZodString>;
47
+ orderBy: z.ZodOptional<z.ZodString>;
48
+ range: z.ZodOptional<z.ZodString>;
49
+ }, z.core.$strip>;
50
+ teamMemberFilters: z.ZodObject<{
51
+ id: z.ZodOptional<z.ZodString>;
52
+ name: z.ZodOptional<z.ZodString>;
53
+ identity: z.ZodOptional<z.ZodString>;
54
+ role: z.ZodOptional<z.ZodEnum<typeof USER_ROLE>>;
55
+ nameLike: z.ZodOptional<z.ZodString>;
56
+ identityLike: z.ZodOptional<z.ZodString>;
57
+ orderBy: z.ZodOptional<z.ZodEnum<{
58
+ createdAt: "createdAt";
59
+ role: "role";
60
+ identity: "identity";
61
+ name: "name";
62
+ updatedAt: "updatedAt";
63
+ }>>;
64
+ rangeStart: z.ZodOptional<z.ZodNumber>;
65
+ rangeEnd: z.ZodOptional<z.ZodNumber>;
66
+ }, z.core.$strip>;
67
+ };
68
+ export type TeamMemberDTO = z.infer<typeof TeamDTOSchemas.teamMember>;
69
+ export type TeamMemberSortField = z.infer<typeof TeamDTOSchemas.teamMemberSortField>;
70
+ export type CreateTeamMemberRequestDTO = z.infer<typeof TeamDTOSchemas.createTeamMemberRequest>;
71
+ export type UpdateTeamMemberRequestDTO = z.infer<typeof TeamDTOSchemas.updateTeamMemberRequest>;
72
+ export type ResetTeamMemberPasswordResponseDTO = z.infer<typeof TeamDTOSchemas.resetTeamMemberPasswordResponse>;
73
+ export type TeamMemberListQueryDTO = z.infer<typeof TeamDTOSchemas.teamMemberListQuery>;
74
+ export type TeamMemberFilters = z.infer<typeof TeamDTOSchemas.teamMemberFilters>;
75
+ //# sourceMappingURL=team.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.types.d.ts","sourceRoot":"","sources":["../../../src/modules/team/team.types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAuGhD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS1B,CAAC;AAGF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC;AACtE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,mBAAmB,CAAC,CAAC;AACrF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,uBAAuB,CAAC,CAAC;AAChG,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,uBAAuB,CAAC,CAAC;AAChG,MAAM,MAAM,kCAAkC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,+BAA+B,CAAC,CAAC;AAChH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,mBAAmB,CAAC,CAAC;AACxF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,iBAAiB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temboplus/tembo-dashboard",
3
- "version": "0.7.1",
3
+ "version": "0.8.0-rc.1",
4
4
  "description": "A foundational library for Temboplus-Dashboard projects providing type-safe data layer abstraction with API contracts, domain models, and repositories.",
5
5
  "author": "Okello Gerald",
6
6
  "license": "MIT",