@devxcrew/platform 0.1.2
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/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/modules/identity/identity.administration-migration.d.ts +2 -0
- package/dist/modules/identity/identity.administration-migration.js +75 -0
- package/dist/modules/identity/identity.administration-repository.d.ts +19 -0
- package/dist/modules/identity/identity.administration-repository.js +102 -0
- package/dist/modules/identity/identity.administration-schema.d.ts +113 -0
- package/dist/modules/identity/identity.administration-schema.js +121 -0
- package/dist/modules/identity/identity.administration-service.d.ts +97 -0
- package/dist/modules/identity/identity.administration-service.js +517 -0
- package/dist/modules/identity/identity.controller.d.ts +22 -0
- package/dist/modules/identity/identity.controller.js +278 -0
- package/dist/modules/identity/identity.error.d.ts +6 -0
- package/dist/modules/identity/identity.error.js +15 -0
- package/dist/modules/identity/identity.lifecycle-schema.d.ts +19 -0
- package/dist/modules/identity/identity.lifecycle-schema.js +29 -0
- package/dist/modules/identity/identity.lifecycle-service.d.ts +64 -0
- package/dist/modules/identity/identity.lifecycle-service.js +395 -0
- package/dist/modules/identity/identity.membership-policy.d.ts +3 -0
- package/dist/modules/identity/identity.membership-policy.js +27 -0
- package/dist/modules/identity/identity.migration.d.ts +2 -0
- package/dist/modules/identity/identity.migration.js +79 -0
- package/dist/modules/identity/identity.password.d.ts +3 -0
- package/dist/modules/identity/identity.password.js +21 -0
- package/dist/modules/identity/identity.permission-declarations-migration.d.ts +5 -0
- package/dist/modules/identity/identity.permission-declarations-migration.js +15 -0
- package/dist/modules/identity/identity.permission-declarations.d.ts +23 -0
- package/dist/modules/identity/identity.permission-declarations.js +57 -0
- package/dist/modules/identity/identity.permission-labels-migration.d.ts +5 -0
- package/dist/modules/identity/identity.permission-labels-migration.js +9 -0
- package/dist/modules/identity/identity.presentation-service.d.ts +23 -0
- package/dist/modules/identity/identity.presentation-service.js +51 -0
- package/dist/modules/identity/identity.provider.d.ts +78 -0
- package/dist/modules/identity/identity.provider.js +119 -0
- package/dist/modules/identity/identity.public-schemas.d.ts +4 -0
- package/dist/modules/identity/identity.public-schemas.js +3 -0
- package/dist/modules/identity/identity.repository.d.ts +40 -0
- package/dist/modules/identity/identity.repository.js +196 -0
- package/dist/modules/identity/identity.request-context.d.ts +2 -0
- package/dist/modules/identity/identity.request-context.js +10 -0
- package/dist/modules/identity/identity.roles-migration.d.ts +2 -0
- package/dist/modules/identity/identity.roles-migration.js +64 -0
- package/dist/modules/identity/identity.roles-service.d.ts +49 -0
- package/dist/modules/identity/identity.roles-service.js +327 -0
- package/dist/modules/identity/identity.routes.d.ts +22 -0
- package/dist/modules/identity/identity.routes.js +11 -0
- package/dist/modules/identity/identity.schema.d.ts +27 -0
- package/dist/modules/identity/identity.schema.js +34 -0
- package/dist/modules/identity/identity.seed.d.ts +3 -0
- package/dist/modules/identity/identity.seed.js +81 -0
- package/dist/modules/identity/identity.service.d.ts +32 -0
- package/dist/modules/identity/identity.service.js +83 -0
- package/dist/modules/identity/identity.types.d.ts +150 -0
- package/dist/modules/identity/identity.types.js +1 -0
- package/dist/modules/identity/index.d.ts +12 -0
- package/dist/modules/identity/index.js +9 -0
- package/package.json +62 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
import { portalSchema, loginSchema, passwordSchema, } from "./identity.schema.js";
|
|
3
|
+
import { IdentityError } from "./identity.error.js";
|
|
4
|
+
import { identityRoutes, portalRoutes } from "./identity.routes.js";
|
|
5
|
+
import { resourceListQuerySchema, membershipDeleteQuerySchema, resourceIdSchema, } from "./identity.administration-schema.js";
|
|
6
|
+
import { checkIdentityRequest, runIdentityRequest, } from "./identity.request-context.js";
|
|
7
|
+
export class IdentityController {
|
|
8
|
+
service;
|
|
9
|
+
config;
|
|
10
|
+
administration;
|
|
11
|
+
lifecycle;
|
|
12
|
+
constructor(service, config, administration, lifecycle) {
|
|
13
|
+
this.service = service;
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.administration = administration;
|
|
16
|
+
this.lifecycle = lifecycle;
|
|
17
|
+
}
|
|
18
|
+
async handle(request, response, signal) {
|
|
19
|
+
return runIdentityRequest(signal, () => this.handleRequest(request, response));
|
|
20
|
+
}
|
|
21
|
+
async authenticateRequest(request, requestedPortal, signal) {
|
|
22
|
+
return runIdentityRequest(signal, async () => {
|
|
23
|
+
checkIdentityRequest();
|
|
24
|
+
const parsedPortal = portalSchema.safeParse(requestedPortal);
|
|
25
|
+
if (!parsedPortal.success)
|
|
26
|
+
throw new IdentityError(422, "Validation failed", { portal: ["Select a supported portal."] });
|
|
27
|
+
const portal = parsedPortal.data;
|
|
28
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(request.method ?? "") && request.headers.origin !== this.config.origin)
|
|
29
|
+
throw new IdentityError(403, "Untrusted request origin.");
|
|
30
|
+
const principal = await this.service.authenticate(portal, this.token(request, portal));
|
|
31
|
+
checkIdentityRequest();
|
|
32
|
+
return principal;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async handleRequest(request, response) {
|
|
36
|
+
const path = new URL(request.url ?? "/", this.config.origin).pathname.replace(/\/+$/, "") || "/";
|
|
37
|
+
const api = path.match(/^\/api\/v1\/identity\/(user|admin|super-admin)\/(.+)$/);
|
|
38
|
+
const desk = Object.entries(portalRoutes).find(([, routes]) => routes.desk === path);
|
|
39
|
+
if (!api && !desk)
|
|
40
|
+
return false;
|
|
41
|
+
const portal = portalSchema.parse(api?.[1] ?? desk?.[0]);
|
|
42
|
+
response.setHeader("Cache-Control", "no-store");
|
|
43
|
+
response.setHeader("X-Content-Type-Options", "nosniff");
|
|
44
|
+
try {
|
|
45
|
+
checkIdentityRequest();
|
|
46
|
+
const token = this.token(request, portal);
|
|
47
|
+
if (desk) {
|
|
48
|
+
try {
|
|
49
|
+
const principal = await this.service.authenticate(portal, token);
|
|
50
|
+
this.service.requirePermission(principal, `desk.${portal}`);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (!(error instanceof IdentityError))
|
|
55
|
+
throw error;
|
|
56
|
+
response.writeHead(302, { Location: portalRoutes[portal].login });
|
|
57
|
+
response.end();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const route = identityRoutes.find((r) => r.method === request.method && r.path === api?.[2]);
|
|
62
|
+
if (request.method !== "GET" &&
|
|
63
|
+
request.headers.origin !== this.config.origin)
|
|
64
|
+
throw new IdentityError(403, "Untrusted request origin.");
|
|
65
|
+
if (!route) {
|
|
66
|
+
await this.adminRequest(request, response, portal, token, api[2]);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (route.action === "login") {
|
|
70
|
+
const result = await this.service.login(portal, loginSchema
|
|
71
|
+
.refine((input) => this.config.mode !== "multi-tenant" || Boolean(input.tenantId), { path: ["tenantId"], message: "Enter an organization ID." })
|
|
72
|
+
.parse(await this.body(request)), request.socket.remoteAddress ?? "unknown", token);
|
|
73
|
+
response.setHeader("Set-Cookie", this.cookie(portal, result.token, result.sessionSeconds));
|
|
74
|
+
this.json(response, 201, { data: result.principal });
|
|
75
|
+
}
|
|
76
|
+
else if (route.action === "logout") {
|
|
77
|
+
await this.service.logout(portal, token);
|
|
78
|
+
response.setHeader("Set-Cookie", this.cookie(portal, "", 0));
|
|
79
|
+
response.writeHead(204);
|
|
80
|
+
response.end();
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const principal = await this.service.authenticate(portal, token);
|
|
84
|
+
if (route.action === "password") {
|
|
85
|
+
await this.service.changePassword(principal, passwordSchema.parse(await this.body(request)));
|
|
86
|
+
response.setHeader("Set-Cookie", this.cookie(portal, "", 0));
|
|
87
|
+
response.writeHead(204);
|
|
88
|
+
response.end();
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
this.service.requirePermission(principal, `desk.${portal}`);
|
|
92
|
+
this.json(response, 200, { data: principal });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (error instanceof ZodError) {
|
|
98
|
+
const errors = {};
|
|
99
|
+
for (const issue of error.issues)
|
|
100
|
+
(errors[String(issue.path[0] ?? "form")] ??= []).push(issue.message);
|
|
101
|
+
this.json(response, 422, { message: "Validation failed", errors });
|
|
102
|
+
}
|
|
103
|
+
else if (error instanceof IdentityError)
|
|
104
|
+
this.json(response, error.status, { message: error.message });
|
|
105
|
+
else {
|
|
106
|
+
console.error("Identity request failed.");
|
|
107
|
+
this.json(response, 500, {
|
|
108
|
+
message: "Unable to complete the request.",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
async adminRequest(request, response, portal, token, path) {
|
|
115
|
+
if (path === "configuration") {
|
|
116
|
+
if (request.method !== "GET")
|
|
117
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
118
|
+
this.json(response, 200, {
|
|
119
|
+
data: await this.administration.configuration(this.config.appId, this.config.mode === "multi-tenant"),
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (["recovery", "recovery/complete", "invitations/accept"].includes(path)) {
|
|
124
|
+
if (request.method !== "POST")
|
|
125
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
126
|
+
const raw = await this.body(request);
|
|
127
|
+
const data = path === "recovery"
|
|
128
|
+
? await this.lifecycle.requestRecovery(portal, raw, request.socket.remoteAddress ?? "unknown")
|
|
129
|
+
: await this.lifecycle.complete(portal, path === "recovery/complete" ? "recovery" : "invitation", raw, request.socket.remoteAddress ?? "unknown");
|
|
130
|
+
this.json(response, path === "recovery" ? 202 : 200, { data });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const principal = await this.service.authenticate(portal, token);
|
|
134
|
+
if (path === "presentation") {
|
|
135
|
+
if (request.method !== "GET")
|
|
136
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
137
|
+
this.json(response, 200, {
|
|
138
|
+
data: await this.administration.presentation(principal),
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (path === "invitations" || path.startsWith("invitations/")) {
|
|
143
|
+
if (path === "invitations" && request.method === "GET") {
|
|
144
|
+
const query = resourceListQuerySchema.parse(Object.fromEntries(new URL(request.url, this.config.origin).searchParams));
|
|
145
|
+
this.json(response, 200, this.wireList(await this.lifecycle.list(principal, query)));
|
|
146
|
+
}
|
|
147
|
+
else if (path === "invitations" && request.method === "POST") {
|
|
148
|
+
this.json(response, 201, {
|
|
149
|
+
data: await this.lifecycle.invite(principal, await this.body(request)),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else if (request.method === "GET") {
|
|
153
|
+
this.json(response, 200, {
|
|
154
|
+
data: await this.lifecycle.show(principal, resourceIdSchema.parse(path.slice("invitations/".length))),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (request.method === "POST" && path.endsWith("/resend")) {
|
|
158
|
+
this.json(response, 201, {
|
|
159
|
+
data: await this.lifecycle.resend(principal, resourceIdSchema.parse(path.slice("invitations/".length, -"/resend".length))),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else if (request.method === "DELETE") {
|
|
163
|
+
await this.lifecycle.revoke(principal, resourceIdSchema.parse(path.slice("invitations/".length)));
|
|
164
|
+
response.writeHead(204);
|
|
165
|
+
response.end();
|
|
166
|
+
}
|
|
167
|
+
else
|
|
168
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if ([
|
|
172
|
+
"profile",
|
|
173
|
+
"settings",
|
|
174
|
+
"application-settings",
|
|
175
|
+
"security-settings",
|
|
176
|
+
].includes(path)) {
|
|
177
|
+
if (!["GET", "PATCH"].includes(request.method ?? ""))
|
|
178
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
179
|
+
const input = request.method === "PATCH" ? await this.body(request) : undefined;
|
|
180
|
+
const data = path === "profile"
|
|
181
|
+
? await this.administration.profile(principal, input)
|
|
182
|
+
: path === "settings"
|
|
183
|
+
? await this.administration.settings(principal, input)
|
|
184
|
+
: await this.administration.applicationSettings(principal, path === "security-settings", input, this.config.sessionSeconds);
|
|
185
|
+
this.json(response, 200, { data });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const match = path.match(/^(users|organizations|memberships|roles|permissions|sessions|audit-events)(?:\/([^/]+))?$/);
|
|
189
|
+
if (!match)
|
|
190
|
+
throw new IdentityError(404, "Not found.");
|
|
191
|
+
const resource = match[1];
|
|
192
|
+
const id = match[2]
|
|
193
|
+
? resourceIdSchema.parse(decodeURIComponent(match[2]))
|
|
194
|
+
: undefined;
|
|
195
|
+
if (request.method === "GET") {
|
|
196
|
+
const query = resourceListQuerySchema.parse(Object.fromEntries(new URL(request.url, this.config.origin).searchParams));
|
|
197
|
+
this.json(response, 200, id
|
|
198
|
+
? { data: await this.administration.show(principal, resource, id) }
|
|
199
|
+
: this.wireList(await this.administration.list(principal, resource, query)));
|
|
200
|
+
}
|
|
201
|
+
else if (request.method === "POST" && !id) {
|
|
202
|
+
this.json(response, 201, {
|
|
203
|
+
data: await this.administration.create(principal, resource, await this.body(request)),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
else if (request.method === "PATCH" && id) {
|
|
207
|
+
this.json(response, 200, {
|
|
208
|
+
data: await this.administration.update(principal, resource, id, await this.body(request)),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
else if (request.method === "DELETE" && id) {
|
|
212
|
+
const query = new URL(request.url, this.config.origin).searchParams;
|
|
213
|
+
const expectedVersion = resource === "memberships"
|
|
214
|
+
? membershipDeleteQuerySchema.parse(Object.fromEntries(query))
|
|
215
|
+
.expectedVersion
|
|
216
|
+
: undefined;
|
|
217
|
+
await this.administration.remove(principal, resource, id, expectedVersion);
|
|
218
|
+
response.writeHead(204);
|
|
219
|
+
response.end();
|
|
220
|
+
}
|
|
221
|
+
else
|
|
222
|
+
throw new IdentityError(405, "Method not allowed.");
|
|
223
|
+
}
|
|
224
|
+
wireList(page) {
|
|
225
|
+
return {
|
|
226
|
+
data: page.data,
|
|
227
|
+
meta: {
|
|
228
|
+
current_page: page.meta.page,
|
|
229
|
+
per_page: page.meta.perPage,
|
|
230
|
+
total: page.meta.total,
|
|
231
|
+
last_page: page.meta.lastPage,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
cookie(portal, token, age) {
|
|
236
|
+
return `${this.cookieName(portal)}=${token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${age}${this.config.origin.startsWith("https:") ? "; Secure" : ""}`;
|
|
237
|
+
}
|
|
238
|
+
cookieName(portal) {
|
|
239
|
+
return `${this.config.origin.startsWith("https:") ? "__Host-" : ""}${this.config.appId}_${portal}_session`;
|
|
240
|
+
}
|
|
241
|
+
token(request, portal) {
|
|
242
|
+
return request.headers.cookie
|
|
243
|
+
?.split(";")
|
|
244
|
+
.map((c) => c.trim())
|
|
245
|
+
.find((c) => c.startsWith(`${this.cookieName(portal)}=`))
|
|
246
|
+
?.split("=")[1];
|
|
247
|
+
}
|
|
248
|
+
json(response, status, body) {
|
|
249
|
+
response.writeHead(status, { "Content-Type": "application/json" });
|
|
250
|
+
response.end(JSON.stringify(body));
|
|
251
|
+
}
|
|
252
|
+
async body(request) {
|
|
253
|
+
if (request.headers["content-type"]?.split(";")[0].trim() !==
|
|
254
|
+
"application/json")
|
|
255
|
+
throw new IdentityError(415, "Use JSON request bodies.");
|
|
256
|
+
const chunks = [];
|
|
257
|
+
let size = 0;
|
|
258
|
+
if (Number(request.headers["content-length"] ?? 0) > 16384) {
|
|
259
|
+
request.resume();
|
|
260
|
+
throw new IdentityError(413, "Request body is too large.");
|
|
261
|
+
}
|
|
262
|
+
for await (const chunk of request.iterator({ destroyOnReturn: false })) {
|
|
263
|
+
checkIdentityRequest();
|
|
264
|
+
size += chunk.length;
|
|
265
|
+
if (size > 16384) {
|
|
266
|
+
request.resume();
|
|
267
|
+
throw new IdentityError(413, "Request body is too large.");
|
|
268
|
+
}
|
|
269
|
+
chunks.push(chunk);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
throw new IdentityError(400, "Invalid JSON.");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Only caller-safe messages and field errors belong in this public transport contract.
|
|
2
|
+
export class IdentityError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
fields;
|
|
5
|
+
code = "identity_error";
|
|
6
|
+
constructor(status, message, fields) {
|
|
7
|
+
if (!Number.isInteger(status) || status < 400 || status > 599)
|
|
8
|
+
throw new Error("Identity errors require an HTTP error status.");
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.name = "IdentityError";
|
|
12
|
+
if (fields)
|
|
13
|
+
this.fields = Object.freeze(Object.fromEntries(Object.entries(fields).map(([key, messages]) => [key, Object.freeze([...messages])])));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const invitationSchema: z.ZodObject<{
|
|
3
|
+
email: z.ZodPipe<z.ZodEmail, z.ZodTransform<string, string>>;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
roleId: z.ZodDefault<z.ZodEnum<{
|
|
6
|
+
admin: "admin";
|
|
7
|
+
"super-admin": "super-admin";
|
|
8
|
+
user: "user";
|
|
9
|
+
}>>;
|
|
10
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, z.core.$strict>;
|
|
12
|
+
export declare const recoverySchema: z.ZodObject<{
|
|
13
|
+
email: z.ZodPipe<z.ZodEmail, z.ZodTransform<string, string>>;
|
|
14
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export declare const tokenCompletionSchema: z.ZodObject<{
|
|
17
|
+
token: z.ZodString;
|
|
18
|
+
password: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { portalSchema } from "./identity.schema.js";
|
|
3
|
+
import { resourceIdSchema } from "./identity.administration-schema.js";
|
|
4
|
+
export const invitationSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
email: z
|
|
7
|
+
.email()
|
|
8
|
+
.max(254)
|
|
9
|
+
.transform((v) => v.trim().toLowerCase()),
|
|
10
|
+
name: z.string().trim().min(1).max(100),
|
|
11
|
+
roleId: portalSchema.default("user"),
|
|
12
|
+
tenantId: resourceIdSchema.optional(),
|
|
13
|
+
})
|
|
14
|
+
.strict();
|
|
15
|
+
export const recoverySchema = z
|
|
16
|
+
.object({
|
|
17
|
+
email: z
|
|
18
|
+
.email()
|
|
19
|
+
.max(254)
|
|
20
|
+
.transform((v) => v.trim().toLowerCase()),
|
|
21
|
+
tenantId: resourceIdSchema.optional(),
|
|
22
|
+
})
|
|
23
|
+
.strict();
|
|
24
|
+
export const tokenCompletionSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
token: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
27
|
+
password: z.string().min(12).max(256),
|
|
28
|
+
})
|
|
29
|
+
.strict();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import type { IdentityConfig, IdentityDeliveryProvider, IdentitySchema, Portal, Principal } from "./identity.types.js";
|
|
3
|
+
import type { IdentityListQuery } from "./identity.administration-schema.js";
|
|
4
|
+
export declare class IdentityLifecycleService {
|
|
5
|
+
private readonly db;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private readonly delivery?;
|
|
8
|
+
constructor(db: Kysely<IdentitySchema>, config: IdentityConfig, delivery?: IdentityDeliveryProvider | undefined);
|
|
9
|
+
invite(actor: Principal, raw: unknown): Promise<{
|
|
10
|
+
id: string;
|
|
11
|
+
email: string;
|
|
12
|
+
name: string;
|
|
13
|
+
roleId: Portal;
|
|
14
|
+
tenantId: string;
|
|
15
|
+
expiresAt: string;
|
|
16
|
+
status: string;
|
|
17
|
+
}>;
|
|
18
|
+
requestRecovery(portal: Portal, raw: unknown, address: string): Promise<{
|
|
19
|
+
message: string;
|
|
20
|
+
}>;
|
|
21
|
+
complete(portal: Portal, kind: "invitation" | "recovery", raw: unknown, address: string): Promise<{
|
|
22
|
+
message: string;
|
|
23
|
+
}>;
|
|
24
|
+
list(actor: Principal, query: IdentityListQuery): Promise<{
|
|
25
|
+
data: {
|
|
26
|
+
id: string;
|
|
27
|
+
email: string;
|
|
28
|
+
name: string;
|
|
29
|
+
roleId: Portal;
|
|
30
|
+
tenantId: string;
|
|
31
|
+
expiresAt: string;
|
|
32
|
+
status: string;
|
|
33
|
+
}[];
|
|
34
|
+
meta: {
|
|
35
|
+
page: number;
|
|
36
|
+
perPage: number;
|
|
37
|
+
total: number;
|
|
38
|
+
lastPage: number;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
show(actor: Principal, id: string): Promise<{
|
|
42
|
+
id: string;
|
|
43
|
+
email: string;
|
|
44
|
+
name: string;
|
|
45
|
+
roleId: Portal;
|
|
46
|
+
tenantId: string;
|
|
47
|
+
expiresAt: string;
|
|
48
|
+
status: string;
|
|
49
|
+
}>;
|
|
50
|
+
resend(actor: Principal, id: string): Promise<{
|
|
51
|
+
id: string;
|
|
52
|
+
email: string;
|
|
53
|
+
name: string;
|
|
54
|
+
roleId: Portal;
|
|
55
|
+
tenantId: string;
|
|
56
|
+
expiresAt: string;
|
|
57
|
+
status: string;
|
|
58
|
+
}>;
|
|
59
|
+
revoke(actor: Principal, id: string): Promise<void>;
|
|
60
|
+
private requireDelivery;
|
|
61
|
+
private issue;
|
|
62
|
+
private present;
|
|
63
|
+
private audit;
|
|
64
|
+
}
|