@inai-dev/hono 1.0.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/dist/api-routes.cjs +175 -0
- package/dist/api-routes.cjs.map +1 -0
- package/dist/api-routes.d.cts +7 -0
- package/dist/api-routes.d.ts +7 -0
- package/dist/api-routes.js +155 -0
- package/dist/api-routes.js.map +1 -0
- package/dist/index.cjs +280 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +251 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware-CH4i5x6z.d.cts +22 -0
- package/dist/middleware-CH4i5x6z.d.ts +22 -0
- package/dist/middleware.cjs +172 -0
- package/dist/middleware.cjs.map +1 -0
- package/dist/middleware.d.cts +3 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.js +151 -0
- package/dist/middleware.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/api-routes.ts
|
|
21
|
+
var api_routes_exports = {};
|
|
22
|
+
__export(api_routes_exports, {
|
|
23
|
+
createAuthRoutes: () => createAuthRoutes
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(api_routes_exports);
|
|
26
|
+
var import_hono = require("hono");
|
|
27
|
+
var import_backend = require("@inai-dev/backend");
|
|
28
|
+
|
|
29
|
+
// src/helpers.ts
|
|
30
|
+
var import_cookie = require("hono/cookie");
|
|
31
|
+
var import_shared = require("@inai-dev/shared");
|
|
32
|
+
function getRefreshTokenFromContext(c) {
|
|
33
|
+
return (0, import_cookie.getCookie)(c, import_shared.COOKIE_REFRESH_TOKEN) ?? null;
|
|
34
|
+
}
|
|
35
|
+
function setAuthCookies(c, tokens, user) {
|
|
36
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
37
|
+
const claims = (0, import_shared.decodeJWTPayload)(tokens.access_token);
|
|
38
|
+
const expiresAt = claims ? new Date(claims.exp * 1e3).toISOString() : new Date(Date.now() + tokens.expires_in * 1e3).toISOString();
|
|
39
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_AUTH_TOKEN, tokens.access_token, {
|
|
40
|
+
httpOnly: true,
|
|
41
|
+
secure: isProduction,
|
|
42
|
+
sameSite: "Lax",
|
|
43
|
+
path: "/",
|
|
44
|
+
maxAge: tokens.expires_in
|
|
45
|
+
});
|
|
46
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, tokens.refresh_token, {
|
|
47
|
+
httpOnly: true,
|
|
48
|
+
secure: isProduction,
|
|
49
|
+
sameSite: "Strict",
|
|
50
|
+
path: "/api/auth",
|
|
51
|
+
maxAge: 7 * 24 * 60 * 60
|
|
52
|
+
});
|
|
53
|
+
(0, import_cookie.setCookie)(
|
|
54
|
+
c,
|
|
55
|
+
import_shared.COOKIE_AUTH_SESSION,
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
user,
|
|
58
|
+
expiresAt,
|
|
59
|
+
permissions: claims?.permissions ?? [],
|
|
60
|
+
orgId: claims?.org_id,
|
|
61
|
+
orgRole: claims?.org_role,
|
|
62
|
+
appId: claims?.app_id,
|
|
63
|
+
envId: claims?.env_id
|
|
64
|
+
}),
|
|
65
|
+
{
|
|
66
|
+
httpOnly: false,
|
|
67
|
+
secure: isProduction,
|
|
68
|
+
sameSite: "Lax",
|
|
69
|
+
path: "/",
|
|
70
|
+
maxAge: tokens.expires_in
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function clearAuthCookies(c) {
|
|
75
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_TOKEN, { path: "/" });
|
|
76
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, { path: "/api/auth" });
|
|
77
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_SESSION, { path: "/" });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/api-routes.ts
|
|
81
|
+
function createAuthRoutes(config = {}) {
|
|
82
|
+
const app = new import_hono.Hono();
|
|
83
|
+
const client = new import_backend.InAIAuthClient(config);
|
|
84
|
+
app.post("/login", async (c) => {
|
|
85
|
+
try {
|
|
86
|
+
const body = await c.req.json();
|
|
87
|
+
const result = await client.login({
|
|
88
|
+
email: body.email,
|
|
89
|
+
password: body.password
|
|
90
|
+
});
|
|
91
|
+
if (result.mfa_required) {
|
|
92
|
+
return c.json({ mfa_required: true, mfa_token: result.mfa_token });
|
|
93
|
+
}
|
|
94
|
+
const tokens = result;
|
|
95
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
96
|
+
setAuthCookies(c, tokens, user);
|
|
97
|
+
return c.json({ user });
|
|
98
|
+
} catch (err) {
|
|
99
|
+
const message = err instanceof Error ? err.message : "Login failed";
|
|
100
|
+
return c.json({ error: message }, 401);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
app.post("/register", async (c) => {
|
|
104
|
+
try {
|
|
105
|
+
const body = await c.req.json();
|
|
106
|
+
const result = await client.register({
|
|
107
|
+
email: body.email,
|
|
108
|
+
password: body.password,
|
|
109
|
+
firstName: body.firstName,
|
|
110
|
+
lastName: body.lastName
|
|
111
|
+
});
|
|
112
|
+
if (!result.access_token) {
|
|
113
|
+
return c.json({ needs_email_verification: true, user: result.user });
|
|
114
|
+
}
|
|
115
|
+
const tokens = result;
|
|
116
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
117
|
+
setAuthCookies(c, tokens, user);
|
|
118
|
+
return c.json({ user });
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const message = err instanceof Error ? err.message : "Registration failed";
|
|
121
|
+
return c.json({ error: message }, 400);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
app.post("/mfa-challenge", async (c) => {
|
|
125
|
+
try {
|
|
126
|
+
const body = await c.req.json();
|
|
127
|
+
const tokens = await client.mfaChallenge({
|
|
128
|
+
mfa_token: body.mfa_token,
|
|
129
|
+
code: body.code
|
|
130
|
+
});
|
|
131
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
132
|
+
setAuthCookies(c, tokens, user);
|
|
133
|
+
return c.json({ user });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
const message = err instanceof Error ? err.message : "MFA verification failed";
|
|
136
|
+
return c.json({ error: message }, 401);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
app.post("/refresh", async (c) => {
|
|
140
|
+
try {
|
|
141
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
142
|
+
if (!refreshToken) {
|
|
143
|
+
clearAuthCookies(c);
|
|
144
|
+
return c.json({ error: "No refresh token" }, 401);
|
|
145
|
+
}
|
|
146
|
+
const tokens = await client.refresh(refreshToken);
|
|
147
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
148
|
+
setAuthCookies(c, tokens, user);
|
|
149
|
+
return c.json({ user });
|
|
150
|
+
} catch {
|
|
151
|
+
clearAuthCookies(c);
|
|
152
|
+
return c.json({ error: "Refresh failed" }, 401);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
app.post("/logout", async (c) => {
|
|
156
|
+
try {
|
|
157
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
158
|
+
if (refreshToken) {
|
|
159
|
+
await client.logout(refreshToken).catch(() => {
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
clearAuthCookies(c);
|
|
163
|
+
return c.json({ success: true });
|
|
164
|
+
} catch {
|
|
165
|
+
clearAuthCookies(c);
|
|
166
|
+
return c.json({ success: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return app;
|
|
170
|
+
}
|
|
171
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
172
|
+
0 && (module.exports = {
|
|
173
|
+
createAuthRoutes
|
|
174
|
+
});
|
|
175
|
+
//# sourceMappingURL=api-routes.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api-routes.ts","../src/helpers.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { InAIAuthConfig, TokenPair, UserResource, LoginResult } from \"@inai-dev/types\";\nimport { InAIAuthClient } from \"@inai-dev/backend\";\nimport {\n setAuthCookies,\n clearAuthCookies,\n getRefreshTokenFromContext,\n} from \"./helpers\";\n\nexport function createAuthRoutes(config: InAIAuthConfig = {}) {\n const app = new Hono();\n const client = new InAIAuthClient(config);\n\n app.post(\"/login\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.login({\n email: body.email,\n password: body.password,\n }) as LoginResult & { user?: UserResource };\n\n if (result.mfa_required) {\n return c.json({ mfa_required: true, mfa_token: result.mfa_token });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Login failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/register\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.register({\n email: body.email,\n password: body.password,\n firstName: body.firstName,\n lastName: body.lastName,\n });\n\n if (!result.access_token) {\n return c.json({ needs_email_verification: true, user: result.user });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Registration failed\";\n return c.json({ error: message }, 400);\n }\n });\n\n app.post(\"/mfa-challenge\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const tokens = await client.mfaChallenge({\n mfa_token: body.mfa_token,\n code: body.code,\n });\n\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"MFA verification failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/refresh\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (!refreshToken) {\n clearAuthCookies(c);\n return c.json({ error: \"No refresh token\" }, 401);\n }\n\n const tokens = await client.refresh(refreshToken);\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch {\n clearAuthCookies(c);\n return c.json({ error: \"Refresh failed\" }, 401);\n }\n });\n\n app.post(\"/logout\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n if (refreshToken) {\n await client.logout(refreshToken).catch(() => {});\n }\n clearAuthCookies(c);\n return c.json({ success: true });\n } catch {\n clearAuthCookies(c);\n return c.json({ success: true });\n }\n });\n\n return app;\n}\n","import type { Context } from \"hono\";\nimport { getCookie, setCookie, deleteCookie } from \"hono/cookie\";\nimport type { AuthObject, TokenPair, UserResource, PlatformUserResource } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_REFRESH_TOKEN,\n COOKIE_AUTH_SESSION,\n decodeJWTPayload,\n} from \"@inai-dev/shared\";\n\nexport function getAuth(c: Context): AuthObject | null {\n return c.get(\"inaiAuth\") ?? null;\n}\n\nexport function getTokenFromContext(c: Context): string | null {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer \")) {\n return authHeader.slice(7);\n }\n\n return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;\n}\n\nexport function getRefreshTokenFromContext(c: Context): string | null {\n return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;\n}\n\nexport function setAuthCookies(\n c: Context,\n tokens: TokenPair,\n user: UserResource | PlatformUserResource,\n): void {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n const claims = decodeJWTPayload(tokens.access_token);\n const expiresAt = claims\n ? new Date(claims.exp * 1000).toISOString()\n : new Date(Date.now() + tokens.expires_in * 1000).toISOString();\n\n setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n });\n\n setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Strict\",\n path: \"/api/auth\",\n maxAge: 7 * 24 * 60 * 60,\n });\n\n setCookie(\n c,\n COOKIE_AUTH_SESSION,\n JSON.stringify({\n user,\n expiresAt,\n permissions: claims?.permissions ?? [],\n orgId: claims?.org_id,\n orgRole: claims?.org_role,\n appId: claims?.app_id,\n envId: claims?.env_id,\n }),\n {\n httpOnly: false,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n },\n );\n}\n\nexport function clearAuthCookies(c: Context): void {\n deleteCookie(c, COOKIE_AUTH_TOKEN, { path: \"/\" });\n deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: \"/api/auth\" });\n deleteCookie(c, COOKIE_AUTH_SESSION, { path: \"/\" });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as hono_types from 'hono/types';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { InAIAuthConfig } from '@inai-dev/types';
|
|
4
|
+
|
|
5
|
+
declare function createAuthRoutes(config?: InAIAuthConfig): Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
|
|
6
|
+
|
|
7
|
+
export { createAuthRoutes };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as hono_types from 'hono/types';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { InAIAuthConfig } from '@inai-dev/types';
|
|
4
|
+
|
|
5
|
+
declare function createAuthRoutes(config?: InAIAuthConfig): Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
|
|
6
|
+
|
|
7
|
+
export { createAuthRoutes };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/api-routes.ts
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { InAIAuthClient } from "@inai-dev/backend";
|
|
4
|
+
|
|
5
|
+
// src/helpers.ts
|
|
6
|
+
import { getCookie, setCookie, deleteCookie } from "hono/cookie";
|
|
7
|
+
import {
|
|
8
|
+
COOKIE_AUTH_TOKEN,
|
|
9
|
+
COOKIE_REFRESH_TOKEN,
|
|
10
|
+
COOKIE_AUTH_SESSION,
|
|
11
|
+
decodeJWTPayload
|
|
12
|
+
} from "@inai-dev/shared";
|
|
13
|
+
function getRefreshTokenFromContext(c) {
|
|
14
|
+
return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;
|
|
15
|
+
}
|
|
16
|
+
function setAuthCookies(c, tokens, user) {
|
|
17
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
18
|
+
const claims = decodeJWTPayload(tokens.access_token);
|
|
19
|
+
const expiresAt = claims ? new Date(claims.exp * 1e3).toISOString() : new Date(Date.now() + tokens.expires_in * 1e3).toISOString();
|
|
20
|
+
setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {
|
|
21
|
+
httpOnly: true,
|
|
22
|
+
secure: isProduction,
|
|
23
|
+
sameSite: "Lax",
|
|
24
|
+
path: "/",
|
|
25
|
+
maxAge: tokens.expires_in
|
|
26
|
+
});
|
|
27
|
+
setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {
|
|
28
|
+
httpOnly: true,
|
|
29
|
+
secure: isProduction,
|
|
30
|
+
sameSite: "Strict",
|
|
31
|
+
path: "/api/auth",
|
|
32
|
+
maxAge: 7 * 24 * 60 * 60
|
|
33
|
+
});
|
|
34
|
+
setCookie(
|
|
35
|
+
c,
|
|
36
|
+
COOKIE_AUTH_SESSION,
|
|
37
|
+
JSON.stringify({
|
|
38
|
+
user,
|
|
39
|
+
expiresAt,
|
|
40
|
+
permissions: claims?.permissions ?? [],
|
|
41
|
+
orgId: claims?.org_id,
|
|
42
|
+
orgRole: claims?.org_role,
|
|
43
|
+
appId: claims?.app_id,
|
|
44
|
+
envId: claims?.env_id
|
|
45
|
+
}),
|
|
46
|
+
{
|
|
47
|
+
httpOnly: false,
|
|
48
|
+
secure: isProduction,
|
|
49
|
+
sameSite: "Lax",
|
|
50
|
+
path: "/",
|
|
51
|
+
maxAge: tokens.expires_in
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function clearAuthCookies(c) {
|
|
56
|
+
deleteCookie(c, COOKIE_AUTH_TOKEN, { path: "/" });
|
|
57
|
+
deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: "/api/auth" });
|
|
58
|
+
deleteCookie(c, COOKIE_AUTH_SESSION, { path: "/" });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/api-routes.ts
|
|
62
|
+
function createAuthRoutes(config = {}) {
|
|
63
|
+
const app = new Hono();
|
|
64
|
+
const client = new InAIAuthClient(config);
|
|
65
|
+
app.post("/login", async (c) => {
|
|
66
|
+
try {
|
|
67
|
+
const body = await c.req.json();
|
|
68
|
+
const result = await client.login({
|
|
69
|
+
email: body.email,
|
|
70
|
+
password: body.password
|
|
71
|
+
});
|
|
72
|
+
if (result.mfa_required) {
|
|
73
|
+
return c.json({ mfa_required: true, mfa_token: result.mfa_token });
|
|
74
|
+
}
|
|
75
|
+
const tokens = result;
|
|
76
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
77
|
+
setAuthCookies(c, tokens, user);
|
|
78
|
+
return c.json({ user });
|
|
79
|
+
} catch (err) {
|
|
80
|
+
const message = err instanceof Error ? err.message : "Login failed";
|
|
81
|
+
return c.json({ error: message }, 401);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
app.post("/register", async (c) => {
|
|
85
|
+
try {
|
|
86
|
+
const body = await c.req.json();
|
|
87
|
+
const result = await client.register({
|
|
88
|
+
email: body.email,
|
|
89
|
+
password: body.password,
|
|
90
|
+
firstName: body.firstName,
|
|
91
|
+
lastName: body.lastName
|
|
92
|
+
});
|
|
93
|
+
if (!result.access_token) {
|
|
94
|
+
return c.json({ needs_email_verification: true, user: result.user });
|
|
95
|
+
}
|
|
96
|
+
const tokens = result;
|
|
97
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
98
|
+
setAuthCookies(c, tokens, user);
|
|
99
|
+
return c.json({ user });
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : "Registration failed";
|
|
102
|
+
return c.json({ error: message }, 400);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
app.post("/mfa-challenge", async (c) => {
|
|
106
|
+
try {
|
|
107
|
+
const body = await c.req.json();
|
|
108
|
+
const tokens = await client.mfaChallenge({
|
|
109
|
+
mfa_token: body.mfa_token,
|
|
110
|
+
code: body.code
|
|
111
|
+
});
|
|
112
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
113
|
+
setAuthCookies(c, tokens, user);
|
|
114
|
+
return c.json({ user });
|
|
115
|
+
} catch (err) {
|
|
116
|
+
const message = err instanceof Error ? err.message : "MFA verification failed";
|
|
117
|
+
return c.json({ error: message }, 401);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
app.post("/refresh", async (c) => {
|
|
121
|
+
try {
|
|
122
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
123
|
+
if (!refreshToken) {
|
|
124
|
+
clearAuthCookies(c);
|
|
125
|
+
return c.json({ error: "No refresh token" }, 401);
|
|
126
|
+
}
|
|
127
|
+
const tokens = await client.refresh(refreshToken);
|
|
128
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
129
|
+
setAuthCookies(c, tokens, user);
|
|
130
|
+
return c.json({ user });
|
|
131
|
+
} catch {
|
|
132
|
+
clearAuthCookies(c);
|
|
133
|
+
return c.json({ error: "Refresh failed" }, 401);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
app.post("/logout", async (c) => {
|
|
137
|
+
try {
|
|
138
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
139
|
+
if (refreshToken) {
|
|
140
|
+
await client.logout(refreshToken).catch(() => {
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
clearAuthCookies(c);
|
|
144
|
+
return c.json({ success: true });
|
|
145
|
+
} catch {
|
|
146
|
+
clearAuthCookies(c);
|
|
147
|
+
return c.json({ success: true });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return app;
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
createAuthRoutes
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=api-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api-routes.ts","../src/helpers.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { InAIAuthConfig, TokenPair, UserResource, LoginResult } from \"@inai-dev/types\";\nimport { InAIAuthClient } from \"@inai-dev/backend\";\nimport {\n setAuthCookies,\n clearAuthCookies,\n getRefreshTokenFromContext,\n} from \"./helpers\";\n\nexport function createAuthRoutes(config: InAIAuthConfig = {}) {\n const app = new Hono();\n const client = new InAIAuthClient(config);\n\n app.post(\"/login\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.login({\n email: body.email,\n password: body.password,\n }) as LoginResult & { user?: UserResource };\n\n if (result.mfa_required) {\n return c.json({ mfa_required: true, mfa_token: result.mfa_token });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Login failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/register\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.register({\n email: body.email,\n password: body.password,\n firstName: body.firstName,\n lastName: body.lastName,\n });\n\n if (!result.access_token) {\n return c.json({ needs_email_verification: true, user: result.user });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Registration failed\";\n return c.json({ error: message }, 400);\n }\n });\n\n app.post(\"/mfa-challenge\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const tokens = await client.mfaChallenge({\n mfa_token: body.mfa_token,\n code: body.code,\n });\n\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"MFA verification failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/refresh\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (!refreshToken) {\n clearAuthCookies(c);\n return c.json({ error: \"No refresh token\" }, 401);\n }\n\n const tokens = await client.refresh(refreshToken);\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch {\n clearAuthCookies(c);\n return c.json({ error: \"Refresh failed\" }, 401);\n }\n });\n\n app.post(\"/logout\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n if (refreshToken) {\n await client.logout(refreshToken).catch(() => {});\n }\n clearAuthCookies(c);\n return c.json({ success: true });\n } catch {\n clearAuthCookies(c);\n return c.json({ success: true });\n }\n });\n\n return app;\n}\n","import type { Context } from \"hono\";\nimport { getCookie, setCookie, deleteCookie } from \"hono/cookie\";\nimport type { AuthObject, TokenPair, UserResource, PlatformUserResource } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_REFRESH_TOKEN,\n COOKIE_AUTH_SESSION,\n decodeJWTPayload,\n} from \"@inai-dev/shared\";\n\nexport function getAuth(c: Context): AuthObject | null {\n return c.get(\"inaiAuth\") ?? null;\n}\n\nexport function getTokenFromContext(c: Context): string | null {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer \")) {\n return authHeader.slice(7);\n }\n\n return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;\n}\n\nexport function getRefreshTokenFromContext(c: Context): string | null {\n return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;\n}\n\nexport function setAuthCookies(\n c: Context,\n tokens: TokenPair,\n user: UserResource | PlatformUserResource,\n): void {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n const claims = decodeJWTPayload(tokens.access_token);\n const expiresAt = claims\n ? new Date(claims.exp * 1000).toISOString()\n : new Date(Date.now() + tokens.expires_in * 1000).toISOString();\n\n setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n });\n\n setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Strict\",\n path: \"/api/auth\",\n maxAge: 7 * 24 * 60 * 60,\n });\n\n setCookie(\n c,\n COOKIE_AUTH_SESSION,\n JSON.stringify({\n user,\n expiresAt,\n permissions: claims?.permissions ?? [],\n orgId: claims?.org_id,\n orgRole: claims?.org_role,\n appId: claims?.app_id,\n envId: claims?.env_id,\n }),\n {\n httpOnly: false,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n },\n );\n}\n\nexport function clearAuthCookies(c: Context): void {\n deleteCookie(c, COOKIE_AUTH_TOKEN, { path: \"/\" });\n deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: \"/api/auth\" });\n deleteCookie(c, COOKIE_AUTH_SESSION, { path: \"/\" });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
clearAuthCookies: () => clearAuthCookies,
|
|
24
|
+
createAuthRoutes: () => createAuthRoutes,
|
|
25
|
+
getAuth: () => getAuth,
|
|
26
|
+
getRefreshTokenFromContext: () => getRefreshTokenFromContext,
|
|
27
|
+
getTokenFromContext: () => getTokenFromContext,
|
|
28
|
+
inaiAuthMiddleware: () => inaiAuthMiddleware,
|
|
29
|
+
requireAuth: () => requireAuth,
|
|
30
|
+
setAuthCookies: () => setAuthCookies
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(src_exports);
|
|
33
|
+
|
|
34
|
+
// src/middleware.ts
|
|
35
|
+
var import_backend = require("@inai-dev/backend");
|
|
36
|
+
var import_shared2 = require("@inai-dev/shared");
|
|
37
|
+
|
|
38
|
+
// src/helpers.ts
|
|
39
|
+
var import_cookie = require("hono/cookie");
|
|
40
|
+
var import_shared = require("@inai-dev/shared");
|
|
41
|
+
function getAuth(c) {
|
|
42
|
+
return c.get("inaiAuth") ?? null;
|
|
43
|
+
}
|
|
44
|
+
function getTokenFromContext(c) {
|
|
45
|
+
const authHeader = c.req.header("Authorization");
|
|
46
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
47
|
+
return authHeader.slice(7);
|
|
48
|
+
}
|
|
49
|
+
return (0, import_cookie.getCookie)(c, import_shared.COOKIE_AUTH_TOKEN) ?? null;
|
|
50
|
+
}
|
|
51
|
+
function getRefreshTokenFromContext(c) {
|
|
52
|
+
return (0, import_cookie.getCookie)(c, import_shared.COOKIE_REFRESH_TOKEN) ?? null;
|
|
53
|
+
}
|
|
54
|
+
function setAuthCookies(c, tokens, user) {
|
|
55
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
56
|
+
const claims = (0, import_shared.decodeJWTPayload)(tokens.access_token);
|
|
57
|
+
const expiresAt = claims ? new Date(claims.exp * 1e3).toISOString() : new Date(Date.now() + tokens.expires_in * 1e3).toISOString();
|
|
58
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_AUTH_TOKEN, tokens.access_token, {
|
|
59
|
+
httpOnly: true,
|
|
60
|
+
secure: isProduction,
|
|
61
|
+
sameSite: "Lax",
|
|
62
|
+
path: "/",
|
|
63
|
+
maxAge: tokens.expires_in
|
|
64
|
+
});
|
|
65
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, tokens.refresh_token, {
|
|
66
|
+
httpOnly: true,
|
|
67
|
+
secure: isProduction,
|
|
68
|
+
sameSite: "Strict",
|
|
69
|
+
path: "/api/auth",
|
|
70
|
+
maxAge: 7 * 24 * 60 * 60
|
|
71
|
+
});
|
|
72
|
+
(0, import_cookie.setCookie)(
|
|
73
|
+
c,
|
|
74
|
+
import_shared.COOKIE_AUTH_SESSION,
|
|
75
|
+
JSON.stringify({
|
|
76
|
+
user,
|
|
77
|
+
expiresAt,
|
|
78
|
+
permissions: claims?.permissions ?? [],
|
|
79
|
+
orgId: claims?.org_id,
|
|
80
|
+
orgRole: claims?.org_role,
|
|
81
|
+
appId: claims?.app_id,
|
|
82
|
+
envId: claims?.env_id
|
|
83
|
+
}),
|
|
84
|
+
{
|
|
85
|
+
httpOnly: false,
|
|
86
|
+
secure: isProduction,
|
|
87
|
+
sameSite: "Lax",
|
|
88
|
+
path: "/",
|
|
89
|
+
maxAge: tokens.expires_in
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function clearAuthCookies(c) {
|
|
94
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_TOKEN, { path: "/" });
|
|
95
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, { path: "/api/auth" });
|
|
96
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_SESSION, { path: "/" });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/middleware.ts
|
|
100
|
+
function matchesRoute(pathname, patterns) {
|
|
101
|
+
return patterns.some((pattern) => {
|
|
102
|
+
if (pattern.endsWith("*")) {
|
|
103
|
+
return pathname.startsWith(pattern.slice(0, -1));
|
|
104
|
+
}
|
|
105
|
+
return pathname === pattern;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function isPublicRoute(path, publicRoutes) {
|
|
109
|
+
if (typeof publicRoutes === "function") return publicRoutes(path);
|
|
110
|
+
return matchesRoute(path, publicRoutes);
|
|
111
|
+
}
|
|
112
|
+
function inaiAuthMiddleware(config = {}) {
|
|
113
|
+
const {
|
|
114
|
+
authMode = "app",
|
|
115
|
+
publicRoutes = [],
|
|
116
|
+
onUnauthorized,
|
|
117
|
+
...authClientConfig
|
|
118
|
+
} = config;
|
|
119
|
+
const client = new import_backend.InAIAuthClient(authClientConfig);
|
|
120
|
+
const isPlatform = authMode === "platform";
|
|
121
|
+
const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
|
|
122
|
+
const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
|
|
123
|
+
return async function middleware(c, next) {
|
|
124
|
+
const path = new URL(c.req.url).pathname;
|
|
125
|
+
if (isPublicRoute(path, publicRoutes)) {
|
|
126
|
+
c.set("inaiAuth", null);
|
|
127
|
+
await next();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const token = getTokenFromContext(c);
|
|
131
|
+
if (!token || (0, import_shared2.isTokenExpired)(token)) {
|
|
132
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
133
|
+
if (refreshToken) {
|
|
134
|
+
try {
|
|
135
|
+
const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
|
|
136
|
+
const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
|
|
137
|
+
setAuthCookies(c, tokens, user);
|
|
138
|
+
const authObj2 = (0, import_backend.buildAuthObjectFromToken)(tokens.access_token);
|
|
139
|
+
c.set("inaiAuth", authObj2);
|
|
140
|
+
await next();
|
|
141
|
+
return;
|
|
142
|
+
} catch {
|
|
143
|
+
clearAuthCookies(c);
|
|
144
|
+
return handleUnauthorized(c);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return handleUnauthorized(c);
|
|
148
|
+
}
|
|
149
|
+
const authObj = (0, import_backend.buildAuthObjectFromToken)(token);
|
|
150
|
+
if (!authObj) {
|
|
151
|
+
return handleUnauthorized(c);
|
|
152
|
+
}
|
|
153
|
+
c.set("inaiAuth", authObj);
|
|
154
|
+
await next();
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function requireAuth(config = {}) {
|
|
158
|
+
return async function middleware(c, next) {
|
|
159
|
+
const auth = getAuth(c);
|
|
160
|
+
if (!auth?.userId) {
|
|
161
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
162
|
+
}
|
|
163
|
+
if (config.role || config.permission) {
|
|
164
|
+
const hasAccess = auth.has({
|
|
165
|
+
role: config.role,
|
|
166
|
+
permission: config.permission
|
|
167
|
+
});
|
|
168
|
+
if (!hasAccess) {
|
|
169
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
await next();
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/api-routes.ts
|
|
177
|
+
var import_hono = require("hono");
|
|
178
|
+
var import_backend2 = require("@inai-dev/backend");
|
|
179
|
+
function createAuthRoutes(config = {}) {
|
|
180
|
+
const app = new import_hono.Hono();
|
|
181
|
+
const client = new import_backend2.InAIAuthClient(config);
|
|
182
|
+
app.post("/login", async (c) => {
|
|
183
|
+
try {
|
|
184
|
+
const body = await c.req.json();
|
|
185
|
+
const result = await client.login({
|
|
186
|
+
email: body.email,
|
|
187
|
+
password: body.password
|
|
188
|
+
});
|
|
189
|
+
if (result.mfa_required) {
|
|
190
|
+
return c.json({ mfa_required: true, mfa_token: result.mfa_token });
|
|
191
|
+
}
|
|
192
|
+
const tokens = result;
|
|
193
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
194
|
+
setAuthCookies(c, tokens, user);
|
|
195
|
+
return c.json({ user });
|
|
196
|
+
} catch (err) {
|
|
197
|
+
const message = err instanceof Error ? err.message : "Login failed";
|
|
198
|
+
return c.json({ error: message }, 401);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
app.post("/register", async (c) => {
|
|
202
|
+
try {
|
|
203
|
+
const body = await c.req.json();
|
|
204
|
+
const result = await client.register({
|
|
205
|
+
email: body.email,
|
|
206
|
+
password: body.password,
|
|
207
|
+
firstName: body.firstName,
|
|
208
|
+
lastName: body.lastName
|
|
209
|
+
});
|
|
210
|
+
if (!result.access_token) {
|
|
211
|
+
return c.json({ needs_email_verification: true, user: result.user });
|
|
212
|
+
}
|
|
213
|
+
const tokens = result;
|
|
214
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
215
|
+
setAuthCookies(c, tokens, user);
|
|
216
|
+
return c.json({ user });
|
|
217
|
+
} catch (err) {
|
|
218
|
+
const message = err instanceof Error ? err.message : "Registration failed";
|
|
219
|
+
return c.json({ error: message }, 400);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
app.post("/mfa-challenge", async (c) => {
|
|
223
|
+
try {
|
|
224
|
+
const body = await c.req.json();
|
|
225
|
+
const tokens = await client.mfaChallenge({
|
|
226
|
+
mfa_token: body.mfa_token,
|
|
227
|
+
code: body.code
|
|
228
|
+
});
|
|
229
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
230
|
+
setAuthCookies(c, tokens, user);
|
|
231
|
+
return c.json({ user });
|
|
232
|
+
} catch (err) {
|
|
233
|
+
const message = err instanceof Error ? err.message : "MFA verification failed";
|
|
234
|
+
return c.json({ error: message }, 401);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
app.post("/refresh", async (c) => {
|
|
238
|
+
try {
|
|
239
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
240
|
+
if (!refreshToken) {
|
|
241
|
+
clearAuthCookies(c);
|
|
242
|
+
return c.json({ error: "No refresh token" }, 401);
|
|
243
|
+
}
|
|
244
|
+
const tokens = await client.refresh(refreshToken);
|
|
245
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
246
|
+
setAuthCookies(c, tokens, user);
|
|
247
|
+
return c.json({ user });
|
|
248
|
+
} catch {
|
|
249
|
+
clearAuthCookies(c);
|
|
250
|
+
return c.json({ error: "Refresh failed" }, 401);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
app.post("/logout", async (c) => {
|
|
254
|
+
try {
|
|
255
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
256
|
+
if (refreshToken) {
|
|
257
|
+
await client.logout(refreshToken).catch(() => {
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
clearAuthCookies(c);
|
|
261
|
+
return c.json({ success: true });
|
|
262
|
+
} catch {
|
|
263
|
+
clearAuthCookies(c);
|
|
264
|
+
return c.json({ success: true });
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return app;
|
|
268
|
+
}
|
|
269
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
270
|
+
0 && (module.exports = {
|
|
271
|
+
clearAuthCookies,
|
|
272
|
+
createAuthRoutes,
|
|
273
|
+
getAuth,
|
|
274
|
+
getRefreshTokenFromContext,
|
|
275
|
+
getTokenFromContext,
|
|
276
|
+
inaiAuthMiddleware,
|
|
277
|
+
requireAuth,
|
|
278
|
+
setAuthCookies
|
|
279
|
+
});
|
|
280
|
+
//# sourceMappingURL=index.cjs.map
|