@absolutejs/auth 0.26.0-beta.3 → 0.26.0-beta.5
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/audit/types.d.ts +1 -1
- package/dist/index.d.ts +5531 -440
- package/dist/index.js +2492 -1108
- package/dist/index.js.map +30 -7
- package/dist/organizations/config.d.ts +46 -0
- package/dist/organizations/inMemoryOrganizationStore.d.ts +2 -0
- package/dist/organizations/operations.d.ts +32 -0
- package/dist/organizations/postgresOrganizationStore.d.ts +412 -0
- package/dist/organizations/routes.d.ts +299 -0
- package/dist/organizations/types.d.ts +44 -0
- package/dist/passwordless/config.d.ts +42 -0
- package/dist/passwordless/inMemoryPasswordlessTokenStore.d.ts +2 -0
- package/dist/passwordless/postgresPasswordlessTokenStore.d.ts +66 -0
- package/dist/passwordless/routes.d.ts +163 -0
- package/dist/passwordless/types.d.ts +9 -0
- package/dist/portal/config.d.ts +34 -0
- package/dist/portal/inMemorySetupSessionStore.d.ts +2 -0
- package/dist/portal/operations.d.ts +10 -0
- package/dist/portal/postgresSetupSessionStore.d.ts +140 -0
- package/dist/portal/routes.d.ts +160 -0
- package/dist/portal/types.d.ts +16 -0
- package/dist/roles/config.d.ts +27 -0
- package/dist/roles/inMemoryRoleStore.d.ts +2 -0
- package/dist/roles/operations.d.ts +8 -0
- package/dist/roles/postgresRoleStore.d.ts +102 -0
- package/dist/roles/resolver.d.ts +17 -0
- package/dist/roles/routes.d.ts +106 -0
- package/dist/roles/types.d.ts +14 -0
- package/dist/types.d.ts +29 -0
- package/dist/webhooks/config.d.ts +21 -0
- package/dist/webhooks/dispatcher.d.ts +3 -0
- package/dist/webhooks/sign.d.ts +11 -0
- package/dist/webhooks/types.d.ts +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { SessionRecord } from '../types';
|
|
3
|
+
import { type OrganizationsRouteProps } from './config';
|
|
4
|
+
export declare const organizationRoutes: <UserType>({ authSessionStore, canCreateOrganization, canManageMembers, emit, getUserId, invitationDurationMs, onMembershipAdded, onMembershipRemoved, onOrganizationCreated, onSendInvitation, organizationsRoute, organizationStore, ownerRoles }: OrganizationsRouteProps<UserType>) => Elysia<"", {
|
|
5
|
+
decorator: {};
|
|
6
|
+
store: {
|
|
7
|
+
session: SessionRecord<UserType>;
|
|
8
|
+
unregisteredSession: import("..").UnregisteredSessionRecord;
|
|
9
|
+
};
|
|
10
|
+
derive: {};
|
|
11
|
+
resolve: {};
|
|
12
|
+
}, {
|
|
13
|
+
typebox: {};
|
|
14
|
+
error: {};
|
|
15
|
+
}, {
|
|
16
|
+
schema: {};
|
|
17
|
+
standaloneSchema: {};
|
|
18
|
+
macro: {};
|
|
19
|
+
macroFn: {};
|
|
20
|
+
parser: {};
|
|
21
|
+
response: {};
|
|
22
|
+
}, {
|
|
23
|
+
[x: string]: {
|
|
24
|
+
get: {
|
|
25
|
+
body: unknown;
|
|
26
|
+
params: {};
|
|
27
|
+
query: unknown;
|
|
28
|
+
headers: unknown;
|
|
29
|
+
response: {
|
|
30
|
+
200: {
|
|
31
|
+
readonly organizations: {
|
|
32
|
+
membership: import("./types").OrganizationMembership;
|
|
33
|
+
organization: import("./types").Organization | undefined;
|
|
34
|
+
}[];
|
|
35
|
+
};
|
|
36
|
+
401: "Authentication required";
|
|
37
|
+
422: {
|
|
38
|
+
type: "validation";
|
|
39
|
+
on: string;
|
|
40
|
+
summary?: string;
|
|
41
|
+
message?: string;
|
|
42
|
+
found?: unknown;
|
|
43
|
+
property?: string;
|
|
44
|
+
expected?: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
} & {
|
|
50
|
+
[x: string]: {
|
|
51
|
+
post: {
|
|
52
|
+
body: {
|
|
53
|
+
metadata?: {} | undefined;
|
|
54
|
+
name: string;
|
|
55
|
+
};
|
|
56
|
+
params: {};
|
|
57
|
+
query: unknown;
|
|
58
|
+
headers: unknown;
|
|
59
|
+
response: {
|
|
60
|
+
200: {
|
|
61
|
+
readonly organization: import("./types").Organization;
|
|
62
|
+
};
|
|
63
|
+
401: "Authentication required";
|
|
64
|
+
403: "Cannot create organizations";
|
|
65
|
+
422: {
|
|
66
|
+
type: "validation";
|
|
67
|
+
on: string;
|
|
68
|
+
summary?: string;
|
|
69
|
+
message?: string;
|
|
70
|
+
found?: unknown;
|
|
71
|
+
property?: string;
|
|
72
|
+
expected?: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
} & {
|
|
78
|
+
[x: string]: {
|
|
79
|
+
":organizationId": {
|
|
80
|
+
invitations: {
|
|
81
|
+
post: {
|
|
82
|
+
body: {
|
|
83
|
+
roles?: string[] | undefined;
|
|
84
|
+
email: string;
|
|
85
|
+
};
|
|
86
|
+
params: {
|
|
87
|
+
organizationId: string;
|
|
88
|
+
};
|
|
89
|
+
query: unknown;
|
|
90
|
+
headers: unknown;
|
|
91
|
+
response: {
|
|
92
|
+
200: {
|
|
93
|
+
readonly invitationId: string;
|
|
94
|
+
readonly token: string;
|
|
95
|
+
};
|
|
96
|
+
401: "Authentication required";
|
|
97
|
+
403: "Cannot manage members";
|
|
98
|
+
422: {
|
|
99
|
+
type: "validation";
|
|
100
|
+
on: string;
|
|
101
|
+
summary?: string;
|
|
102
|
+
message?: string;
|
|
103
|
+
found?: unknown;
|
|
104
|
+
property?: string;
|
|
105
|
+
expected?: string;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
} & {
|
|
113
|
+
[x: string]: {
|
|
114
|
+
":organizationId": {
|
|
115
|
+
invitations: {
|
|
116
|
+
get: {
|
|
117
|
+
body: unknown;
|
|
118
|
+
params: {
|
|
119
|
+
organizationId: string;
|
|
120
|
+
};
|
|
121
|
+
query: unknown;
|
|
122
|
+
headers: unknown;
|
|
123
|
+
response: {
|
|
124
|
+
200: {
|
|
125
|
+
readonly invitations: {
|
|
126
|
+
email: string;
|
|
127
|
+
expiresAt: number;
|
|
128
|
+
invitationId: string;
|
|
129
|
+
roles: string[];
|
|
130
|
+
state: import("./types").InvitationState;
|
|
131
|
+
}[];
|
|
132
|
+
};
|
|
133
|
+
401: "Authentication required";
|
|
134
|
+
403: "Cannot manage members";
|
|
135
|
+
422: {
|
|
136
|
+
type: "validation";
|
|
137
|
+
on: string;
|
|
138
|
+
summary?: string;
|
|
139
|
+
message?: string;
|
|
140
|
+
found?: unknown;
|
|
141
|
+
property?: string;
|
|
142
|
+
expected?: string;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
} & {
|
|
150
|
+
[x: string]: {
|
|
151
|
+
":organizationId": {
|
|
152
|
+
invitations: {
|
|
153
|
+
":invitationId": {
|
|
154
|
+
delete: {
|
|
155
|
+
body: unknown;
|
|
156
|
+
params: {
|
|
157
|
+
organizationId: string;
|
|
158
|
+
invitationId: string;
|
|
159
|
+
};
|
|
160
|
+
query: unknown;
|
|
161
|
+
headers: unknown;
|
|
162
|
+
response: {
|
|
163
|
+
200: {
|
|
164
|
+
readonly revoked: string;
|
|
165
|
+
};
|
|
166
|
+
401: "Authentication required";
|
|
167
|
+
403: "Cannot manage members";
|
|
168
|
+
404: "Invitation not found";
|
|
169
|
+
422: {
|
|
170
|
+
type: "validation";
|
|
171
|
+
on: string;
|
|
172
|
+
summary?: string;
|
|
173
|
+
message?: string;
|
|
174
|
+
found?: unknown;
|
|
175
|
+
property?: string;
|
|
176
|
+
expected?: string;
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
} & {
|
|
185
|
+
[x: string]: {
|
|
186
|
+
invitations: {
|
|
187
|
+
accept: {
|
|
188
|
+
post: {
|
|
189
|
+
body: {
|
|
190
|
+
token: string;
|
|
191
|
+
};
|
|
192
|
+
params: {};
|
|
193
|
+
query: unknown;
|
|
194
|
+
headers: unknown;
|
|
195
|
+
response: {
|
|
196
|
+
200: {
|
|
197
|
+
readonly organizationId: string;
|
|
198
|
+
readonly roles: string[];
|
|
199
|
+
};
|
|
200
|
+
400: "Invalid or expired invitation";
|
|
201
|
+
401: "Authentication required";
|
|
202
|
+
422: {
|
|
203
|
+
type: "validation";
|
|
204
|
+
on: string;
|
|
205
|
+
summary?: string;
|
|
206
|
+
message?: string;
|
|
207
|
+
found?: unknown;
|
|
208
|
+
property?: string;
|
|
209
|
+
expected?: string;
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
} & {
|
|
217
|
+
[x: string]: {
|
|
218
|
+
":organizationId": {
|
|
219
|
+
members: {
|
|
220
|
+
get: {
|
|
221
|
+
body: unknown;
|
|
222
|
+
params: {
|
|
223
|
+
organizationId: string;
|
|
224
|
+
};
|
|
225
|
+
query: unknown;
|
|
226
|
+
headers: unknown;
|
|
227
|
+
response: {
|
|
228
|
+
200: {
|
|
229
|
+
readonly members: import("./types").OrganizationMembership[];
|
|
230
|
+
};
|
|
231
|
+
401: "Authentication required";
|
|
232
|
+
403: "Not a member";
|
|
233
|
+
422: {
|
|
234
|
+
type: "validation";
|
|
235
|
+
on: string;
|
|
236
|
+
summary?: string;
|
|
237
|
+
message?: string;
|
|
238
|
+
found?: unknown;
|
|
239
|
+
property?: string;
|
|
240
|
+
expected?: string;
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
} & {
|
|
248
|
+
[x: string]: {
|
|
249
|
+
":organizationId": {
|
|
250
|
+
members: {
|
|
251
|
+
":userId": {
|
|
252
|
+
delete: {
|
|
253
|
+
body: unknown;
|
|
254
|
+
params: {
|
|
255
|
+
userId: string;
|
|
256
|
+
organizationId: string;
|
|
257
|
+
};
|
|
258
|
+
query: unknown;
|
|
259
|
+
headers: unknown;
|
|
260
|
+
response: {
|
|
261
|
+
200: {
|
|
262
|
+
readonly removed: string;
|
|
263
|
+
};
|
|
264
|
+
401: "Authentication required";
|
|
265
|
+
403: "Cannot manage members";
|
|
266
|
+
422: {
|
|
267
|
+
type: "validation";
|
|
268
|
+
on: string;
|
|
269
|
+
summary?: string;
|
|
270
|
+
message?: string;
|
|
271
|
+
found?: unknown;
|
|
272
|
+
property?: string;
|
|
273
|
+
expected?: string;
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
}, {
|
|
282
|
+
derive: {};
|
|
283
|
+
resolve: {};
|
|
284
|
+
schema: {};
|
|
285
|
+
standaloneSchema: {};
|
|
286
|
+
response: {};
|
|
287
|
+
}, {
|
|
288
|
+
derive: {};
|
|
289
|
+
resolve: {};
|
|
290
|
+
schema: {};
|
|
291
|
+
standaloneSchema: {};
|
|
292
|
+
response: {};
|
|
293
|
+
} & {
|
|
294
|
+
derive: {};
|
|
295
|
+
resolve: {};
|
|
296
|
+
schema: {};
|
|
297
|
+
standaloneSchema: {};
|
|
298
|
+
response: {};
|
|
299
|
+
}>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { OrganizationId } from '../tenancy';
|
|
2
|
+
export type Organization = {
|
|
3
|
+
createdAt: number;
|
|
4
|
+
metadata?: Record<string, unknown>;
|
|
5
|
+
name: string;
|
|
6
|
+
organizationId: OrganizationId;
|
|
7
|
+
updatedAt: number;
|
|
8
|
+
};
|
|
9
|
+
export type MembershipStatus = 'active' | 'suspended';
|
|
10
|
+
export type OrganizationMembership = {
|
|
11
|
+
createdAt: number;
|
|
12
|
+
organizationId: OrganizationId;
|
|
13
|
+
roles: string[];
|
|
14
|
+
status: MembershipStatus;
|
|
15
|
+
updatedAt: number;
|
|
16
|
+
userId: string;
|
|
17
|
+
};
|
|
18
|
+
export type InvitationState = 'accepted' | 'pending' | 'revoked';
|
|
19
|
+
export type OrganizationInvitation = {
|
|
20
|
+
acceptedAt?: number;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
email: string;
|
|
23
|
+
expiresAt: number;
|
|
24
|
+
invitationId: string;
|
|
25
|
+
inviterUserId?: string;
|
|
26
|
+
organizationId: OrganizationId;
|
|
27
|
+
roles: string[];
|
|
28
|
+
state: InvitationState;
|
|
29
|
+
tokenHash: string;
|
|
30
|
+
};
|
|
31
|
+
export type OrganizationStore = {
|
|
32
|
+
deleteOrganization: (organizationId: OrganizationId) => Promise<void>;
|
|
33
|
+
getInvitation: (invitationId: string) => Promise<OrganizationInvitation | undefined>;
|
|
34
|
+
getInvitationByTokenHash: (tokenHash: string) => Promise<OrganizationInvitation | undefined>;
|
|
35
|
+
getMembership: (organizationId: OrganizationId, userId: string) => Promise<OrganizationMembership | undefined>;
|
|
36
|
+
getOrganization: (organizationId: OrganizationId) => Promise<Organization | undefined>;
|
|
37
|
+
listInvitationsByOrganization: (organizationId: OrganizationId) => Promise<OrganizationInvitation[]>;
|
|
38
|
+
listMembershipsByOrganization: (organizationId: OrganizationId) => Promise<OrganizationMembership[]>;
|
|
39
|
+
listMembershipsByUser: (userId: string) => Promise<OrganizationMembership[]>;
|
|
40
|
+
removeMembership: (organizationId: OrganizationId, userId: string) => Promise<void>;
|
|
41
|
+
saveInvitation: (invitation: OrganizationInvitation) => Promise<void>;
|
|
42
|
+
saveMembership: (membership: OrganizationMembership) => Promise<void>;
|
|
43
|
+
saveOrganization: (organization: Organization) => Promise<void>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AuditEmitter } from '../audit/config';
|
|
2
|
+
import type { AuthSessionStore } from '../session/types';
|
|
3
|
+
import type { RouteString, UserSessionId } from '../types';
|
|
4
|
+
import type { PasswordlessTokenStore } from './types';
|
|
5
|
+
export declare const DEFAULT_MAGIC_LINK_TTL_MS: number;
|
|
6
|
+
export declare const DEFAULT_OTP_LENGTH = 6;
|
|
7
|
+
export declare const DEFAULT_OTP_TTL_MS: number;
|
|
8
|
+
export declare const DEFAULT_PASSWORDLESS_ROUTE: RouteString;
|
|
9
|
+
export declare const DEFAULT_PASSWORDLESS_SESSION_TTL_MS: number;
|
|
10
|
+
export type MagicLinkMessage = {
|
|
11
|
+
email: string;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
token: string;
|
|
14
|
+
};
|
|
15
|
+
export type PasswordlessOtpMessage = {
|
|
16
|
+
code: string;
|
|
17
|
+
email: string;
|
|
18
|
+
expiresAt: number;
|
|
19
|
+
};
|
|
20
|
+
export type PasswordlessConfig<UserType> = {
|
|
21
|
+
getUserByEmail: (email: string) => Promise<UserType | null | undefined> | UserType | null | undefined;
|
|
22
|
+
passwordlessTokenStore: PasswordlessTokenStore;
|
|
23
|
+
getUserId?: (user: UserType) => string;
|
|
24
|
+
magicLinkTokenDurationMs?: number;
|
|
25
|
+
onCreateUser?: (context: {
|
|
26
|
+
email: string;
|
|
27
|
+
}) => Promise<UserType> | UserType;
|
|
28
|
+
onPasswordlessLogin?: (context: {
|
|
29
|
+
user: UserType;
|
|
30
|
+
userSessionId: UserSessionId;
|
|
31
|
+
}) => void | Promise<void>;
|
|
32
|
+
onSendMagicLink?: (message: MagicLinkMessage) => void | Promise<void>;
|
|
33
|
+
onSendOtp?: (message: PasswordlessOtpMessage) => void | Promise<void>;
|
|
34
|
+
otpDurationMs?: number;
|
|
35
|
+
otpLength?: number;
|
|
36
|
+
passwordlessRoute?: RouteString;
|
|
37
|
+
sessionDurationMs?: number;
|
|
38
|
+
};
|
|
39
|
+
export type PasswordlessRouteProps<UserType> = PasswordlessConfig<UserType> & {
|
|
40
|
+
authSessionStore?: AuthSessionStore<UserType>;
|
|
41
|
+
emit?: AuditEmitter;
|
|
42
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type AnyPgDatabase } from '../stores/postgres';
|
|
2
|
+
import type { PasswordlessTokenStore } from './types';
|
|
3
|
+
export declare const passwordlessTokensTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
4
|
+
name: "auth_passwordless_tokens";
|
|
5
|
+
schema: undefined;
|
|
6
|
+
columns: {
|
|
7
|
+
email: import("drizzle-orm/pg-core").PgColumn<{
|
|
8
|
+
name: "email";
|
|
9
|
+
tableName: "auth_passwordless_tokens";
|
|
10
|
+
dataType: "string";
|
|
11
|
+
columnType: "PgVarchar";
|
|
12
|
+
data: string;
|
|
13
|
+
driverParam: string;
|
|
14
|
+
notNull: true;
|
|
15
|
+
hasDefault: false;
|
|
16
|
+
isPrimaryKey: false;
|
|
17
|
+
isAutoincrement: false;
|
|
18
|
+
hasRuntimeDefault: false;
|
|
19
|
+
enumValues: [string, ...string[]];
|
|
20
|
+
baseColumn: never;
|
|
21
|
+
identity: undefined;
|
|
22
|
+
generated: undefined;
|
|
23
|
+
}, {}, {
|
|
24
|
+
length: 255;
|
|
25
|
+
}>;
|
|
26
|
+
expires_at_ms: import("drizzle-orm/pg-core").PgColumn<{
|
|
27
|
+
name: "expires_at_ms";
|
|
28
|
+
tableName: "auth_passwordless_tokens";
|
|
29
|
+
dataType: "number";
|
|
30
|
+
columnType: "PgBigInt53";
|
|
31
|
+
data: number;
|
|
32
|
+
driverParam: string | number;
|
|
33
|
+
notNull: true;
|
|
34
|
+
hasDefault: false;
|
|
35
|
+
isPrimaryKey: false;
|
|
36
|
+
isAutoincrement: false;
|
|
37
|
+
hasRuntimeDefault: false;
|
|
38
|
+
enumValues: undefined;
|
|
39
|
+
baseColumn: never;
|
|
40
|
+
identity: undefined;
|
|
41
|
+
generated: undefined;
|
|
42
|
+
}, {}, {}>;
|
|
43
|
+
token_hash: import("drizzle-orm/pg-core").PgColumn<{
|
|
44
|
+
name: "token_hash";
|
|
45
|
+
tableName: "auth_passwordless_tokens";
|
|
46
|
+
dataType: "string";
|
|
47
|
+
columnType: "PgVarchar";
|
|
48
|
+
data: string;
|
|
49
|
+
driverParam: string;
|
|
50
|
+
notNull: true;
|
|
51
|
+
hasDefault: false;
|
|
52
|
+
isPrimaryKey: true;
|
|
53
|
+
isAutoincrement: false;
|
|
54
|
+
hasRuntimeDefault: false;
|
|
55
|
+
enumValues: [string, ...string[]];
|
|
56
|
+
baseColumn: never;
|
|
57
|
+
identity: undefined;
|
|
58
|
+
generated: undefined;
|
|
59
|
+
}, {}, {
|
|
60
|
+
length: 255;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
dialect: "pg";
|
|
64
|
+
}>;
|
|
65
|
+
export declare const createNeonPasswordlessTokenStore: (databaseUrl: string) => PasswordlessTokenStore;
|
|
66
|
+
export declare const createPostgresPasswordlessTokenStore: (db: AnyPgDatabase) => PasswordlessTokenStore;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { SessionRecord } from '../types';
|
|
3
|
+
import { type PasswordlessRouteProps } from './config';
|
|
4
|
+
export declare const passwordlessRoutes: <UserType>({ authSessionStore, emit, getUserByEmail, getUserId, magicLinkTokenDurationMs, onCreateUser, onPasswordlessLogin, onSendMagicLink, onSendOtp, otpDurationMs, otpLength, passwordlessRoute, passwordlessTokenStore, sessionDurationMs }: PasswordlessRouteProps<UserType>) => Elysia<"", {
|
|
5
|
+
decorator: {};
|
|
6
|
+
store: {} | {
|
|
7
|
+
session: SessionRecord<UserType>;
|
|
8
|
+
unregisteredSession: import("..").UnregisteredSessionRecord;
|
|
9
|
+
} | {
|
|
10
|
+
session: SessionRecord<UserType>;
|
|
11
|
+
unregisteredSession: import("..").UnregisteredSessionRecord;
|
|
12
|
+
} | {
|
|
13
|
+
session: SessionRecord<UserType>;
|
|
14
|
+
unregisteredSession: import("..").UnregisteredSessionRecord;
|
|
15
|
+
};
|
|
16
|
+
derive: {};
|
|
17
|
+
resolve: {};
|
|
18
|
+
}, {
|
|
19
|
+
typebox: {};
|
|
20
|
+
error: {};
|
|
21
|
+
}, {
|
|
22
|
+
schema: {};
|
|
23
|
+
standaloneSchema: {};
|
|
24
|
+
macro: {};
|
|
25
|
+
macroFn: {};
|
|
26
|
+
parser: {};
|
|
27
|
+
response: {};
|
|
28
|
+
}, ({} | ({
|
|
29
|
+
[x: string]: {
|
|
30
|
+
"magic-link": {
|
|
31
|
+
post: {
|
|
32
|
+
body: {
|
|
33
|
+
email: string;
|
|
34
|
+
};
|
|
35
|
+
params: {};
|
|
36
|
+
query: unknown;
|
|
37
|
+
headers: unknown;
|
|
38
|
+
response: {
|
|
39
|
+
200: {
|
|
40
|
+
readonly status: "magic_link_sent";
|
|
41
|
+
};
|
|
42
|
+
422: {
|
|
43
|
+
type: "validation";
|
|
44
|
+
on: string;
|
|
45
|
+
summary?: string;
|
|
46
|
+
message?: string;
|
|
47
|
+
found?: unknown;
|
|
48
|
+
property?: string;
|
|
49
|
+
expected?: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
} & {
|
|
56
|
+
[x: string]: {
|
|
57
|
+
"magic-link": {
|
|
58
|
+
verify: {
|
|
59
|
+
post: {
|
|
60
|
+
body: {
|
|
61
|
+
token: string;
|
|
62
|
+
};
|
|
63
|
+
params: {};
|
|
64
|
+
query: unknown;
|
|
65
|
+
headers: unknown;
|
|
66
|
+
response: {
|
|
67
|
+
200: {
|
|
68
|
+
readonly status: "authenticated";
|
|
69
|
+
};
|
|
70
|
+
400: "Invalid or expired link";
|
|
71
|
+
401: "No account for this email";
|
|
72
|
+
422: {
|
|
73
|
+
type: "validation";
|
|
74
|
+
on: string;
|
|
75
|
+
summary?: string;
|
|
76
|
+
message?: string;
|
|
77
|
+
found?: unknown;
|
|
78
|
+
property?: string;
|
|
79
|
+
expected?: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
})) & ({} | ({
|
|
87
|
+
[x: string]: {
|
|
88
|
+
otp: {
|
|
89
|
+
post: {
|
|
90
|
+
body: {
|
|
91
|
+
email: string;
|
|
92
|
+
};
|
|
93
|
+
params: {};
|
|
94
|
+
query: unknown;
|
|
95
|
+
headers: unknown;
|
|
96
|
+
response: {
|
|
97
|
+
200: {
|
|
98
|
+
readonly status: "otp_sent";
|
|
99
|
+
};
|
|
100
|
+
422: {
|
|
101
|
+
type: "validation";
|
|
102
|
+
on: string;
|
|
103
|
+
summary?: string;
|
|
104
|
+
message?: string;
|
|
105
|
+
found?: unknown;
|
|
106
|
+
property?: string;
|
|
107
|
+
expected?: string;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
} & {
|
|
114
|
+
[x: string]: {
|
|
115
|
+
otp: {
|
|
116
|
+
verify: {
|
|
117
|
+
post: {
|
|
118
|
+
body: {
|
|
119
|
+
email: string;
|
|
120
|
+
code: string;
|
|
121
|
+
};
|
|
122
|
+
params: {};
|
|
123
|
+
query: unknown;
|
|
124
|
+
headers: unknown;
|
|
125
|
+
response: {
|
|
126
|
+
200: {
|
|
127
|
+
readonly status: "authenticated";
|
|
128
|
+
};
|
|
129
|
+
400: "Invalid or expired code";
|
|
130
|
+
401: "No account for this email";
|
|
131
|
+
422: {
|
|
132
|
+
type: "validation";
|
|
133
|
+
on: string;
|
|
134
|
+
summary?: string;
|
|
135
|
+
message?: string;
|
|
136
|
+
found?: unknown;
|
|
137
|
+
property?: string;
|
|
138
|
+
expected?: string;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
})), {
|
|
146
|
+
derive: {};
|
|
147
|
+
resolve: {};
|
|
148
|
+
schema: {};
|
|
149
|
+
standaloneSchema: {};
|
|
150
|
+
response: {};
|
|
151
|
+
}, {
|
|
152
|
+
derive: {};
|
|
153
|
+
resolve: {};
|
|
154
|
+
schema: {};
|
|
155
|
+
standaloneSchema: {};
|
|
156
|
+
response: {};
|
|
157
|
+
} & {
|
|
158
|
+
derive: {};
|
|
159
|
+
resolve: {};
|
|
160
|
+
schema: {};
|
|
161
|
+
standaloneSchema: {};
|
|
162
|
+
response: {};
|
|
163
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type PasswordlessToken = {
|
|
2
|
+
email: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
tokenHash: string;
|
|
5
|
+
};
|
|
6
|
+
export type PasswordlessTokenStore = {
|
|
7
|
+
consumeToken: (tokenHash: string) => Promise<PasswordlessToken | undefined>;
|
|
8
|
+
saveToken: (token: PasswordlessToken) => Promise<void>;
|
|
9
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AuditEmitter } from '../audit/config';
|
|
2
|
+
import type { ScimTokenStore } from '../scim/types';
|
|
3
|
+
import type { SSOConnectionStore, SSOConnectionType } from '../sso/types';
|
|
4
|
+
import type { OrganizationId } from '../tenancy';
|
|
5
|
+
import type { RouteString } from '../types';
|
|
6
|
+
import type { SetupCapability, SetupSessionStore } from './types';
|
|
7
|
+
export declare const DEFAULT_PORTAL_ROUTE: RouteString;
|
|
8
|
+
export declare const DEFAULT_SETUP_SESSION_TTL_MS: number;
|
|
9
|
+
export type PortalConfig = {
|
|
10
|
+
setupSessionStore: SetupSessionStore;
|
|
11
|
+
onScimTokenCreated?: (context: {
|
|
12
|
+
organizationId: OrganizationId;
|
|
13
|
+
tokenId: string;
|
|
14
|
+
}) => void | Promise<void>;
|
|
15
|
+
onSsoConnectionConfigured?: (context: {
|
|
16
|
+
organizationId: OrganizationId;
|
|
17
|
+
type: SSOConnectionType;
|
|
18
|
+
}) => void | Promise<void>;
|
|
19
|
+
portalRoute?: RouteString;
|
|
20
|
+
scimRoute?: RouteString;
|
|
21
|
+
scimTokenStore?: ScimTokenStore;
|
|
22
|
+
ssoConnectionStore?: SSOConnectionStore;
|
|
23
|
+
ssoRoute?: RouteString;
|
|
24
|
+
};
|
|
25
|
+
export type PortalRouteProps = PortalConfig & {
|
|
26
|
+
emit?: AuditEmitter;
|
|
27
|
+
};
|
|
28
|
+
export type SetupSessionRequest = {
|
|
29
|
+
capabilities: SetupCapability[];
|
|
30
|
+
createdBy?: string;
|
|
31
|
+
organizationId: OrganizationId;
|
|
32
|
+
setupSessionDurationMs?: number;
|
|
33
|
+
setupSessionStore: SetupSessionStore;
|
|
34
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type SetupSessionRequest } from './config';
|
|
2
|
+
import type { SetupSession, SetupSessionStore } from './types';
|
|
3
|
+
export declare const createSetupSession: ({ capabilities, createdBy, organizationId, setupSessionDurationMs, setupSessionStore }: SetupSessionRequest) => Promise<{
|
|
4
|
+
setupSession: SetupSession;
|
|
5
|
+
token: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const resolveSetupSession: ({ authorization, setupSessionStore }: {
|
|
8
|
+
authorization: string | undefined;
|
|
9
|
+
setupSessionStore: SetupSessionStore;
|
|
10
|
+
}) => Promise<SetupSession | undefined>;
|