@terreno/api 0.1.0 → 0.3.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.d.ts +28 -2
- package/dist/api.js +20 -7
- 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/expressServer.js +3 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- 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 +34 -0
- package/package.json +6 -3
- package/src/api.ts +61 -3
- 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/expressServer.ts +5 -6
- package/src/index.ts +4 -0
- package/src/openApiValidator.ts +1 -1
- package/src/terrenoApp.test.ts +201 -0
- package/src/terrenoApp.ts +347 -0
- package/src/terrenoPlugin.ts +34 -0
- package/.claude/CLAUDE.local.md +0 -204
- package/.cursor/rules/00-root.mdc +0 -338
- package/.github/copilot-instructions.md +0 -333
- package/AGENTS.md +0 -333
package/dist/api.d.ts
CHANGED
|
@@ -218,12 +218,38 @@ export interface ModelRouterOptions<T> {
|
|
|
218
218
|
*/
|
|
219
219
|
validation?: boolean | ModelRouterValidationOptions;
|
|
220
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Registration object returned by modelRouter when called with a path.
|
|
223
|
+
*
|
|
224
|
+
* Used with `TerrenoApp.register()` to mount model routers at specific paths.
|
|
225
|
+
* Contains the Express router and the path it should be mounted at.
|
|
226
|
+
*
|
|
227
|
+
* @see modelRouter for creating registrations
|
|
228
|
+
* @see TerrenoApp for registering routers
|
|
229
|
+
*/
|
|
230
|
+
export interface ModelRouterRegistration {
|
|
231
|
+
/** Internal type discriminator for registration detection */
|
|
232
|
+
__type: "modelRouter";
|
|
233
|
+
/** The path where the router should be mounted (e.g., "/todos") */
|
|
234
|
+
path: string;
|
|
235
|
+
/** The Express router containing CRUD endpoints */
|
|
236
|
+
router: express.Router;
|
|
237
|
+
}
|
|
221
238
|
/**
|
|
222
239
|
* Create a set of CRUD routes given a Mongoose model and configuration options.
|
|
223
240
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
241
|
+
* When called with a path as the first argument, returns a `ModelRouterRegistration` that can be
|
|
242
|
+
* passed to `TerrenoApp.register()`.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* // Traditional usage (returns express.Router):
|
|
246
|
+
* router.use("/todos", modelRouter(Todo, options));
|
|
247
|
+
*
|
|
248
|
+
* // Registration usage (returns ModelRouterRegistration):
|
|
249
|
+
* const todoRouter = modelRouter("/todos", Todo, options);
|
|
250
|
+
* app.register(todoRouter);
|
|
226
251
|
*/
|
|
252
|
+
export declare function modelRouter<T>(path: string, model: Model<T>, options: ModelRouterOptions<T>): ModelRouterRegistration;
|
|
227
253
|
export declare function modelRouter<T>(model: Model<T>, options: ModelRouterOptions<T>): express.Router;
|
|
228
254
|
/**
|
|
229
255
|
* Options for the asyncHandler function.
|
package/dist/api.js
CHANGED
|
@@ -284,13 +284,26 @@ function getQueryValidationMiddleware(model, options) {
|
|
|
284
284
|
}
|
|
285
285
|
return (0, openApiValidator_1.validateQueryParams)(querySchema, validationOptions);
|
|
286
286
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
287
|
+
function modelRouter(pathOrModel, modelOrOptions, maybeOptions) {
|
|
288
|
+
var model;
|
|
289
|
+
var options;
|
|
290
|
+
var path;
|
|
291
|
+
if (typeof pathOrModel === "string") {
|
|
292
|
+
path = pathOrModel;
|
|
293
|
+
model = modelOrOptions;
|
|
294
|
+
options = maybeOptions;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
model = pathOrModel;
|
|
298
|
+
options = modelOrOptions;
|
|
299
|
+
}
|
|
300
|
+
var router = _buildModelRouter(model, options);
|
|
301
|
+
if (path !== undefined) {
|
|
302
|
+
return { __type: "modelRouter", path: path, router: router };
|
|
303
|
+
}
|
|
304
|
+
return router;
|
|
305
|
+
}
|
|
306
|
+
function _buildModelRouter(model, options) {
|
|
294
307
|
var _this = this;
|
|
295
308
|
var _a;
|
|
296
309
|
var router = express_1.default.Router();
|
|
@@ -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
|
+
});
|