@terreno/api 0.0.18 → 0.2.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 +73 -3
- package/dist/api.d.ts +96 -3
- package/dist/api.js +159 -11
- package/dist/api.test.js +906 -2
- package/dist/auth.js +3 -1
- package/dist/betterAuth.d.ts +91 -0
- package/dist/betterAuth.js +8 -0
- package/dist/betterAuth.test.d.ts +1 -0
- package/dist/betterAuth.test.js +181 -0
- package/dist/betterAuthApp.d.ts +22 -0
- package/dist/betterAuthApp.js +38 -0
- package/dist/betterAuthApp.test.d.ts +1 -0
- package/dist/betterAuthApp.test.js +242 -0
- package/dist/betterAuthSetup.d.ts +60 -0
- package/dist/betterAuthSetup.js +278 -0
- package/dist/betterAuthSetup.test.d.ts +1 -0
- package/dist/betterAuthSetup.test.js +684 -0
- package/dist/errors.js +14 -11
- package/dist/example.js +7 -7
- package/dist/expressServer.js +2 -2
- package/dist/githubAuth.test.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/openApi.test.js +8 -5
- package/dist/openApiBuilder.d.ts +69 -1
- package/dist/openApiBuilder.js +109 -5
- package/dist/openApiValidator.d.ts +296 -0
- package/dist/openApiValidator.js +698 -0
- package/dist/openApiValidator.test.d.ts +1 -0
- package/dist/openApiValidator.test.js +346 -0
- package/dist/plugins.test.js +3 -3
- package/dist/terrenoApp.d.ts +189 -0
- package/dist/terrenoApp.js +352 -0
- package/dist/terrenoApp.test.d.ts +1 -0
- package/dist/terrenoApp.test.js +264 -0
- package/dist/terrenoPlugin.d.ts +38 -0
- package/dist/terrenoPlugin.js +2 -0
- package/dist/tests.js +34 -24
- package/package.json +8 -2
- package/src/__snapshots__/openApi.test.ts.snap +399 -0
- package/src/__snapshots__/openApiBuilder.test.ts.snap +108 -0
- package/src/api.test.ts +743 -2
- package/src/api.ts +270 -6
- package/src/auth.ts +3 -1
- package/src/betterAuth.test.ts +160 -0
- package/src/betterAuth.ts +104 -0
- package/src/betterAuthApp.test.ts +114 -0
- package/src/betterAuthApp.ts +60 -0
- package/src/betterAuthSetup.test.ts +485 -0
- package/src/betterAuthSetup.ts +251 -0
- package/src/errors.ts +14 -11
- package/src/example.ts +7 -7
- package/src/expressServer.ts +4 -5
- package/src/githubAuth.test.ts +3 -3
- package/src/index.ts +6 -0
- package/src/openApi.test.ts +8 -5
- package/src/openApiBuilder.ts +188 -15
- package/src/openApiValidator.test.ts +241 -0
- package/src/openApiValidator.ts +860 -0
- package/src/plugins.test.ts +3 -3
- package/src/terrenoApp.test.ts +201 -0
- package/src/terrenoApp.ts +347 -0
- package/src/terrenoPlugin.ts +39 -0
- package/src/tests.ts +34 -24
- package/.cursorrules +0 -107
- package/.windsurfrules +0 -107
- package/AGENTS.md +0 -313
- package/dist/response.d.ts +0 -0
- package/dist/response.js +0 -1
- package/index.ts +0 -1
- package/src/response.ts +0 -0
package/dist/auth.js
CHANGED
|
@@ -377,7 +377,9 @@ function addAuthRoutes(app, userModel, authOptions) {
|
|
|
377
377
|
logger_1.logger.warn("Invalid login: ".concat(info));
|
|
378
378
|
return [2 /*return*/, res.status(401).json({ message: info === null || info === void 0 ? void 0 : info.message })];
|
|
379
379
|
}
|
|
380
|
-
|
|
380
|
+
if (process.env.NODE_ENV !== "test") {
|
|
381
|
+
logger_1.logger.info("User logged in: ".concat(user._id, ", type: ").concat(user.type || "N/A"));
|
|
382
|
+
}
|
|
381
383
|
return [4 /*yield*/, (0, exports.generateTokens)(user, authOptions)];
|
|
382
384
|
case 1:
|
|
383
385
|
tokens = _a.sent();
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Better Auth types and configuration interfaces for @terreno/api.
|
|
3
|
+
*
|
|
4
|
+
* These types support optional Better Auth integration alongside the existing
|
|
5
|
+
* JWT/Passport authentication system.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* OAuth provider configuration for Better Auth.
|
|
9
|
+
*/
|
|
10
|
+
export interface BetterAuthOAuthProvider {
|
|
11
|
+
clientId: string;
|
|
12
|
+
clientSecret: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Configuration options for Better Auth integration.
|
|
16
|
+
*/
|
|
17
|
+
export interface BetterAuthConfig {
|
|
18
|
+
/**
|
|
19
|
+
* Whether Better Auth is enabled for this server.
|
|
20
|
+
*/
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Google OAuth provider configuration.
|
|
24
|
+
*/
|
|
25
|
+
googleOAuth?: BetterAuthOAuthProvider;
|
|
26
|
+
/**
|
|
27
|
+
* Apple OAuth provider configuration.
|
|
28
|
+
*/
|
|
29
|
+
appleOAuth?: BetterAuthOAuthProvider;
|
|
30
|
+
/**
|
|
31
|
+
* GitHub OAuth provider configuration.
|
|
32
|
+
*/
|
|
33
|
+
githubOAuth?: BetterAuthOAuthProvider;
|
|
34
|
+
/**
|
|
35
|
+
* Trusted origins for CORS and redirect validation.
|
|
36
|
+
* Include your app's deep link schemes (e.g., "terreno://", "exp://").
|
|
37
|
+
*/
|
|
38
|
+
trustedOrigins?: string[];
|
|
39
|
+
/**
|
|
40
|
+
* Base path for Better Auth routes.
|
|
41
|
+
* @default "/api/auth"
|
|
42
|
+
*/
|
|
43
|
+
basePath?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Secret key for Better Auth session encryption.
|
|
46
|
+
* If not provided, falls back to BETTER_AUTH_SECRET environment variable.
|
|
47
|
+
*/
|
|
48
|
+
secret?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Base URL for the auth server.
|
|
51
|
+
* If not provided, falls back to BETTER_AUTH_URL environment variable.
|
|
52
|
+
*/
|
|
53
|
+
baseURL?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Auth provider selection for setupServer.
|
|
57
|
+
* - "jwt": Traditional JWT/Passport authentication (default)
|
|
58
|
+
* - "better-auth": Better Auth with OAuth support
|
|
59
|
+
*/
|
|
60
|
+
export type AuthProvider = "jwt" | "better-auth";
|
|
61
|
+
/**
|
|
62
|
+
* User data from Better Auth session.
|
|
63
|
+
*/
|
|
64
|
+
export interface BetterAuthUser {
|
|
65
|
+
id: string;
|
|
66
|
+
email: string;
|
|
67
|
+
name: string | null;
|
|
68
|
+
image: string | null;
|
|
69
|
+
emailVerified: boolean;
|
|
70
|
+
createdAt: Date;
|
|
71
|
+
updatedAt: Date;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Session data from Better Auth.
|
|
75
|
+
*/
|
|
76
|
+
export interface BetterAuthSession {
|
|
77
|
+
id: string;
|
|
78
|
+
userId: string;
|
|
79
|
+
expiresAt: Date;
|
|
80
|
+
ipAddress: string | null;
|
|
81
|
+
userAgent: string | null;
|
|
82
|
+
createdAt: Date;
|
|
83
|
+
updatedAt: Date;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Combined session and user data from Better Auth.
|
|
87
|
+
*/
|
|
88
|
+
export interface BetterAuthSessionData {
|
|
89
|
+
session: BetterAuthSession;
|
|
90
|
+
user: BetterAuthUser;
|
|
91
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Better Auth types and configuration interfaces for @terreno/api.
|
|
4
|
+
*
|
|
5
|
+
* These types support optional Better Auth integration alongside the existing
|
|
6
|
+
* JWT/Passport authentication system.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
var bun_test_1 = require("bun:test");
|
|
40
|
+
(0, bun_test_1.describe)("Better Auth types", function () {
|
|
41
|
+
(0, bun_test_1.it)("defines BetterAuthOAuthProvider interface correctly", function () {
|
|
42
|
+
var provider = {
|
|
43
|
+
clientId: "test-client-id",
|
|
44
|
+
clientSecret: "test-client-secret",
|
|
45
|
+
};
|
|
46
|
+
(0, bun_test_1.expect)(provider.clientId).toBe("test-client-id");
|
|
47
|
+
(0, bun_test_1.expect)(provider.clientSecret).toBe("test-client-secret");
|
|
48
|
+
});
|
|
49
|
+
(0, bun_test_1.it)("defines BetterAuthConfig interface correctly", function () {
|
|
50
|
+
var _a, _b;
|
|
51
|
+
var config = {
|
|
52
|
+
basePath: "/api/auth",
|
|
53
|
+
baseURL: "http://localhost:3000",
|
|
54
|
+
enabled: true,
|
|
55
|
+
githubOAuth: {
|
|
56
|
+
clientId: "github-client-id",
|
|
57
|
+
clientSecret: "github-client-secret",
|
|
58
|
+
},
|
|
59
|
+
googleOAuth: {
|
|
60
|
+
clientId: "google-client-id",
|
|
61
|
+
clientSecret: "google-client-secret",
|
|
62
|
+
},
|
|
63
|
+
secret: "test-secret",
|
|
64
|
+
trustedOrigins: ["terreno://", "exp://"],
|
|
65
|
+
};
|
|
66
|
+
(0, bun_test_1.expect)(config.enabled).toBe(true);
|
|
67
|
+
(0, bun_test_1.expect)((_a = config.googleOAuth) === null || _a === void 0 ? void 0 : _a.clientId).toBe("google-client-id");
|
|
68
|
+
(0, bun_test_1.expect)((_b = config.githubOAuth) === null || _b === void 0 ? void 0 : _b.clientId).toBe("github-client-id");
|
|
69
|
+
(0, bun_test_1.expect)(config.trustedOrigins).toContain("terreno://");
|
|
70
|
+
(0, bun_test_1.expect)(config.basePath).toBe("/api/auth");
|
|
71
|
+
});
|
|
72
|
+
(0, bun_test_1.it)("allows minimal BetterAuthConfig", function () {
|
|
73
|
+
var minimalConfig = {
|
|
74
|
+
enabled: false,
|
|
75
|
+
};
|
|
76
|
+
(0, bun_test_1.expect)(minimalConfig.enabled).toBe(false);
|
|
77
|
+
(0, bun_test_1.expect)(minimalConfig.googleOAuth).toBeUndefined();
|
|
78
|
+
(0, bun_test_1.expect)(minimalConfig.basePath).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
(0, bun_test_1.it)("defines AuthProvider type correctly", function () {
|
|
81
|
+
var jwtProvider = "jwt";
|
|
82
|
+
var betterAuthProvider = "better-auth";
|
|
83
|
+
(0, bun_test_1.expect)(jwtProvider).toBe("jwt");
|
|
84
|
+
(0, bun_test_1.expect)(betterAuthProvider).toBe("better-auth");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
(0, bun_test_1.describe)("Better Auth setup", function () {
|
|
88
|
+
(0, bun_test_1.it)("syncBetterAuthUser creates a new user when not found", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
89
|
+
var betterAuthUser;
|
|
90
|
+
return __generator(this, function (_a) {
|
|
91
|
+
betterAuthUser = {
|
|
92
|
+
createdAt: new Date(),
|
|
93
|
+
email: "test@example.com",
|
|
94
|
+
emailVerified: true,
|
|
95
|
+
id: "ba-user-123",
|
|
96
|
+
image: null,
|
|
97
|
+
name: "Test User",
|
|
98
|
+
updatedAt: new Date(),
|
|
99
|
+
};
|
|
100
|
+
(0, bun_test_1.expect)(betterAuthUser.id).toBe("ba-user-123");
|
|
101
|
+
(0, bun_test_1.expect)(betterAuthUser.email).toBe("test@example.com");
|
|
102
|
+
(0, bun_test_1.expect)(betterAuthUser.name).toBe("Test User");
|
|
103
|
+
return [2 /*return*/];
|
|
104
|
+
});
|
|
105
|
+
}); });
|
|
106
|
+
(0, bun_test_1.it)("BetterAuthSession has correct structure", function () {
|
|
107
|
+
var session = {
|
|
108
|
+
createdAt: new Date(),
|
|
109
|
+
expiresAt: new Date(Date.now() + 3600000),
|
|
110
|
+
id: "session-123",
|
|
111
|
+
ipAddress: "127.0.0.1",
|
|
112
|
+
updatedAt: new Date(),
|
|
113
|
+
userAgent: "Mozilla/5.0",
|
|
114
|
+
userId: "user-456",
|
|
115
|
+
};
|
|
116
|
+
(0, bun_test_1.expect)(session.id).toBe("session-123");
|
|
117
|
+
(0, bun_test_1.expect)(session.userId).toBe("user-456");
|
|
118
|
+
(0, bun_test_1.expect)(session.expiresAt.getTime()).toBeGreaterThan(Date.now());
|
|
119
|
+
});
|
|
120
|
+
(0, bun_test_1.it)("BetterAuthSessionData combines session and user", function () {
|
|
121
|
+
var sessionData = {
|
|
122
|
+
session: {
|
|
123
|
+
createdAt: new Date(),
|
|
124
|
+
expiresAt: new Date(),
|
|
125
|
+
id: "session-123",
|
|
126
|
+
ipAddress: null,
|
|
127
|
+
updatedAt: new Date(),
|
|
128
|
+
userAgent: null,
|
|
129
|
+
userId: "user-456",
|
|
130
|
+
},
|
|
131
|
+
user: {
|
|
132
|
+
createdAt: new Date(),
|
|
133
|
+
email: "test@example.com",
|
|
134
|
+
emailVerified: false,
|
|
135
|
+
id: "user-456",
|
|
136
|
+
image: null,
|
|
137
|
+
name: "Test",
|
|
138
|
+
updatedAt: new Date(),
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
(0, bun_test_1.expect)(sessionData.session.userId).toBe(sessionData.user.id);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
(0, bun_test_1.describe)("Better Auth config validation", function () {
|
|
145
|
+
(0, bun_test_1.it)("basePath defaults to /api/auth when not specified", function () {
|
|
146
|
+
var _a;
|
|
147
|
+
var config = {
|
|
148
|
+
enabled: true,
|
|
149
|
+
};
|
|
150
|
+
var basePath = (_a = config.basePath) !== null && _a !== void 0 ? _a : "/api/auth";
|
|
151
|
+
(0, bun_test_1.expect)(basePath).toBe("/api/auth");
|
|
152
|
+
});
|
|
153
|
+
(0, bun_test_1.it)("trustedOrigins defaults to empty array when not specified", function () {
|
|
154
|
+
var _a;
|
|
155
|
+
var config = {
|
|
156
|
+
enabled: true,
|
|
157
|
+
};
|
|
158
|
+
var trustedOrigins = (_a = config.trustedOrigins) !== null && _a !== void 0 ? _a : [];
|
|
159
|
+
(0, bun_test_1.expect)(trustedOrigins).toEqual([]);
|
|
160
|
+
});
|
|
161
|
+
(0, bun_test_1.it)("supports multiple OAuth providers simultaneously", function () {
|
|
162
|
+
var config = {
|
|
163
|
+
appleOAuth: {
|
|
164
|
+
clientId: "apple-id",
|
|
165
|
+
clientSecret: "apple-secret",
|
|
166
|
+
},
|
|
167
|
+
enabled: true,
|
|
168
|
+
githubOAuth: {
|
|
169
|
+
clientId: "github-id",
|
|
170
|
+
clientSecret: "github-secret",
|
|
171
|
+
},
|
|
172
|
+
googleOAuth: {
|
|
173
|
+
clientId: "google-id",
|
|
174
|
+
clientSecret: "google-secret",
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
(0, bun_test_1.expect)(config.googleOAuth).toBeDefined();
|
|
178
|
+
(0, bun_test_1.expect)(config.githubOAuth).toBeDefined();
|
|
179
|
+
(0, bun_test_1.expect)(config.appleOAuth).toBeDefined();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BetterAuthApp plugin for @terreno/api.
|
|
3
|
+
*
|
|
4
|
+
* Registers Better Auth as a TerrenoPlugin, mounting routes, session middleware,
|
|
5
|
+
* and user sync on an existing Express application.
|
|
6
|
+
*/
|
|
7
|
+
import type express from "express";
|
|
8
|
+
import type { UserModel } from "./auth";
|
|
9
|
+
import type { BetterAuthConfig } from "./betterAuth";
|
|
10
|
+
import { type BetterAuthInstance } from "./betterAuthSetup";
|
|
11
|
+
import type { TerrenoPlugin } from "./terrenoPlugin";
|
|
12
|
+
export interface BetterAuthAppOptions {
|
|
13
|
+
config: BetterAuthConfig;
|
|
14
|
+
userModel?: UserModel;
|
|
15
|
+
}
|
|
16
|
+
export declare class BetterAuthApp implements TerrenoPlugin {
|
|
17
|
+
private auth;
|
|
18
|
+
private options;
|
|
19
|
+
constructor(options: BetterAuthAppOptions);
|
|
20
|
+
register(app: express.Application): void;
|
|
21
|
+
getAuth(): BetterAuthInstance | undefined;
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BetterAuthApp plugin for @terreno/api.
|
|
4
|
+
*
|
|
5
|
+
* Registers Better Auth as a TerrenoPlugin, mounting routes, session middleware,
|
|
6
|
+
* and user sync on an existing Express application.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.BetterAuthApp = void 0;
|
|
10
|
+
var betterAuthSetup_1 = require("./betterAuthSetup");
|
|
11
|
+
var logger_1 = require("./logger");
|
|
12
|
+
var BetterAuthApp = /** @class */ (function () {
|
|
13
|
+
function BetterAuthApp(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
BetterAuthApp.prototype.register = function (app) {
|
|
17
|
+
var _a;
|
|
18
|
+
var _b = this.options, config = _b.config, userModel = _b.userModel;
|
|
19
|
+
var mongoClient = (0, betterAuthSetup_1.getMongoClientFromMongoose)();
|
|
20
|
+
this.auth = (0, betterAuthSetup_1.createBetterAuth)({
|
|
21
|
+
config: config,
|
|
22
|
+
mongoClient: mongoClient,
|
|
23
|
+
userModel: userModel,
|
|
24
|
+
});
|
|
25
|
+
var basePath = (_a = config.basePath) !== null && _a !== void 0 ? _a : "/api/auth";
|
|
26
|
+
(0, betterAuthSetup_1.mountBetterAuthRoutes)(app, this.auth, basePath);
|
|
27
|
+
app.use((0, betterAuthSetup_1.createBetterAuthSessionMiddleware)(this.auth, userModel));
|
|
28
|
+
if (userModel) {
|
|
29
|
+
(0, betterAuthSetup_1.setupBetterAuthUserSync)(this.auth, userModel);
|
|
30
|
+
}
|
|
31
|
+
logger_1.logger.info("Better Auth initialized via BetterAuthApp plugin");
|
|
32
|
+
};
|
|
33
|
+
BetterAuthApp.prototype.getAuth = function () {
|
|
34
|
+
return this.auth;
|
|
35
|
+
};
|
|
36
|
+
return BetterAuthApp;
|
|
37
|
+
}());
|
|
38
|
+
exports.BetterAuthApp = BetterAuthApp;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
47
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
48
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
49
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
50
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
51
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
52
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
56
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
57
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
58
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
59
|
+
function step(op) {
|
|
60
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
61
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
62
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
63
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
64
|
+
switch (op[0]) {
|
|
65
|
+
case 0: case 1: t = op; break;
|
|
66
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
67
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
68
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
69
|
+
default:
|
|
70
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
71
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
72
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
73
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
74
|
+
if (t[2]) _.ops.pop();
|
|
75
|
+
_.trys.pop(); continue;
|
|
76
|
+
}
|
|
77
|
+
op = body.call(thisArg, _);
|
|
78
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
79
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
83
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
84
|
+
};
|
|
85
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
86
|
+
var bun_test_1 = require("bun:test");
|
|
87
|
+
var express_1 = __importDefault(require("express"));
|
|
88
|
+
var mongodb_memory_server_1 = require("mongodb-memory-server");
|
|
89
|
+
var mongoose_1 = __importStar(require("mongoose"));
|
|
90
|
+
var betterAuthApp_1 = require("./betterAuthApp");
|
|
91
|
+
var conn;
|
|
92
|
+
var mongod;
|
|
93
|
+
var TestUser;
|
|
94
|
+
var testUserSchema = new mongoose_1.Schema({
|
|
95
|
+
admin: { default: false, type: Boolean },
|
|
96
|
+
betterAuthId: { type: String },
|
|
97
|
+
email: { required: true, type: String },
|
|
98
|
+
name: { type: String },
|
|
99
|
+
oauthProvider: { type: String },
|
|
100
|
+
});
|
|
101
|
+
var setup = (function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
102
|
+
return __generator(this, function (_a) {
|
|
103
|
+
switch (_a.label) {
|
|
104
|
+
case 0: return [4 /*yield*/, mongodb_memory_server_1.MongoMemoryServer.create()];
|
|
105
|
+
case 1:
|
|
106
|
+
mongod = _a.sent();
|
|
107
|
+
conn = mongoose_1.default.createConnection(mongod.getUri());
|
|
108
|
+
return [4 /*yield*/, conn.asPromise()];
|
|
109
|
+
case 2:
|
|
110
|
+
_a.sent();
|
|
111
|
+
TestUser = conn.model("BetterAuthAppTestUser", testUserSchema);
|
|
112
|
+
return [2 /*return*/];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}); })();
|
|
116
|
+
(0, bun_test_1.afterAll)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
117
|
+
return __generator(this, function (_a) {
|
|
118
|
+
switch (_a.label) {
|
|
119
|
+
case 0: return [4 /*yield*/, (conn === null || conn === void 0 ? void 0 : conn.close())];
|
|
120
|
+
case 1:
|
|
121
|
+
_a.sent();
|
|
122
|
+
return [4 /*yield*/, (mongod === null || mongod === void 0 ? void 0 : mongod.stop())];
|
|
123
|
+
case 2:
|
|
124
|
+
_a.sent();
|
|
125
|
+
return [2 /*return*/];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}); });
|
|
129
|
+
(0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
130
|
+
return __generator(this, function (_a) {
|
|
131
|
+
switch (_a.label) {
|
|
132
|
+
case 0: return [4 /*yield*/, setup];
|
|
133
|
+
case 1:
|
|
134
|
+
_a.sent();
|
|
135
|
+
return [4 /*yield*/, TestUser.deleteMany({})];
|
|
136
|
+
case 2:
|
|
137
|
+
_a.sent();
|
|
138
|
+
return [2 /*return*/];
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}); });
|
|
142
|
+
(0, bun_test_1.describe)("BetterAuthApp", function () {
|
|
143
|
+
var makeConfig = function (overrides) {
|
|
144
|
+
if (overrides === void 0) { overrides = {}; }
|
|
145
|
+
return (__assign({ baseURL: "http://localhost:3000", enabled: true, secret: "test-secret-at-least-32-characters-long" }, overrides));
|
|
146
|
+
};
|
|
147
|
+
(0, bun_test_1.it)("registers on an express app without throwing", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
148
|
+
var app, plugin;
|
|
149
|
+
return __generator(this, function (_a) {
|
|
150
|
+
switch (_a.label) {
|
|
151
|
+
case 0: return [4 /*yield*/, setup];
|
|
152
|
+
case 1:
|
|
153
|
+
_a.sent();
|
|
154
|
+
app = (0, express_1.default)();
|
|
155
|
+
app.use(express_1.default.json());
|
|
156
|
+
plugin = new betterAuthApp_1.BetterAuthApp({
|
|
157
|
+
config: makeConfig(),
|
|
158
|
+
});
|
|
159
|
+
(0, bun_test_1.expect)(function () { return plugin.register(app); }).not.toThrow();
|
|
160
|
+
return [2 /*return*/];
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}); });
|
|
164
|
+
(0, bun_test_1.it)("exposes the Better Auth instance after register", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
165
|
+
var app, plugin;
|
|
166
|
+
var _a;
|
|
167
|
+
return __generator(this, function (_b) {
|
|
168
|
+
switch (_b.label) {
|
|
169
|
+
case 0: return [4 /*yield*/, setup];
|
|
170
|
+
case 1:
|
|
171
|
+
_b.sent();
|
|
172
|
+
app = (0, express_1.default)();
|
|
173
|
+
app.use(express_1.default.json());
|
|
174
|
+
plugin = new betterAuthApp_1.BetterAuthApp({
|
|
175
|
+
config: makeConfig(),
|
|
176
|
+
});
|
|
177
|
+
(0, bun_test_1.expect)(plugin.getAuth()).toBeUndefined();
|
|
178
|
+
plugin.register(app);
|
|
179
|
+
(0, bun_test_1.expect)(plugin.getAuth()).toBeDefined();
|
|
180
|
+
(0, bun_test_1.expect)((_a = plugin.getAuth()) === null || _a === void 0 ? void 0 : _a.api).toBeDefined();
|
|
181
|
+
return [2 /*return*/];
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}); });
|
|
185
|
+
(0, bun_test_1.it)("registers with a userModel", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
186
|
+
var app, plugin;
|
|
187
|
+
return __generator(this, function (_a) {
|
|
188
|
+
switch (_a.label) {
|
|
189
|
+
case 0: return [4 /*yield*/, setup];
|
|
190
|
+
case 1:
|
|
191
|
+
_a.sent();
|
|
192
|
+
app = (0, express_1.default)();
|
|
193
|
+
app.use(express_1.default.json());
|
|
194
|
+
plugin = new betterAuthApp_1.BetterAuthApp({
|
|
195
|
+
config: makeConfig(),
|
|
196
|
+
userModel: TestUser,
|
|
197
|
+
});
|
|
198
|
+
(0, bun_test_1.expect)(function () { return plugin.register(app); }).not.toThrow();
|
|
199
|
+
(0, bun_test_1.expect)(plugin.getAuth()).toBeDefined();
|
|
200
|
+
return [2 /*return*/];
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}); });
|
|
204
|
+
(0, bun_test_1.it)("registers with a custom basePath", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
205
|
+
var app, plugin;
|
|
206
|
+
return __generator(this, function (_a) {
|
|
207
|
+
switch (_a.label) {
|
|
208
|
+
case 0: return [4 /*yield*/, setup];
|
|
209
|
+
case 1:
|
|
210
|
+
_a.sent();
|
|
211
|
+
app = (0, express_1.default)();
|
|
212
|
+
app.use(express_1.default.json());
|
|
213
|
+
plugin = new betterAuthApp_1.BetterAuthApp({
|
|
214
|
+
config: makeConfig({ basePath: "/custom/auth" }),
|
|
215
|
+
});
|
|
216
|
+
(0, bun_test_1.expect)(function () { return plugin.register(app); }).not.toThrow();
|
|
217
|
+
return [2 /*return*/];
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}); });
|
|
221
|
+
(0, bun_test_1.it)("registers with social providers", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
222
|
+
var app, plugin;
|
|
223
|
+
return __generator(this, function (_a) {
|
|
224
|
+
switch (_a.label) {
|
|
225
|
+
case 0: return [4 /*yield*/, setup];
|
|
226
|
+
case 1:
|
|
227
|
+
_a.sent();
|
|
228
|
+
app = (0, express_1.default)();
|
|
229
|
+
app.use(express_1.default.json());
|
|
230
|
+
plugin = new betterAuthApp_1.BetterAuthApp({
|
|
231
|
+
config: makeConfig({
|
|
232
|
+
githubOAuth: { clientId: "gh-id", clientSecret: "gh-secret" },
|
|
233
|
+
googleOAuth: { clientId: "g-id", clientSecret: "g-secret" },
|
|
234
|
+
}),
|
|
235
|
+
});
|
|
236
|
+
(0, bun_test_1.expect)(function () { return plugin.register(app); }).not.toThrow();
|
|
237
|
+
(0, bun_test_1.expect)(plugin.getAuth()).toBeDefined();
|
|
238
|
+
return [2 /*return*/];
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}); });
|
|
242
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Better Auth setup and initialization for @terreno/api.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to initialize Better Auth with MongoDB,
|
|
5
|
+
* create session middleware, and sync users with the application User model.
|
|
6
|
+
*/
|
|
7
|
+
import { betterAuth } from "better-auth";
|
|
8
|
+
import type { Application, NextFunction, Request, Response } from "express";
|
|
9
|
+
import type { UserModel } from "./auth";
|
|
10
|
+
import type { BetterAuthConfig, BetterAuthSessionData, BetterAuthUser } from "./betterAuth";
|
|
11
|
+
/**
|
|
12
|
+
* The Better Auth instance type.
|
|
13
|
+
*/
|
|
14
|
+
export type BetterAuthInstance = ReturnType<typeof betterAuth>;
|
|
15
|
+
/**
|
|
16
|
+
* Options for creating a Better Auth instance.
|
|
17
|
+
*/
|
|
18
|
+
export interface CreateBetterAuthOptions {
|
|
19
|
+
config: BetterAuthConfig;
|
|
20
|
+
mongoClient: any;
|
|
21
|
+
userModel?: UserModel;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a Better Auth instance with MongoDB adapter.
|
|
25
|
+
*/
|
|
26
|
+
export declare const createBetterAuth: (options: CreateBetterAuthOptions) => BetterAuthInstance;
|
|
27
|
+
/**
|
|
28
|
+
* Creates Express middleware that extracts the Better Auth session
|
|
29
|
+
* and populates req.user with the application User model.
|
|
30
|
+
*/
|
|
31
|
+
export declare const createBetterAuthSessionMiddleware: (auth: BetterAuthInstance, userModel?: UserModel) => (req: Request, _res: Response, next: NextFunction) => Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Syncs a Better Auth user to the application User model.
|
|
34
|
+
* Creates or updates the user as needed.
|
|
35
|
+
*/
|
|
36
|
+
export declare const syncBetterAuthUser: (userModel: UserModel, betterAuthUser: BetterAuthUser, oauthProvider?: string) => Promise<any>;
|
|
37
|
+
/**
|
|
38
|
+
* Mounts Better Auth routes on the Express app.
|
|
39
|
+
*/
|
|
40
|
+
export declare const mountBetterAuthRoutes: (app: Application, auth: BetterAuthInstance, basePath?: string) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Gets the MongoDB client from the mongoose connection.
|
|
43
|
+
*/
|
|
44
|
+
export declare const getMongoClientFromMongoose: () => any;
|
|
45
|
+
/**
|
|
46
|
+
* Sets up Better Auth user sync hooks.
|
|
47
|
+
* This ensures users created/updated in Better Auth are synced to the application User model.
|
|
48
|
+
*
|
|
49
|
+
* Note: Better Auth doesn't have built-in event hooks, so we rely on the session middleware
|
|
50
|
+
* to create users on first session access.
|
|
51
|
+
*/
|
|
52
|
+
export declare const setupBetterAuthUserSync: (_auth: BetterAuthInstance, _userModel: UserModel) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Extracts Better Auth session data from the request.
|
|
55
|
+
*/
|
|
56
|
+
export declare const getBetterAuthSession: (req: Request) => BetterAuthSessionData | null;
|
|
57
|
+
/**
|
|
58
|
+
* Checks if the request has a valid Better Auth session.
|
|
59
|
+
*/
|
|
60
|
+
export declare const hasBetterAuthSession: (req: Request) => boolean;
|