@objectstack/plugin-auth 3.2.7 → 3.2.9
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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +15 -0
- package/dist/index.d.mts +38 -22
- package/dist/index.d.ts +38 -22
- package/dist/index.js +159 -139
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +159 -139
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/auth-plugin.ts +24 -1
package/dist/index.js
CHANGED
|
@@ -570,145 +570,6 @@ var AuthManager = class {
|
|
|
570
570
|
}
|
|
571
571
|
};
|
|
572
572
|
|
|
573
|
-
// src/auth-plugin.ts
|
|
574
|
-
var AuthPlugin = class {
|
|
575
|
-
constructor(options = {}) {
|
|
576
|
-
this.name = "com.objectstack.auth";
|
|
577
|
-
this.type = "standard";
|
|
578
|
-
this.version = "1.0.0";
|
|
579
|
-
this.dependencies = [];
|
|
580
|
-
this.authManager = null;
|
|
581
|
-
this.options = {
|
|
582
|
-
registerRoutes: true,
|
|
583
|
-
basePath: "/api/v1/auth",
|
|
584
|
-
...options
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
async init(ctx) {
|
|
588
|
-
ctx.logger.info("Initializing Auth Plugin...");
|
|
589
|
-
if (!this.options.secret) {
|
|
590
|
-
throw new Error("AuthPlugin: secret is required");
|
|
591
|
-
}
|
|
592
|
-
const dataEngine = ctx.getService("data");
|
|
593
|
-
if (!dataEngine) {
|
|
594
|
-
ctx.logger.warn("No data engine service found - auth will use in-memory storage");
|
|
595
|
-
}
|
|
596
|
-
this.authManager = new AuthManager({
|
|
597
|
-
...this.options,
|
|
598
|
-
dataEngine
|
|
599
|
-
});
|
|
600
|
-
ctx.registerService("auth", this.authManager);
|
|
601
|
-
ctx.logger.info("Auth Plugin initialized successfully");
|
|
602
|
-
}
|
|
603
|
-
async start(ctx) {
|
|
604
|
-
ctx.logger.info("Starting Auth Plugin...");
|
|
605
|
-
if (!this.authManager) {
|
|
606
|
-
throw new Error("Auth manager not initialized");
|
|
607
|
-
}
|
|
608
|
-
if (this.options.registerRoutes) {
|
|
609
|
-
ctx.hook("kernel:ready", async () => {
|
|
610
|
-
let httpServer = null;
|
|
611
|
-
try {
|
|
612
|
-
httpServer = ctx.getService("http-server");
|
|
613
|
-
} catch {
|
|
614
|
-
}
|
|
615
|
-
if (httpServer) {
|
|
616
|
-
const serverWithPort = httpServer;
|
|
617
|
-
if (this.authManager && typeof serverWithPort.getPort === "function") {
|
|
618
|
-
const actualPort = serverWithPort.getPort();
|
|
619
|
-
if (actualPort) {
|
|
620
|
-
const configuredUrl = this.options.baseUrl || "http://localhost:3000";
|
|
621
|
-
const configuredOrigin = new URL(configuredUrl).origin;
|
|
622
|
-
const actualUrl = `http://localhost:${actualPort}`;
|
|
623
|
-
if (configuredOrigin !== actualUrl) {
|
|
624
|
-
this.authManager.setRuntimeBaseUrl(actualUrl);
|
|
625
|
-
ctx.logger.info(
|
|
626
|
-
`Auth baseUrl auto-updated to ${actualUrl} (configured: ${configuredUrl})`
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
this.registerAuthRoutes(httpServer, ctx);
|
|
632
|
-
ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);
|
|
633
|
-
} else {
|
|
634
|
-
ctx.logger.warn(
|
|
635
|
-
"No HTTP server available \u2014 auth routes not registered. Auth service is still available for MSW/mock environments via HttpDispatcher."
|
|
636
|
-
);
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
try {
|
|
641
|
-
const ql = ctx.getService("objectql");
|
|
642
|
-
if (ql && typeof ql.registerMiddleware === "function") {
|
|
643
|
-
ql.registerMiddleware(async (opCtx, next) => {
|
|
644
|
-
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
645
|
-
return next();
|
|
646
|
-
}
|
|
647
|
-
await next();
|
|
648
|
-
});
|
|
649
|
-
ctx.logger.info("Auth middleware registered on ObjectQL engine");
|
|
650
|
-
}
|
|
651
|
-
} catch (_e) {
|
|
652
|
-
ctx.logger.debug("ObjectQL engine not available, skipping auth middleware registration");
|
|
653
|
-
}
|
|
654
|
-
ctx.logger.info("Auth Plugin started successfully");
|
|
655
|
-
}
|
|
656
|
-
async destroy() {
|
|
657
|
-
this.authManager = null;
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Register authentication routes with HTTP server
|
|
661
|
-
*
|
|
662
|
-
* Uses better-auth's universal handler for all authentication requests.
|
|
663
|
-
* This forwards all requests under basePath to better-auth, which handles:
|
|
664
|
-
* - Email/password authentication
|
|
665
|
-
* - OAuth providers (Google, GitHub, etc.)
|
|
666
|
-
* - Session management
|
|
667
|
-
* - Password reset
|
|
668
|
-
* - Email verification
|
|
669
|
-
* - 2FA, passkeys, magic links (if enabled)
|
|
670
|
-
*/
|
|
671
|
-
registerAuthRoutes(httpServer, ctx) {
|
|
672
|
-
if (!this.authManager) return;
|
|
673
|
-
const basePath = this.options.basePath || "/api/v1/auth";
|
|
674
|
-
if (!("getRawApp" in httpServer) || typeof httpServer.getRawApp !== "function") {
|
|
675
|
-
ctx.logger.error("HTTP server does not support getRawApp() - wildcard routing requires Hono server");
|
|
676
|
-
throw new Error(
|
|
677
|
-
"AuthPlugin requires HonoServerPlugin for wildcard routing support. Please ensure HonoServerPlugin is loaded before AuthPlugin."
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
|
-
const rawApp = httpServer.getRawApp();
|
|
681
|
-
rawApp.all(`${basePath}/*`, async (c) => {
|
|
682
|
-
try {
|
|
683
|
-
const response = await this.authManager.handleRequest(c.req.raw);
|
|
684
|
-
if (response.status >= 500) {
|
|
685
|
-
try {
|
|
686
|
-
const body = await response.clone().text();
|
|
687
|
-
ctx.logger.error("[AuthPlugin] better-auth returned server error", new Error(`HTTP ${response.status}: ${body}`));
|
|
688
|
-
} catch {
|
|
689
|
-
ctx.logger.error("[AuthPlugin] better-auth returned server error", new Error(`HTTP ${response.status}: (unable to read body)`));
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return response;
|
|
693
|
-
} catch (error) {
|
|
694
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
695
|
-
ctx.logger.error("Auth request error:", err);
|
|
696
|
-
return new Response(
|
|
697
|
-
JSON.stringify({
|
|
698
|
-
success: false,
|
|
699
|
-
error: err.message
|
|
700
|
-
}),
|
|
701
|
-
{
|
|
702
|
-
status: 500,
|
|
703
|
-
headers: { "Content-Type": "application/json" }
|
|
704
|
-
}
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
|
|
712
573
|
// src/objects/sys-user.object.ts
|
|
713
574
|
var import_data = require("@objectstack/spec/data");
|
|
714
575
|
var SysUser = import_data.ObjectSchema.create({
|
|
@@ -1418,6 +1279,165 @@ var SysTwoFactor = import_data11.ObjectSchema.create({
|
|
|
1418
1279
|
mru: false
|
|
1419
1280
|
}
|
|
1420
1281
|
});
|
|
1282
|
+
|
|
1283
|
+
// src/auth-plugin.ts
|
|
1284
|
+
var AuthPlugin = class {
|
|
1285
|
+
constructor(options = {}) {
|
|
1286
|
+
this.name = "com.objectstack.auth";
|
|
1287
|
+
this.type = "standard";
|
|
1288
|
+
this.version = "1.0.0";
|
|
1289
|
+
this.dependencies = [];
|
|
1290
|
+
this.authManager = null;
|
|
1291
|
+
this.options = {
|
|
1292
|
+
registerRoutes: true,
|
|
1293
|
+
basePath: "/api/v1/auth",
|
|
1294
|
+
...options
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
async init(ctx) {
|
|
1298
|
+
ctx.logger.info("Initializing Auth Plugin...");
|
|
1299
|
+
if (!this.options.secret) {
|
|
1300
|
+
throw new Error("AuthPlugin: secret is required");
|
|
1301
|
+
}
|
|
1302
|
+
const dataEngine = ctx.getService("data");
|
|
1303
|
+
if (!dataEngine) {
|
|
1304
|
+
ctx.logger.warn("No data engine service found - auth will use in-memory storage");
|
|
1305
|
+
}
|
|
1306
|
+
this.authManager = new AuthManager({
|
|
1307
|
+
...this.options,
|
|
1308
|
+
dataEngine
|
|
1309
|
+
});
|
|
1310
|
+
ctx.registerService("auth", this.authManager);
|
|
1311
|
+
ctx.registerService("app.com.objectstack.system", {
|
|
1312
|
+
id: "com.objectstack.system",
|
|
1313
|
+
name: "System",
|
|
1314
|
+
version: "1.0.0",
|
|
1315
|
+
type: "plugin",
|
|
1316
|
+
namespace: "sys",
|
|
1317
|
+
objects: [
|
|
1318
|
+
SysUser,
|
|
1319
|
+
SysSession,
|
|
1320
|
+
SysAccount,
|
|
1321
|
+
SysVerification,
|
|
1322
|
+
SysOrganization,
|
|
1323
|
+
SysMember,
|
|
1324
|
+
SysInvitation,
|
|
1325
|
+
SysTeam,
|
|
1326
|
+
SysTeamMember,
|
|
1327
|
+
SysApiKey,
|
|
1328
|
+
SysTwoFactor
|
|
1329
|
+
]
|
|
1330
|
+
});
|
|
1331
|
+
ctx.logger.info("Auth Plugin initialized successfully");
|
|
1332
|
+
}
|
|
1333
|
+
async start(ctx) {
|
|
1334
|
+
ctx.logger.info("Starting Auth Plugin...");
|
|
1335
|
+
if (!this.authManager) {
|
|
1336
|
+
throw new Error("Auth manager not initialized");
|
|
1337
|
+
}
|
|
1338
|
+
if (this.options.registerRoutes) {
|
|
1339
|
+
ctx.hook("kernel:ready", async () => {
|
|
1340
|
+
let httpServer = null;
|
|
1341
|
+
try {
|
|
1342
|
+
httpServer = ctx.getService("http-server");
|
|
1343
|
+
} catch {
|
|
1344
|
+
}
|
|
1345
|
+
if (httpServer) {
|
|
1346
|
+
const serverWithPort = httpServer;
|
|
1347
|
+
if (this.authManager && typeof serverWithPort.getPort === "function") {
|
|
1348
|
+
const actualPort = serverWithPort.getPort();
|
|
1349
|
+
if (actualPort) {
|
|
1350
|
+
const configuredUrl = this.options.baseUrl || "http://localhost:3000";
|
|
1351
|
+
const configuredOrigin = new URL(configuredUrl).origin;
|
|
1352
|
+
const actualUrl = `http://localhost:${actualPort}`;
|
|
1353
|
+
if (configuredOrigin !== actualUrl) {
|
|
1354
|
+
this.authManager.setRuntimeBaseUrl(actualUrl);
|
|
1355
|
+
ctx.logger.info(
|
|
1356
|
+
`Auth baseUrl auto-updated to ${actualUrl} (configured: ${configuredUrl})`
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
this.registerAuthRoutes(httpServer, ctx);
|
|
1362
|
+
ctx.logger.info(`Auth routes registered at ${this.options.basePath}`);
|
|
1363
|
+
} else {
|
|
1364
|
+
ctx.logger.warn(
|
|
1365
|
+
"No HTTP server available \u2014 auth routes not registered. Auth service is still available for MSW/mock environments via HttpDispatcher."
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
try {
|
|
1371
|
+
const ql = ctx.getService("objectql");
|
|
1372
|
+
if (ql && typeof ql.registerMiddleware === "function") {
|
|
1373
|
+
ql.registerMiddleware(async (opCtx, next) => {
|
|
1374
|
+
if (opCtx.context?.userId || opCtx.context?.isSystem) {
|
|
1375
|
+
return next();
|
|
1376
|
+
}
|
|
1377
|
+
await next();
|
|
1378
|
+
});
|
|
1379
|
+
ctx.logger.info("Auth middleware registered on ObjectQL engine");
|
|
1380
|
+
}
|
|
1381
|
+
} catch (_e) {
|
|
1382
|
+
ctx.logger.debug("ObjectQL engine not available, skipping auth middleware registration");
|
|
1383
|
+
}
|
|
1384
|
+
ctx.logger.info("Auth Plugin started successfully");
|
|
1385
|
+
}
|
|
1386
|
+
async destroy() {
|
|
1387
|
+
this.authManager = null;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Register authentication routes with HTTP server
|
|
1391
|
+
*
|
|
1392
|
+
* Uses better-auth's universal handler for all authentication requests.
|
|
1393
|
+
* This forwards all requests under basePath to better-auth, which handles:
|
|
1394
|
+
* - Email/password authentication
|
|
1395
|
+
* - OAuth providers (Google, GitHub, etc.)
|
|
1396
|
+
* - Session management
|
|
1397
|
+
* - Password reset
|
|
1398
|
+
* - Email verification
|
|
1399
|
+
* - 2FA, passkeys, magic links (if enabled)
|
|
1400
|
+
*/
|
|
1401
|
+
registerAuthRoutes(httpServer, ctx) {
|
|
1402
|
+
if (!this.authManager) return;
|
|
1403
|
+
const basePath = this.options.basePath || "/api/v1/auth";
|
|
1404
|
+
if (!("getRawApp" in httpServer) || typeof httpServer.getRawApp !== "function") {
|
|
1405
|
+
ctx.logger.error("HTTP server does not support getRawApp() - wildcard routing requires Hono server");
|
|
1406
|
+
throw new Error(
|
|
1407
|
+
"AuthPlugin requires HonoServerPlugin for wildcard routing support. Please ensure HonoServerPlugin is loaded before AuthPlugin."
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
const rawApp = httpServer.getRawApp();
|
|
1411
|
+
rawApp.all(`${basePath}/*`, async (c) => {
|
|
1412
|
+
try {
|
|
1413
|
+
const response = await this.authManager.handleRequest(c.req.raw);
|
|
1414
|
+
if (response.status >= 500) {
|
|
1415
|
+
try {
|
|
1416
|
+
const body = await response.clone().text();
|
|
1417
|
+
ctx.logger.error("[AuthPlugin] better-auth returned server error", new Error(`HTTP ${response.status}: ${body}`));
|
|
1418
|
+
} catch {
|
|
1419
|
+
ctx.logger.error("[AuthPlugin] better-auth returned server error", new Error(`HTTP ${response.status}: (unable to read body)`));
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
return response;
|
|
1423
|
+
} catch (error) {
|
|
1424
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1425
|
+
ctx.logger.error("Auth request error:", err);
|
|
1426
|
+
return new Response(
|
|
1427
|
+
JSON.stringify({
|
|
1428
|
+
success: false,
|
|
1429
|
+
error: err.message
|
|
1430
|
+
}),
|
|
1431
|
+
{
|
|
1432
|
+
status: 500,
|
|
1433
|
+
headers: { "Content-Type": "application/json" }
|
|
1434
|
+
}
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
ctx.logger.info(`Auth routes registered: All requests under ${basePath}/* forwarded to better-auth`);
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1421
1441
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1422
1442
|
0 && (module.exports = {
|
|
1423
1443
|
AUTH_ACCOUNT_CONFIG,
|