workos 0.11.2 → 0.12.0
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 +165 -6
- package/dist/bin.js +22 -1
- package/dist/bin.js.map +1 -1
- package/dist/check-coverage.ts +237 -0
- package/dist/commands/debug.js +0 -1
- package/dist/commands/debug.js.map +1 -1
- package/dist/commands/dev.d.ts +23 -0
- package/dist/commands/dev.js +139 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/emulate.d.ts +6 -0
- package/dist/commands/emulate.js +64 -0
- package/dist/commands/emulate.js.map +1 -0
- package/dist/commands/login.js +0 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/emulate/core/id.d.ts +48 -0
- package/dist/emulate/core/id.js +73 -0
- package/dist/emulate/core/id.js.map +1 -0
- package/dist/emulate/core/index.d.ts +8 -0
- package/dist/emulate/core/index.js +8 -0
- package/dist/emulate/core/index.js.map +1 -0
- package/dist/emulate/core/jwt.d.ts +28 -0
- package/dist/emulate/core/jwt.js +78 -0
- package/dist/emulate/core/jwt.js.map +1 -0
- package/dist/emulate/core/middleware/auth.d.ts +15 -0
- package/dist/emulate/core/middleware/auth.js +17 -0
- package/dist/emulate/core/middleware/auth.js.map +1 -0
- package/dist/emulate/core/middleware/error-handler.d.ts +22 -0
- package/dist/emulate/core/middleware/error-handler.js +72 -0
- package/dist/emulate/core/middleware/error-handler.js.map +1 -0
- package/dist/emulate/core/pagination.d.ts +27 -0
- package/dist/emulate/core/pagination.js +43 -0
- package/dist/emulate/core/pagination.js.map +1 -0
- package/dist/emulate/core/plugin.d.ts +15 -0
- package/dist/emulate/core/plugin.js +2 -0
- package/dist/emulate/core/plugin.js.map +1 -0
- package/dist/emulate/core/server.d.ts +17 -0
- package/dist/emulate/core/server.js +90 -0
- package/dist/emulate/core/server.js.map +1 -0
- package/dist/emulate/core/store.d.ts +44 -0
- package/dist/emulate/core/store.js +169 -0
- package/dist/emulate/core/store.js.map +1 -0
- package/dist/emulate/index.d.ts +25 -0
- package/dist/emulate/index.js +47 -0
- package/dist/emulate/index.js.map +1 -0
- package/dist/emulate/workos/constants.d.ts +56 -0
- package/dist/emulate/workos/constants.js +56 -0
- package/dist/emulate/workos/constants.js.map +1 -0
- package/dist/emulate/workos/entities.d.ts +360 -0
- package/dist/emulate/workos/entities.js +2 -0
- package/dist/emulate/workos/entities.js.map +1 -0
- package/dist/emulate/workos/event-bus.d.ts +17 -0
- package/dist/emulate/workos/event-bus.js +70 -0
- package/dist/emulate/workos/event-bus.js.map +1 -0
- package/dist/emulate/workos/helpers.d.ts +72 -0
- package/dist/emulate/workos/helpers.js +211 -0
- package/dist/emulate/workos/helpers.js.map +1 -0
- package/dist/emulate/workos/index.d.ts +91 -0
- package/dist/emulate/workos/index.js +322 -0
- package/dist/emulate/workos/index.js.map +1 -0
- package/dist/emulate/workos/role-helpers.d.ts +21 -0
- package/dist/emulate/workos/role-helpers.js +130 -0
- package/dist/emulate/workos/role-helpers.js.map +1 -0
- package/dist/emulate/workos/routes/api-keys.d.ts +2 -0
- package/dist/emulate/workos/routes/api-keys.js +32 -0
- package/dist/emulate/workos/routes/api-keys.js.map +1 -0
- package/dist/emulate/workos/routes/audit-logs.d.ts +2 -0
- package/dist/emulate/workos/routes/audit-logs.js +104 -0
- package/dist/emulate/workos/routes/audit-logs.js.map +1 -0
- package/dist/emulate/workos/routes/auth-challenges.d.ts +2 -0
- package/dist/emulate/workos/routes/auth-challenges.js +51 -0
- package/dist/emulate/workos/routes/auth-challenges.js.map +1 -0
- package/dist/emulate/workos/routes/auth-factors.d.ts +2 -0
- package/dist/emulate/workos/routes/auth-factors.js +51 -0
- package/dist/emulate/workos/routes/auth-factors.js.map +1 -0
- package/dist/emulate/workos/routes/auth.d.ts +2 -0
- package/dist/emulate/workos/routes/auth.js +350 -0
- package/dist/emulate/workos/routes/auth.js.map +1 -0
- package/dist/emulate/workos/routes/authorization-checks.d.ts +10 -0
- package/dist/emulate/workos/routes/authorization-checks.js +123 -0
- package/dist/emulate/workos/routes/authorization-checks.js.map +1 -0
- package/dist/emulate/workos/routes/authorization-org-roles.d.ts +2 -0
- package/dist/emulate/workos/routes/authorization-org-roles.js +64 -0
- package/dist/emulate/workos/routes/authorization-org-roles.js.map +1 -0
- package/dist/emulate/workos/routes/authorization-permissions.d.ts +2 -0
- package/dist/emulate/workos/routes/authorization-permissions.js +67 -0
- package/dist/emulate/workos/routes/authorization-permissions.js.map +1 -0
- package/dist/emulate/workos/routes/authorization-resources.d.ts +2 -0
- package/dist/emulate/workos/routes/authorization-resources.js +117 -0
- package/dist/emulate/workos/routes/authorization-resources.js.map +1 -0
- package/dist/emulate/workos/routes/authorization-roles.d.ts +2 -0
- package/dist/emulate/workos/routes/authorization-roles.js +13 -0
- package/dist/emulate/workos/routes/authorization-roles.js.map +1 -0
- package/dist/emulate/workos/routes/config.d.ts +2 -0
- package/dist/emulate/workos/routes/config.js +57 -0
- package/dist/emulate/workos/routes/config.js.map +1 -0
- package/dist/emulate/workos/routes/connect.d.ts +2 -0
- package/dist/emulate/workos/routes/connect.js +65 -0
- package/dist/emulate/workos/routes/connect.js.map +1 -0
- package/dist/emulate/workos/routes/connections.d.ts +2 -0
- package/dist/emulate/workos/routes/connections.js +73 -0
- package/dist/emulate/workos/routes/connections.js.map +1 -0
- package/dist/emulate/workos/routes/data-integrations.d.ts +2 -0
- package/dist/emulate/workos/routes/data-integrations.js +55 -0
- package/dist/emulate/workos/routes/data-integrations.js.map +1 -0
- package/dist/emulate/workos/routes/directories.d.ts +2 -0
- package/dist/emulate/workos/routes/directories.js +90 -0
- package/dist/emulate/workos/routes/directories.js.map +1 -0
- package/dist/emulate/workos/routes/email-verification.d.ts +2 -0
- package/dist/emulate/workos/routes/email-verification.js +49 -0
- package/dist/emulate/workos/routes/email-verification.js.map +1 -0
- package/dist/emulate/workos/routes/events.d.ts +2 -0
- package/dist/emulate/workos/routes/events.js +18 -0
- package/dist/emulate/workos/routes/events.js.map +1 -0
- package/dist/emulate/workos/routes/feature-flags.d.ts +2 -0
- package/dist/emulate/workos/routes/feature-flags.js +103 -0
- package/dist/emulate/workos/routes/feature-flags.js.map +1 -0
- package/dist/emulate/workos/routes/invitations.d.ts +2 -0
- package/dist/emulate/workos/routes/invitations.js +122 -0
- package/dist/emulate/workos/routes/invitations.js.map +1 -0
- package/dist/emulate/workos/routes/legacy-mfa.d.ts +2 -0
- package/dist/emulate/workos/routes/legacy-mfa.js +75 -0
- package/dist/emulate/workos/routes/legacy-mfa.js.map +1 -0
- package/dist/emulate/workos/routes/magic-auth.d.ts +2 -0
- package/dist/emulate/workos/routes/magic-auth.js +32 -0
- package/dist/emulate/workos/routes/magic-auth.js.map +1 -0
- package/dist/emulate/workos/routes/memberships.d.ts +2 -0
- package/dist/emulate/workos/routes/memberships.js +114 -0
- package/dist/emulate/workos/routes/memberships.js.map +1 -0
- package/dist/emulate/workos/routes/organization-domains.d.ts +2 -0
- package/dist/emulate/workos/routes/organization-domains.js +58 -0
- package/dist/emulate/workos/routes/organization-domains.js.map +1 -0
- package/dist/emulate/workos/routes/organizations.d.ts +2 -0
- package/dist/emulate/workos/routes/organizations.js +131 -0
- package/dist/emulate/workos/routes/organizations.js.map +1 -0
- package/dist/emulate/workos/routes/password-reset.d.ts +2 -0
- package/dist/emulate/workos/routes/password-reset.js +61 -0
- package/dist/emulate/workos/routes/password-reset.js.map +1 -0
- package/dist/emulate/workos/routes/pipes.d.ts +2 -0
- package/dist/emulate/workos/routes/pipes.js +82 -0
- package/dist/emulate/workos/routes/pipes.js.map +1 -0
- package/dist/emulate/workos/routes/portal.d.ts +2 -0
- package/dist/emulate/workos/routes/portal.js +18 -0
- package/dist/emulate/workos/routes/portal.js.map +1 -0
- package/dist/emulate/workos/routes/radar.d.ts +2 -0
- package/dist/emulate/workos/routes/radar.js +41 -0
- package/dist/emulate/workos/routes/radar.js.map +1 -0
- package/dist/emulate/workos/routes/sessions.d.ts +2 -0
- package/dist/emulate/workos/routes/sessions.js +51 -0
- package/dist/emulate/workos/routes/sessions.js.map +1 -0
- package/dist/emulate/workos/routes/sso.d.ts +2 -0
- package/dist/emulate/workos/routes/sso.js +161 -0
- package/dist/emulate/workos/routes/sso.js.map +1 -0
- package/dist/emulate/workos/routes/user-features.d.ts +2 -0
- package/dist/emulate/workos/routes/user-features.js +50 -0
- package/dist/emulate/workos/routes/user-features.js.map +1 -0
- package/dist/emulate/workos/routes/users.d.ts +2 -0
- package/dist/emulate/workos/routes/users.js +129 -0
- package/dist/emulate/workos/routes/users.js.map +1 -0
- package/dist/emulate/workos/routes/webhook-endpoints.d.ts +2 -0
- package/dist/emulate/workos/routes/webhook-endpoints.js +66 -0
- package/dist/emulate/workos/routes/webhook-endpoints.js.map +1 -0
- package/dist/emulate/workos/routes/widgets.d.ts +2 -0
- package/dist/emulate/workos/routes/widgets.js +27 -0
- package/dist/emulate/workos/routes/widgets.js.map +1 -0
- package/dist/emulate/workos/store.d.ts +48 -0
- package/dist/emulate/workos/store.js +102 -0
- package/dist/emulate/workos/store.js.map +1 -0
- package/dist/emulate/workos/webhook-signer.d.ts +1 -0
- package/dist/emulate/workos/webhook-signer.js +8 -0
- package/dist/emulate/workos/webhook-signer.js.map +1 -0
- package/dist/gen-routes-lib.spec.ts +659 -0
- package/dist/gen-routes-lib.ts +647 -0
- package/dist/gen-routes.ts +96 -0
- package/dist/lib/dev-command.d.ts +26 -0
- package/dist/lib/dev-command.js +122 -0
- package/dist/lib/dev-command.js.map +1 -0
- package/dist/lib/run-with-core.js +0 -3
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/lib/settings.js +1 -1
- package/dist/lib/settings.js.map +1 -1
- package/dist/utils/help-json.js +1 -0
- package/dist/utils/help-json.js.map +1 -1
- package/dist/utils/register-subcommand.d.ts +5 -2
- package/dist/utils/register-subcommand.js +16 -19
- package/dist/utils/register-subcommand.js.map +1 -1
- package/package.json +21 -8
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { notFound, parseListParams } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatDirectory, formatDirectoryUser, formatDirectoryGroup, formatListResponse } from '../helpers.js';
|
|
4
|
+
export function directoryRoutes(ctx) {
|
|
5
|
+
const { app, store } = ctx;
|
|
6
|
+
const ws = getWorkOSStore(store);
|
|
7
|
+
// List directories
|
|
8
|
+
app.get('/directories', (c) => {
|
|
9
|
+
const url = new URL(c.req.url);
|
|
10
|
+
const params = parseListParams(url);
|
|
11
|
+
const orgFilter = url.searchParams.get('organization_id') ?? undefined;
|
|
12
|
+
const search = url.searchParams.get('search') ?? undefined;
|
|
13
|
+
const result = ws.directories.list({
|
|
14
|
+
...params,
|
|
15
|
+
filter: (d) => {
|
|
16
|
+
if (orgFilter && d.organization_id !== orgFilter)
|
|
17
|
+
return false;
|
|
18
|
+
if (search && !d.name.toLowerCase().includes(search.toLowerCase()))
|
|
19
|
+
return false;
|
|
20
|
+
return true;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return c.json(formatListResponse(result, formatDirectory));
|
|
24
|
+
});
|
|
25
|
+
// Get directory
|
|
26
|
+
app.get('/directories/:id', (c) => {
|
|
27
|
+
const dir = ws.directories.get(c.req.param('id'));
|
|
28
|
+
if (!dir)
|
|
29
|
+
throw notFound('Directory');
|
|
30
|
+
return c.json(formatDirectory(dir));
|
|
31
|
+
});
|
|
32
|
+
// Delete directory (cascade users + groups)
|
|
33
|
+
app.delete('/directories/:id', (c) => {
|
|
34
|
+
const dir = ws.directories.get(c.req.param('id'));
|
|
35
|
+
if (!dir)
|
|
36
|
+
throw notFound('Directory');
|
|
37
|
+
ws.directoryUsers.deleteBy('directory_id', dir.id);
|
|
38
|
+
ws.directoryGroups.deleteBy('directory_id', dir.id);
|
|
39
|
+
ws.directories.delete(dir.id);
|
|
40
|
+
return c.body(null, 204);
|
|
41
|
+
});
|
|
42
|
+
// List directory users
|
|
43
|
+
app.get('/directory_users', (c) => {
|
|
44
|
+
const url = new URL(c.req.url);
|
|
45
|
+
const params = parseListParams(url);
|
|
46
|
+
const directoryId = url.searchParams.get('directory_id') ?? undefined;
|
|
47
|
+
const groupId = url.searchParams.get('group_id') ?? undefined;
|
|
48
|
+
const result = ws.directoryUsers.list({
|
|
49
|
+
...params,
|
|
50
|
+
filter: (u) => {
|
|
51
|
+
if (directoryId && u.directory_id !== directoryId)
|
|
52
|
+
return false;
|
|
53
|
+
if (groupId && !u.groups.some((g) => g.id === groupId))
|
|
54
|
+
return false;
|
|
55
|
+
return true;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return c.json(formatListResponse(result, formatDirectoryUser));
|
|
59
|
+
});
|
|
60
|
+
// Get directory user
|
|
61
|
+
app.get('/directory_users/:id', (c) => {
|
|
62
|
+
const user = ws.directoryUsers.get(c.req.param('id'));
|
|
63
|
+
if (!user)
|
|
64
|
+
throw notFound('DirectoryUser');
|
|
65
|
+
return c.json(formatDirectoryUser(user));
|
|
66
|
+
});
|
|
67
|
+
// List directory groups
|
|
68
|
+
app.get('/directory_groups', (c) => {
|
|
69
|
+
const url = new URL(c.req.url);
|
|
70
|
+
const params = parseListParams(url);
|
|
71
|
+
const directoryId = url.searchParams.get('directory_id') ?? undefined;
|
|
72
|
+
const result = ws.directoryGroups.list({
|
|
73
|
+
...params,
|
|
74
|
+
filter: (g) => {
|
|
75
|
+
if (directoryId && g.directory_id !== directoryId)
|
|
76
|
+
return false;
|
|
77
|
+
return true;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
return c.json(formatListResponse(result, formatDirectoryGroup));
|
|
81
|
+
});
|
|
82
|
+
// Get directory group
|
|
83
|
+
app.get('/directory_groups/:id', (c) => {
|
|
84
|
+
const group = ws.directoryGroups.get(c.req.param('id'));
|
|
85
|
+
if (!group)
|
|
86
|
+
throw notFound('DirectoryGroup');
|
|
87
|
+
return c.json(formatDirectoryGroup(group));
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=directories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directories.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/directories.ts"],"names":[],"mappings":"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","sourcesContent":["import { type RouteContext, notFound, parseListParams } from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatDirectory, formatDirectoryUser, formatDirectoryGroup, formatListResponse } from '../helpers.js';\n\nexport function directoryRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n // List directories\n app.get('/directories', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const orgFilter = url.searchParams.get('organization_id') ?? undefined;\n const search = url.searchParams.get('search') ?? undefined;\n\n const result = ws.directories.list({\n ...params,\n filter: (d) => {\n if (orgFilter && d.organization_id !== orgFilter) return false;\n if (search && !d.name.toLowerCase().includes(search.toLowerCase())) return false;\n return true;\n },\n });\n\n return c.json(formatListResponse(result, formatDirectory));\n });\n\n // Get directory\n app.get('/directories/:id', (c) => {\n const dir = ws.directories.get(c.req.param('id'));\n if (!dir) throw notFound('Directory');\n return c.json(formatDirectory(dir));\n });\n\n // Delete directory (cascade users + groups)\n app.delete('/directories/:id', (c) => {\n const dir = ws.directories.get(c.req.param('id'));\n if (!dir) throw notFound('Directory');\n\n ws.directoryUsers.deleteBy('directory_id', dir.id);\n ws.directoryGroups.deleteBy('directory_id', dir.id);\n\n ws.directories.delete(dir.id);\n return c.body(null, 204);\n });\n\n // List directory users\n app.get('/directory_users', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const directoryId = url.searchParams.get('directory_id') ?? undefined;\n const groupId = url.searchParams.get('group_id') ?? undefined;\n\n const result = ws.directoryUsers.list({\n ...params,\n filter: (u) => {\n if (directoryId && u.directory_id !== directoryId) return false;\n if (groupId && !u.groups.some((g) => g.id === groupId)) return false;\n return true;\n },\n });\n\n return c.json(formatListResponse(result, formatDirectoryUser));\n });\n\n // Get directory user\n app.get('/directory_users/:id', (c) => {\n const user = ws.directoryUsers.get(c.req.param('id'));\n if (!user) throw notFound('DirectoryUser');\n return c.json(formatDirectoryUser(user));\n });\n\n // List directory groups\n app.get('/directory_groups', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const directoryId = url.searchParams.get('directory_id') ?? undefined;\n\n const result = ws.directoryGroups.list({\n ...params,\n filter: (g) => {\n if (directoryId && g.directory_id !== directoryId) return false;\n return true;\n },\n });\n\n return c.json(formatListResponse(result, formatDirectoryGroup));\n });\n\n // Get directory group\n app.get('/directory_groups/:id', (c) => {\n const group = ws.directoryGroups.get(c.req.param('id'));\n if (!group) throw notFound('DirectoryGroup');\n return c.json(formatDirectoryGroup(group));\n });\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatEmailVerification, formatUser, generateCode, expiresIn, isExpired } from '../helpers.js';
|
|
4
|
+
export function emailVerificationRoutes(ctx) {
|
|
5
|
+
const { app, store } = ctx;
|
|
6
|
+
const ws = getWorkOSStore(store);
|
|
7
|
+
app.get('/user_management/email_verification/:id', (c) => {
|
|
8
|
+
const ev = ws.emailVerifications.get(c.req.param('id'));
|
|
9
|
+
if (!ev)
|
|
10
|
+
throw notFound('Email Verification');
|
|
11
|
+
return c.json(formatEmailVerification(ev));
|
|
12
|
+
});
|
|
13
|
+
app.post('/user_management/users/:id/email_verification/send', (c) => {
|
|
14
|
+
const user = ws.users.get(c.req.param('id'));
|
|
15
|
+
if (!user)
|
|
16
|
+
throw notFound('User');
|
|
17
|
+
const ev = ws.emailVerifications.insert({
|
|
18
|
+
object: 'email_verification',
|
|
19
|
+
user_id: user.id,
|
|
20
|
+
email: user.email,
|
|
21
|
+
code: generateCode(),
|
|
22
|
+
expires_at: expiresIn(10),
|
|
23
|
+
});
|
|
24
|
+
return c.json(formatEmailVerification(ev), 201);
|
|
25
|
+
});
|
|
26
|
+
app.post('/user_management/users/:id/email_verification/confirm', async (c) => {
|
|
27
|
+
const user = ws.users.get(c.req.param('id'));
|
|
28
|
+
if (!user)
|
|
29
|
+
throw notFound('User');
|
|
30
|
+
const body = await parseJsonBody(c);
|
|
31
|
+
const code = body.code;
|
|
32
|
+
if (!code) {
|
|
33
|
+
throw new WorkOSApiError(400, 'code is required', 'invalid_request');
|
|
34
|
+
}
|
|
35
|
+
const verifications = ws.emailVerifications.findBy('user_id', user.id);
|
|
36
|
+
const ev = verifications.find((v) => v.code === code);
|
|
37
|
+
if (!ev) {
|
|
38
|
+
throw new WorkOSApiError(400, 'Invalid code', 'invalid_code');
|
|
39
|
+
}
|
|
40
|
+
if (isExpired(ev.expires_at)) {
|
|
41
|
+
throw new WorkOSApiError(400, 'Code has expired', 'expired_code');
|
|
42
|
+
}
|
|
43
|
+
ws.users.update(user.id, { email_verified: true });
|
|
44
|
+
ws.emailVerifications.delete(ev.id);
|
|
45
|
+
const updated = ws.users.get(user.id);
|
|
46
|
+
return c.json(formatUser(updated));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=email-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-verification.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/email-verification.ts"],"names":[],"mappings":"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","sourcesContent":["import { type RouteContext, notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatEmailVerification, formatUser, generateCode, expiresIn, isExpired } from '../helpers.js';\n\nexport function emailVerificationRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n app.get('/user_management/email_verification/:id', (c) => {\n const ev = ws.emailVerifications.get(c.req.param('id'));\n if (!ev) throw notFound('Email Verification');\n return c.json(formatEmailVerification(ev));\n });\n\n app.post('/user_management/users/:id/email_verification/send', (c) => {\n const user = ws.users.get(c.req.param('id'));\n if (!user) throw notFound('User');\n\n const ev = ws.emailVerifications.insert({\n object: 'email_verification',\n user_id: user.id,\n email: user.email,\n code: generateCode(),\n expires_at: expiresIn(10),\n });\n\n return c.json(formatEmailVerification(ev), 201);\n });\n\n app.post('/user_management/users/:id/email_verification/confirm', async (c) => {\n const user = ws.users.get(c.req.param('id'));\n if (!user) throw notFound('User');\n\n const body = await parseJsonBody(c);\n const code = body.code as string | undefined;\n if (!code) {\n throw new WorkOSApiError(400, 'code is required', 'invalid_request');\n }\n\n const verifications = ws.emailVerifications.findBy('user_id', user.id);\n const ev = verifications.find((v) => v.code === code);\n\n if (!ev) {\n throw new WorkOSApiError(400, 'Invalid code', 'invalid_code');\n }\n if (isExpired(ev.expires_at)) {\n throw new WorkOSApiError(400, 'Code has expired', 'expired_code');\n }\n\n ws.users.update(user.id, { email_verified: true });\n ws.emailVerifications.delete(ev.id);\n\n const updated = ws.users.get(user.id)!;\n return c.json(formatUser(updated));\n });\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { parseListParams } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatEvent, formatListResponse } from '../helpers.js';
|
|
4
|
+
export function eventRoutes(ctx) {
|
|
5
|
+
const { app, store } = ctx;
|
|
6
|
+
const ws = getWorkOSStore(store);
|
|
7
|
+
app.get('/events', (c) => {
|
|
8
|
+
const url = new URL(c.req.url);
|
|
9
|
+
const params = parseListParams(url);
|
|
10
|
+
const eventTypes = url.searchParams.getAll('events[]');
|
|
11
|
+
const result = ws.events.list({
|
|
12
|
+
...params,
|
|
13
|
+
filter: eventTypes.length > 0 ? (e) => eventTypes.includes(e.event) : undefined,
|
|
14
|
+
});
|
|
15
|
+
return c.json(formatListResponse(result, formatEvent));
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,UAAU,WAAW,CAAC,GAAiB;IAC3C,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;IAC3B,MAAM,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAEjC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;YAC5B,GAAG,MAAM;YACT,MAAM,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;SAChF,CAAC,CAAC;QAEH,OAAO,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { type RouteContext, parseListParams } from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatEvent, formatListResponse } from '../helpers.js';\n\nexport function eventRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n app.get('/events', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const eventTypes = url.searchParams.getAll('events[]');\n\n const result = ws.events.list({\n ...params,\n filter: eventTypes.length > 0 ? (e) => eventTypes.includes(e.event) : undefined,\n });\n\n return c.json(formatListResponse(result, formatEvent));\n });\n}\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { notFound, parseJsonBody, parseListParams } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatFeatureFlag, formatFlagTarget, formatListResponse } from '../helpers.js';
|
|
4
|
+
function evaluateFlags(ws, resourceId) {
|
|
5
|
+
const flags = ws.featureFlags.all();
|
|
6
|
+
return flags.map((flag) => {
|
|
7
|
+
const target = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);
|
|
8
|
+
return {
|
|
9
|
+
slug: flag.slug,
|
|
10
|
+
type: flag.type,
|
|
11
|
+
value: target ? target.value : flag.enabled ? flag.default_value : null,
|
|
12
|
+
enabled: flag.enabled,
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function featureFlagRoutes(ctx) {
|
|
17
|
+
const { app, store } = ctx;
|
|
18
|
+
const ws = getWorkOSStore(store);
|
|
19
|
+
// List all flags
|
|
20
|
+
app.get('/feature-flags', (c) => {
|
|
21
|
+
const url = new URL(c.req.url);
|
|
22
|
+
const params = parseListParams(url);
|
|
23
|
+
const result = ws.featureFlags.list({ ...params });
|
|
24
|
+
return c.json(formatListResponse(result, formatFeatureFlag));
|
|
25
|
+
});
|
|
26
|
+
// Get flag by slug
|
|
27
|
+
app.get('/feature-flags/:slug', (c) => {
|
|
28
|
+
const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));
|
|
29
|
+
if (!flag)
|
|
30
|
+
throw notFound('FeatureFlag');
|
|
31
|
+
return c.json(formatFeatureFlag(flag));
|
|
32
|
+
});
|
|
33
|
+
// Enable flag
|
|
34
|
+
app.post('/feature-flags/:slug/enable', (c) => {
|
|
35
|
+
const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));
|
|
36
|
+
if (!flag)
|
|
37
|
+
throw notFound('FeatureFlag');
|
|
38
|
+
const updated = ws.featureFlags.update(flag.id, { enabled: true });
|
|
39
|
+
return c.json(formatFeatureFlag(updated));
|
|
40
|
+
});
|
|
41
|
+
// Disable flag
|
|
42
|
+
app.post('/feature-flags/:slug/disable', (c) => {
|
|
43
|
+
const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));
|
|
44
|
+
if (!flag)
|
|
45
|
+
throw notFound('FeatureFlag');
|
|
46
|
+
const updated = ws.featureFlags.update(flag.id, { enabled: false });
|
|
47
|
+
return c.json(formatFeatureFlag(updated));
|
|
48
|
+
});
|
|
49
|
+
// Add/update target
|
|
50
|
+
app.put('/feature-flags/:slug/targets/:resourceId', async (c) => {
|
|
51
|
+
const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));
|
|
52
|
+
if (!flag)
|
|
53
|
+
throw notFound('FeatureFlag');
|
|
54
|
+
const resourceId = c.req.param('resourceId');
|
|
55
|
+
const body = await parseJsonBody(c);
|
|
56
|
+
// Upsert: find existing target or create
|
|
57
|
+
const existing = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);
|
|
58
|
+
if (existing) {
|
|
59
|
+
const updated = ws.flagTargets.update(existing.id, {
|
|
60
|
+
value: body.value,
|
|
61
|
+
resource_type: body.resource_type ?? existing.resource_type,
|
|
62
|
+
});
|
|
63
|
+
return c.json(formatFlagTarget(updated));
|
|
64
|
+
}
|
|
65
|
+
const target = ws.flagTargets.insert({
|
|
66
|
+
object: 'flag_target',
|
|
67
|
+
flag_slug: flag.slug,
|
|
68
|
+
resource_id: resourceId,
|
|
69
|
+
resource_type: body.resource_type ?? 'user',
|
|
70
|
+
value: body.value,
|
|
71
|
+
});
|
|
72
|
+
return c.json(formatFlagTarget(target), 201);
|
|
73
|
+
});
|
|
74
|
+
// Remove target
|
|
75
|
+
app.delete('/feature-flags/:slug/targets/:resourceId', (c) => {
|
|
76
|
+
const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));
|
|
77
|
+
if (!flag)
|
|
78
|
+
throw notFound('FeatureFlag');
|
|
79
|
+
const resourceId = c.req.param('resourceId');
|
|
80
|
+
const target = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);
|
|
81
|
+
if (!target)
|
|
82
|
+
throw notFound('FlagTarget');
|
|
83
|
+
ws.flagTargets.delete(target.id);
|
|
84
|
+
return c.body(null, 204);
|
|
85
|
+
});
|
|
86
|
+
// Evaluate flags for organization
|
|
87
|
+
app.get('/organizations/:orgId/feature-flags', (c) => {
|
|
88
|
+
return c.json({
|
|
89
|
+
object: 'list',
|
|
90
|
+
data: evaluateFlags(ws, c.req.param('orgId')),
|
|
91
|
+
list_metadata: { before: null, after: null },
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// Evaluate flags for user
|
|
95
|
+
app.get('/user_management/users/:userId/feature-flags', (c) => {
|
|
96
|
+
return c.json({
|
|
97
|
+
object: 'list',
|
|
98
|
+
data: evaluateFlags(ws, c.req.param('userId')),
|
|
99
|
+
list_metadata: { before: null, after: null },
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=feature-flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flags.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/feature-flags.ts"],"names":[],"mappings":"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","sourcesContent":["import { type RouteContext, notFound, parseJsonBody, parseListParams } from '../../core/index.js';\nimport { getWorkOSStore, type WorkOSStore } from '../store.js';\nimport { formatFeatureFlag, formatFlagTarget, formatListResponse } from '../helpers.js';\n\nfunction evaluateFlags(ws: WorkOSStore, resourceId: string) {\n const flags = ws.featureFlags.all();\n return flags.map((flag) => {\n const target = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);\n return {\n slug: flag.slug,\n type: flag.type,\n value: target ? target.value : flag.enabled ? flag.default_value : null,\n enabled: flag.enabled,\n };\n });\n}\n\nexport function featureFlagRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n // List all flags\n app.get('/feature-flags', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const result = ws.featureFlags.list({ ...params });\n return c.json(formatListResponse(result, formatFeatureFlag));\n });\n\n // Get flag by slug\n app.get('/feature-flags/:slug', (c) => {\n const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));\n if (!flag) throw notFound('FeatureFlag');\n return c.json(formatFeatureFlag(flag));\n });\n\n // Enable flag\n app.post('/feature-flags/:slug/enable', (c) => {\n const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));\n if (!flag) throw notFound('FeatureFlag');\n const updated = ws.featureFlags.update(flag.id, { enabled: true });\n return c.json(formatFeatureFlag(updated!));\n });\n\n // Disable flag\n app.post('/feature-flags/:slug/disable', (c) => {\n const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));\n if (!flag) throw notFound('FeatureFlag');\n const updated = ws.featureFlags.update(flag.id, { enabled: false });\n return c.json(formatFeatureFlag(updated!));\n });\n\n // Add/update target\n app.put('/feature-flags/:slug/targets/:resourceId', async (c) => {\n const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));\n if (!flag) throw notFound('FeatureFlag');\n\n const resourceId = c.req.param('resourceId');\n const body = await parseJsonBody(c);\n\n // Upsert: find existing target or create\n const existing = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);\n\n if (existing) {\n const updated = ws.flagTargets.update(existing.id, {\n value: body.value,\n resource_type: (body.resource_type as string) ?? existing.resource_type,\n });\n return c.json(formatFlagTarget(updated!));\n }\n\n const target = ws.flagTargets.insert({\n object: 'flag_target',\n flag_slug: flag.slug,\n resource_id: resourceId,\n resource_type: (body.resource_type as string) ?? 'user',\n value: body.value,\n });\n\n return c.json(formatFlagTarget(target), 201);\n });\n\n // Remove target\n app.delete('/feature-flags/:slug/targets/:resourceId', (c) => {\n const flag = ws.featureFlags.findOneBy('slug', c.req.param('slug'));\n if (!flag) throw notFound('FeatureFlag');\n\n const resourceId = c.req.param('resourceId');\n const target = ws.flagTargets.findBy('flag_slug', flag.slug).find((t) => t.resource_id === resourceId);\n if (!target) throw notFound('FlagTarget');\n\n ws.flagTargets.delete(target.id);\n return c.body(null, 204);\n });\n\n // Evaluate flags for organization\n app.get('/organizations/:orgId/feature-flags', (c) => {\n return c.json({\n object: 'list',\n data: evaluateFlags(ws, c.req.param('orgId')),\n list_metadata: { before: null, after: null },\n });\n });\n\n // Evaluate flags for user\n app.get('/user_management/users/:userId/feature-flags', (c) => {\n return c.json({\n object: 'list',\n data: evaluateFlags(ws, c.req.param('userId')),\n list_metadata: { before: null, after: null },\n });\n });\n}\n"]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { notFound, validationError, parseJsonBody, WorkOSApiError, parseListParams, } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatInvitation, generateVerificationToken, expiresIn, formatListResponse } from '../helpers.js';
|
|
4
|
+
import { STORE_KEYS, EVENTS } from '../constants.js';
|
|
5
|
+
export function invitationRoutes(ctx) {
|
|
6
|
+
const { app, store, baseUrl } = ctx;
|
|
7
|
+
const ws = getWorkOSStore(store);
|
|
8
|
+
app.post('/user_management/invitations', async (c) => {
|
|
9
|
+
const body = await parseJsonBody(c);
|
|
10
|
+
const email = body.email;
|
|
11
|
+
if (!email) {
|
|
12
|
+
throw validationError('email is required', [{ field: 'email', code: 'required' }]);
|
|
13
|
+
}
|
|
14
|
+
const token = generateVerificationToken();
|
|
15
|
+
const inv = ws.invitations.insert({
|
|
16
|
+
object: 'invitation',
|
|
17
|
+
email,
|
|
18
|
+
state: 'pending',
|
|
19
|
+
token,
|
|
20
|
+
accept_invitation_url: `${baseUrl}/user_management/invitations/accept?token=${token}`,
|
|
21
|
+
organization_id: body.organization_id ?? null,
|
|
22
|
+
inviter_user_id: body.inviter_user_id ?? null,
|
|
23
|
+
role_slug: body.role_slug ?? null,
|
|
24
|
+
expires_at: expiresIn(72 * 60), // 72 hours
|
|
25
|
+
});
|
|
26
|
+
return c.json(formatInvitation(inv), 201);
|
|
27
|
+
});
|
|
28
|
+
app.get('/user_management/invitations', (c) => {
|
|
29
|
+
const url = new URL(c.req.url);
|
|
30
|
+
const params = parseListParams(url);
|
|
31
|
+
const emailFilter = url.searchParams.get('email') ?? undefined;
|
|
32
|
+
const orgFilter = url.searchParams.get('organization_id') ?? undefined;
|
|
33
|
+
const result = ws.invitations.list({
|
|
34
|
+
...params,
|
|
35
|
+
filter: (inv) => {
|
|
36
|
+
if (emailFilter && inv.email !== emailFilter)
|
|
37
|
+
return false;
|
|
38
|
+
if (orgFilter && inv.organization_id !== orgFilter)
|
|
39
|
+
return false;
|
|
40
|
+
return true;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return c.json(formatListResponse(result, formatInvitation));
|
|
44
|
+
});
|
|
45
|
+
app.get('/user_management/invitations/by_token/:token', (c) => {
|
|
46
|
+
const inv = ws.invitations.findOneBy('token', c.req.param('token'));
|
|
47
|
+
if (!inv)
|
|
48
|
+
throw notFound('Invitation');
|
|
49
|
+
return c.json(formatInvitation(inv));
|
|
50
|
+
});
|
|
51
|
+
app.get('/user_management/invitations/:id', (c) => {
|
|
52
|
+
const inv = ws.invitations.get(c.req.param('id'));
|
|
53
|
+
if (!inv)
|
|
54
|
+
throw notFound('Invitation');
|
|
55
|
+
return c.json(formatInvitation(inv));
|
|
56
|
+
});
|
|
57
|
+
app.post('/user_management/invitations/:id/accept', (c) => {
|
|
58
|
+
const inv = ws.invitations.get(c.req.param('id'));
|
|
59
|
+
if (!inv)
|
|
60
|
+
throw notFound('Invitation');
|
|
61
|
+
if (inv.state !== 'pending') {
|
|
62
|
+
throw new WorkOSApiError(400, `Invitation is ${inv.state}`, 'invalid_invitation_state');
|
|
63
|
+
}
|
|
64
|
+
ws.invitations.update(inv.id, { state: 'accepted' });
|
|
65
|
+
const eventBus = store.getData(STORE_KEYS.eventBus);
|
|
66
|
+
eventBus?.emit({ event: EVENTS.invitationAccepted, data: formatInvitation(ws.invitations.get(inv.id)) });
|
|
67
|
+
// Create org membership if invitation has an organization
|
|
68
|
+
if (inv.organization_id) {
|
|
69
|
+
const user = ws.users.findOneBy('email', inv.email);
|
|
70
|
+
if (user) {
|
|
71
|
+
ws.organizationMemberships.insert({
|
|
72
|
+
object: 'organization_membership',
|
|
73
|
+
organization_id: inv.organization_id,
|
|
74
|
+
user_id: user.id,
|
|
75
|
+
role: { slug: inv.role_slug ?? 'member' },
|
|
76
|
+
status: 'active',
|
|
77
|
+
external_id: null,
|
|
78
|
+
metadata: {},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const updated = ws.invitations.get(inv.id);
|
|
83
|
+
return c.json(formatInvitation(updated));
|
|
84
|
+
});
|
|
85
|
+
app.post('/user_management/invitations/:id/revoke', (c) => {
|
|
86
|
+
const inv = ws.invitations.get(c.req.param('id'));
|
|
87
|
+
if (!inv)
|
|
88
|
+
throw notFound('Invitation');
|
|
89
|
+
if (inv.state !== 'pending') {
|
|
90
|
+
throw new WorkOSApiError(400, `Invitation is ${inv.state}`, 'invalid_invitation_state');
|
|
91
|
+
}
|
|
92
|
+
ws.invitations.update(inv.id, { state: 'revoked' });
|
|
93
|
+
const eventBus = store.getData(STORE_KEYS.eventBus);
|
|
94
|
+
eventBus?.emit({ event: EVENTS.invitationRevoked, data: formatInvitation(ws.invitations.get(inv.id)) });
|
|
95
|
+
const updated = ws.invitations.get(inv.id);
|
|
96
|
+
return c.json(formatInvitation(updated));
|
|
97
|
+
});
|
|
98
|
+
app.post('/user_management/invitations/:id/resend', (c) => {
|
|
99
|
+
const inv = ws.invitations.get(c.req.param('id'));
|
|
100
|
+
if (!inv)
|
|
101
|
+
throw notFound('Invitation');
|
|
102
|
+
const newToken = generateVerificationToken();
|
|
103
|
+
ws.invitations.update(inv.id, {
|
|
104
|
+
token: newToken,
|
|
105
|
+
accept_invitation_url: `${baseUrl}/user_management/invitations/accept?token=${newToken}`,
|
|
106
|
+
expires_at: expiresIn(72 * 60),
|
|
107
|
+
state: 'pending',
|
|
108
|
+
});
|
|
109
|
+
const eventBus = store.getData(STORE_KEYS.eventBus);
|
|
110
|
+
eventBus?.emit({ event: EVENTS.invitationResent, data: formatInvitation(ws.invitations.get(inv.id)) });
|
|
111
|
+
const updated = ws.invitations.get(inv.id);
|
|
112
|
+
return c.json(formatInvitation(updated));
|
|
113
|
+
});
|
|
114
|
+
app.delete('/user_management/invitations/:id', (c) => {
|
|
115
|
+
const inv = ws.invitations.get(c.req.param('id'));
|
|
116
|
+
if (!inv)
|
|
117
|
+
throw notFound('Invitation');
|
|
118
|
+
ws.invitations.delete(inv.id);
|
|
119
|
+
return c.body(null, 204);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=invitations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invitations.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/invitations.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RouteContext,\n notFound,\n validationError,\n parseJsonBody,\n WorkOSApiError,\n parseListParams,\n} from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatInvitation, generateVerificationToken, expiresIn, formatListResponse } from '../helpers.js';\nimport type { EventBus } from '../event-bus.js';\nimport { STORE_KEYS, EVENTS } from '../constants.js';\n\nexport function invitationRoutes(ctx: RouteContext): void {\n const { app, store, baseUrl } = ctx;\n const ws = getWorkOSStore(store);\n\n app.post('/user_management/invitations', async (c) => {\n const body = await parseJsonBody(c);\n const email = body.email as string | undefined;\n if (!email) {\n throw validationError('email is required', [{ field: 'email', code: 'required' }]);\n }\n\n const token = generateVerificationToken();\n const inv = ws.invitations.insert({\n object: 'invitation',\n email,\n state: 'pending',\n token,\n accept_invitation_url: `${baseUrl}/user_management/invitations/accept?token=${token}`,\n organization_id: (body.organization_id as string) ?? null,\n inviter_user_id: (body.inviter_user_id as string) ?? null,\n role_slug: (body.role_slug as string) ?? null,\n expires_at: expiresIn(72 * 60), // 72 hours\n });\n\n return c.json(formatInvitation(inv), 201);\n });\n\n app.get('/user_management/invitations', (c) => {\n const url = new URL(c.req.url);\n const params = parseListParams(url);\n const emailFilter = url.searchParams.get('email') ?? undefined;\n const orgFilter = url.searchParams.get('organization_id') ?? undefined;\n\n const result = ws.invitations.list({\n ...params,\n filter: (inv) => {\n if (emailFilter && inv.email !== emailFilter) return false;\n if (orgFilter && inv.organization_id !== orgFilter) return false;\n return true;\n },\n });\n\n return c.json(formatListResponse(result, formatInvitation));\n });\n\n app.get('/user_management/invitations/by_token/:token', (c) => {\n const inv = ws.invitations.findOneBy('token', c.req.param('token'));\n if (!inv) throw notFound('Invitation');\n return c.json(formatInvitation(inv));\n });\n\n app.get('/user_management/invitations/:id', (c) => {\n const inv = ws.invitations.get(c.req.param('id'));\n if (!inv) throw notFound('Invitation');\n return c.json(formatInvitation(inv));\n });\n\n app.post('/user_management/invitations/:id/accept', (c) => {\n const inv = ws.invitations.get(c.req.param('id'));\n if (!inv) throw notFound('Invitation');\n\n if (inv.state !== 'pending') {\n throw new WorkOSApiError(400, `Invitation is ${inv.state}`, 'invalid_invitation_state');\n }\n\n ws.invitations.update(inv.id, { state: 'accepted' });\n const eventBus = store.getData<EventBus>(STORE_KEYS.eventBus);\n eventBus?.emit({ event: EVENTS.invitationAccepted, data: formatInvitation(ws.invitations.get(inv.id)!) });\n\n // Create org membership if invitation has an organization\n if (inv.organization_id) {\n const user = ws.users.findOneBy('email', inv.email);\n if (user) {\n ws.organizationMemberships.insert({\n object: 'organization_membership',\n organization_id: inv.organization_id,\n user_id: user.id,\n role: { slug: inv.role_slug ?? 'member' },\n status: 'active',\n external_id: null,\n metadata: {},\n });\n }\n }\n\n const updated = ws.invitations.get(inv.id)!;\n return c.json(formatInvitation(updated));\n });\n\n app.post('/user_management/invitations/:id/revoke', (c) => {\n const inv = ws.invitations.get(c.req.param('id'));\n if (!inv) throw notFound('Invitation');\n\n if (inv.state !== 'pending') {\n throw new WorkOSApiError(400, `Invitation is ${inv.state}`, 'invalid_invitation_state');\n }\n\n ws.invitations.update(inv.id, { state: 'revoked' });\n const eventBus = store.getData<EventBus>(STORE_KEYS.eventBus);\n eventBus?.emit({ event: EVENTS.invitationRevoked, data: formatInvitation(ws.invitations.get(inv.id)!) });\n const updated = ws.invitations.get(inv.id)!;\n return c.json(formatInvitation(updated));\n });\n\n app.post('/user_management/invitations/:id/resend', (c) => {\n const inv = ws.invitations.get(c.req.param('id'));\n if (!inv) throw notFound('Invitation');\n\n const newToken = generateVerificationToken();\n ws.invitations.update(inv.id, {\n token: newToken,\n accept_invitation_url: `${baseUrl}/user_management/invitations/accept?token=${newToken}`,\n expires_at: expiresIn(72 * 60),\n state: 'pending',\n });\n\n const eventBus = store.getData<EventBus>(STORE_KEYS.eventBus);\n eventBus?.emit({ event: EVENTS.invitationResent, data: formatInvitation(ws.invitations.get(inv.id)!) });\n const updated = ws.invitations.get(inv.id)!;\n return c.json(formatInvitation(updated));\n });\n\n app.delete('/user_management/invitations/:id', (c) => {\n const inv = ws.invitations.get(c.req.param('id'));\n if (!inv) throw notFound('Invitation');\n ws.invitations.delete(inv.id);\n return c.body(null, 204);\n });\n}\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatAuthFactor, formatAuthChallenge, expiresIn, isExpired, generateCode } from '../helpers.js';
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
5
|
+
export function legacyMfaRoutes(ctx) {
|
|
6
|
+
const { app, store } = ctx;
|
|
7
|
+
const ws = getWorkOSStore(store);
|
|
8
|
+
// Enroll factor (legacy path — not tied to user management users)
|
|
9
|
+
app.post('/auth/factors/enroll', async (c) => {
|
|
10
|
+
const body = await parseJsonBody(c);
|
|
11
|
+
const type = body.type ?? 'totp';
|
|
12
|
+
const issuer = body.totp_issuer ?? 'WorkOS Emulator';
|
|
13
|
+
const totpUser = body.totp_user ?? 'legacy@emulator';
|
|
14
|
+
const secret = randomBytes(20).toString('hex').slice(0, 32).toUpperCase();
|
|
15
|
+
const uri = `otpauth://totp/${encodeURIComponent(issuer)}:${encodeURIComponent(totpUser)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;
|
|
16
|
+
const factor = ws.authFactors.insert({
|
|
17
|
+
object: 'authentication_factor',
|
|
18
|
+
user_id: 'legacy',
|
|
19
|
+
type: type,
|
|
20
|
+
totp: { issuer, user: totpUser, uri },
|
|
21
|
+
});
|
|
22
|
+
return c.json(formatAuthFactor(factor), 201);
|
|
23
|
+
});
|
|
24
|
+
// Get factor
|
|
25
|
+
app.get('/auth/factors/:id', (c) => {
|
|
26
|
+
const factor = ws.authFactors.get(c.req.param('id'));
|
|
27
|
+
if (!factor)
|
|
28
|
+
throw notFound('AuthenticationFactor');
|
|
29
|
+
return c.json(formatAuthFactor(factor));
|
|
30
|
+
});
|
|
31
|
+
// Delete factor
|
|
32
|
+
app.delete('/auth/factors/:id', (c) => {
|
|
33
|
+
const factor = ws.authFactors.get(c.req.param('id'));
|
|
34
|
+
if (!factor)
|
|
35
|
+
throw notFound('AuthenticationFactor');
|
|
36
|
+
ws.authFactors.delete(factor.id);
|
|
37
|
+
return c.body(null, 204);
|
|
38
|
+
});
|
|
39
|
+
// Create challenge
|
|
40
|
+
app.post('/auth/factors/:id/challenge', async (c) => {
|
|
41
|
+
const factor = ws.authFactors.get(c.req.param('id'));
|
|
42
|
+
if (!factor)
|
|
43
|
+
throw notFound('AuthenticationFactor');
|
|
44
|
+
const code = generateCode();
|
|
45
|
+
const challenge = ws.authChallenges.insert({
|
|
46
|
+
object: 'authentication_challenge',
|
|
47
|
+
user_id: factor.user_id,
|
|
48
|
+
factor_id: factor.id,
|
|
49
|
+
expires_at: expiresIn(10),
|
|
50
|
+
code,
|
|
51
|
+
});
|
|
52
|
+
return c.json(formatAuthChallenge(challenge), 201);
|
|
53
|
+
});
|
|
54
|
+
// Verify challenge
|
|
55
|
+
app.post('/auth/challenges/:id/verify', async (c) => {
|
|
56
|
+
const challenge = ws.authChallenges.get(c.req.param('id'));
|
|
57
|
+
if (!challenge)
|
|
58
|
+
throw notFound('AuthenticationChallenge');
|
|
59
|
+
if (isExpired(challenge.expires_at)) {
|
|
60
|
+
ws.authChallenges.delete(challenge.id);
|
|
61
|
+
throw new WorkOSApiError(400, 'Challenge has expired', 'expired_challenge');
|
|
62
|
+
}
|
|
63
|
+
const body = await parseJsonBody(c);
|
|
64
|
+
const code = body.code;
|
|
65
|
+
if (!code) {
|
|
66
|
+
throw new WorkOSApiError(400, 'code is required', 'invalid_request');
|
|
67
|
+
}
|
|
68
|
+
if (challenge.code && code !== challenge.code) {
|
|
69
|
+
throw new WorkOSApiError(400, 'Invalid one-time code', 'invalid_one_time_code');
|
|
70
|
+
}
|
|
71
|
+
ws.authChallenges.delete(challenge.id);
|
|
72
|
+
return c.json({ challenge: formatAuthChallenge(challenge), valid: true });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=legacy-mfa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-mfa.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/legacy-mfa.ts"],"names":[],"mappings":"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","sourcesContent":["import { type RouteContext, notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatAuthFactor, formatAuthChallenge, expiresIn, isExpired, generateCode } from '../helpers.js';\nimport { randomBytes } from 'node:crypto';\n\nexport function legacyMfaRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n // Enroll factor (legacy path — not tied to user management users)\n app.post('/auth/factors/enroll', async (c) => {\n const body = await parseJsonBody(c);\n const type = (body.type as string) ?? 'totp';\n const issuer = (body.totp_issuer as string) ?? 'WorkOS Emulator';\n const totpUser = (body.totp_user as string) ?? 'legacy@emulator';\n const secret = randomBytes(20).toString('hex').slice(0, 32).toUpperCase();\n const uri = `otpauth://totp/${encodeURIComponent(issuer)}:${encodeURIComponent(totpUser)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;\n\n const factor = ws.authFactors.insert({\n object: 'authentication_factor',\n user_id: 'legacy',\n type: type as 'totp',\n totp: { issuer, user: totpUser, uri },\n });\n\n return c.json(formatAuthFactor(factor), 201);\n });\n\n // Get factor\n app.get('/auth/factors/:id', (c) => {\n const factor = ws.authFactors.get(c.req.param('id'));\n if (!factor) throw notFound('AuthenticationFactor');\n return c.json(formatAuthFactor(factor));\n });\n\n // Delete factor\n app.delete('/auth/factors/:id', (c) => {\n const factor = ws.authFactors.get(c.req.param('id'));\n if (!factor) throw notFound('AuthenticationFactor');\n ws.authFactors.delete(factor.id);\n return c.body(null, 204);\n });\n\n // Create challenge\n app.post('/auth/factors/:id/challenge', async (c) => {\n const factor = ws.authFactors.get(c.req.param('id'));\n if (!factor) throw notFound('AuthenticationFactor');\n\n const code = generateCode();\n const challenge = ws.authChallenges.insert({\n object: 'authentication_challenge',\n user_id: factor.user_id,\n factor_id: factor.id,\n expires_at: expiresIn(10),\n code,\n });\n\n return c.json(formatAuthChallenge(challenge), 201);\n });\n\n // Verify challenge\n app.post('/auth/challenges/:id/verify', async (c) => {\n const challenge = ws.authChallenges.get(c.req.param('id'));\n if (!challenge) throw notFound('AuthenticationChallenge');\n\n if (isExpired(challenge.expires_at)) {\n ws.authChallenges.delete(challenge.id);\n throw new WorkOSApiError(400, 'Challenge has expired', 'expired_challenge');\n }\n\n const body = await parseJsonBody(c);\n const code = body.code as string;\n if (!code) {\n throw new WorkOSApiError(400, 'code is required', 'invalid_request');\n }\n if (challenge.code && code !== challenge.code) {\n throw new WorkOSApiError(400, 'Invalid one-time code', 'invalid_one_time_code');\n }\n\n ws.authChallenges.delete(challenge.id);\n return c.json({ challenge: formatAuthChallenge(challenge), valid: true });\n });\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';
|
|
2
|
+
import { getWorkOSStore } from '../store.js';
|
|
3
|
+
import { formatMagicAuth, generateCode, expiresIn } from '../helpers.js';
|
|
4
|
+
export function magicAuthRoutes(ctx) {
|
|
5
|
+
const { app, store } = ctx;
|
|
6
|
+
const ws = getWorkOSStore(store);
|
|
7
|
+
app.get('/user_management/magic_auth/:id', (c) => {
|
|
8
|
+
const ma = ws.magicAuths.get(c.req.param('id'));
|
|
9
|
+
if (!ma)
|
|
10
|
+
throw notFound('Magic Auth');
|
|
11
|
+
return c.json(formatMagicAuth(ma));
|
|
12
|
+
});
|
|
13
|
+
app.post('/user_management/magic_auth', async (c) => {
|
|
14
|
+
const body = await parseJsonBody(c);
|
|
15
|
+
const email = body.email;
|
|
16
|
+
if (!email) {
|
|
17
|
+
throw new WorkOSApiError(400, 'email is required', 'invalid_request');
|
|
18
|
+
}
|
|
19
|
+
const user = ws.users.findOneBy('email', email);
|
|
20
|
+
if (!user)
|
|
21
|
+
throw notFound('User');
|
|
22
|
+
const ma = ws.magicAuths.insert({
|
|
23
|
+
object: 'magic_auth',
|
|
24
|
+
user_id: user.id,
|
|
25
|
+
email: user.email,
|
|
26
|
+
code: generateCode(),
|
|
27
|
+
expires_at: expiresIn(10),
|
|
28
|
+
});
|
|
29
|
+
return c.json(formatMagicAuth(ma), 201);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=magic-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magic-auth.js","sourceRoot":"","sources":["../../../../src/emulate/workos/routes/magic-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,UAAU,eAAe,CAAC,GAAiB;IAC/C,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;IAC3B,MAAM,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAEjC,GAAG,CAAC,GAAG,CAAC,iCAAiC,EAAE,CAAC,CAAC,EAAE,EAAE;QAC/C,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,EAAE;YAAE,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;QACtC,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAClD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAA2B,CAAC;QAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,cAAc,CAAC,GAAG,EAAE,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI;YAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAC9B,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,IAAI,CAAC,EAAE;YAChB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,YAAY,EAAE;YACpB,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC;SAC1B,CAAC,CAAC;QAEH,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { type RouteContext, notFound, parseJsonBody, WorkOSApiError } from '../../core/index.js';\nimport { getWorkOSStore } from '../store.js';\nimport { formatMagicAuth, generateCode, expiresIn } from '../helpers.js';\n\nexport function magicAuthRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ws = getWorkOSStore(store);\n\n app.get('/user_management/magic_auth/:id', (c) => {\n const ma = ws.magicAuths.get(c.req.param('id'));\n if (!ma) throw notFound('Magic Auth');\n return c.json(formatMagicAuth(ma));\n });\n\n app.post('/user_management/magic_auth', async (c) => {\n const body = await parseJsonBody(c);\n const email = body.email as string | undefined;\n if (!email) {\n throw new WorkOSApiError(400, 'email is required', 'invalid_request');\n }\n\n const user = ws.users.findOneBy('email', email);\n if (!user) throw notFound('User');\n\n const ma = ws.magicAuths.insert({\n object: 'magic_auth',\n user_id: user.id,\n email: user.email,\n code: generateCode(),\n expires_at: expiresIn(10),\n });\n\n return c.json(formatMagicAuth(ma), 201);\n });\n}\n"]}
|