@objectstack/plugin-auth 4.0.2 → 4.0.4

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/index.js CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  SysTeamMember: () => SysTeamMember,
50
50
  SysTwoFactor: () => SysTwoFactor,
51
51
  SysUser: () => SysUser,
52
+ SysUserPreference: () => SysUserPreference,
52
53
  SysVerification: () => SysVerification,
53
54
  buildOrganizationPluginSchema: () => buildOrganizationPluginSchema,
54
55
  buildTwoFactorPluginSchema: () => buildTwoFactorPluginSchema,
@@ -432,7 +433,20 @@ var AuthManager = class {
432
433
  // better-auth plugins — registered based on AuthPluginConfig flags
433
434
  plugins: this.buildPluginList(),
434
435
  // Trusted origins for CSRF protection (supports wildcards like "https://*.example.com")
435
- ...this.config.trustedOrigins?.length ? { trustedOrigins: this.config.trustedOrigins } : {},
436
+ // Auto-includes origins from CORS_ORIGIN env var so CORS and CSRF stay in sync.
437
+ ...(() => {
438
+ const origins = [...this.config.trustedOrigins || []];
439
+ const corsOrigin = process.env.CORS_ORIGIN;
440
+ if (corsOrigin && corsOrigin !== "*") {
441
+ corsOrigin.split(",").map((s) => s.trim()).filter(Boolean).forEach((o) => {
442
+ if (!origins.includes(o)) origins.push(o);
443
+ });
444
+ }
445
+ if (!origins.length && (!corsOrigin || corsOrigin === "*")) {
446
+ origins.push("http://localhost:*");
447
+ }
448
+ return origins.length ? { trustedOrigins: origins } : {};
449
+ })(),
436
450
  // Advanced options (cross-subdomain cookies, secure cookies, CSRF, etc.)
437
451
  ...this.config.advanced ? {
438
452
  advanced: {
@@ -568,6 +582,59 @@ var AuthManager = class {
568
582
  get api() {
569
583
  return this.getOrCreateAuth().api;
570
584
  }
585
+ /**
586
+ * Get public authentication configuration
587
+ * Returns safe, non-sensitive configuration that can be exposed to the frontend
588
+ *
589
+ * This allows the frontend to discover:
590
+ * - Which social/OAuth providers are available
591
+ * - Whether email/password login is enabled
592
+ * - Which advanced features are enabled (2FA, magic links, etc.)
593
+ */
594
+ getPublicConfig() {
595
+ const socialProviders = [];
596
+ if (this.config.socialProviders) {
597
+ for (const [id, providerConfig] of Object.entries(this.config.socialProviders)) {
598
+ if (providerConfig.enabled !== false) {
599
+ const nameMap = {
600
+ google: "Google",
601
+ github: "GitHub",
602
+ microsoft: "Microsoft",
603
+ apple: "Apple",
604
+ facebook: "Facebook",
605
+ twitter: "Twitter",
606
+ discord: "Discord",
607
+ gitlab: "GitLab",
608
+ linkedin: "LinkedIn"
609
+ };
610
+ socialProviders.push({
611
+ id,
612
+ name: nameMap[id] || id.charAt(0).toUpperCase() + id.slice(1),
613
+ enabled: true
614
+ });
615
+ }
616
+ }
617
+ }
618
+ const emailPasswordConfig = this.config.emailAndPassword ?? {};
619
+ const emailPassword = {
620
+ enabled: emailPasswordConfig.enabled !== false,
621
+ // Default to true
622
+ disableSignUp: emailPasswordConfig.disableSignUp ?? false,
623
+ requireEmailVerification: emailPasswordConfig.requireEmailVerification ?? false
624
+ };
625
+ const pluginConfig = this.config.plugins ?? {};
626
+ const features = {
627
+ twoFactor: pluginConfig.twoFactor ?? false,
628
+ passkeys: pluginConfig.passkeys ?? false,
629
+ magicLink: pluginConfig.magicLink ?? false,
630
+ organization: pluginConfig.organization ?? false
631
+ };
632
+ return {
633
+ emailPassword,
634
+ socialProviders,
635
+ features
636
+ };
637
+ }
571
638
  };
572
639
 
573
640
  // src/objects/sys-user.object.ts
@@ -1280,6 +1347,65 @@ var SysTwoFactor = import_data11.ObjectSchema.create({
1280
1347
  }
1281
1348
  });
1282
1349
 
1350
+ // src/objects/sys-user-preference.object.ts
1351
+ var import_data12 = require("@objectstack/spec/data");
1352
+ var SysUserPreference = import_data12.ObjectSchema.create({
1353
+ namespace: "sys",
1354
+ name: "user_preference",
1355
+ label: "User Preference",
1356
+ pluralLabel: "User Preferences",
1357
+ icon: "settings",
1358
+ isSystem: true,
1359
+ description: "Per-user key-value preferences (theme, locale, etc.)",
1360
+ titleFormat: "{key}",
1361
+ compactLayout: ["user_id", "key"],
1362
+ fields: {
1363
+ id: import_data12.Field.text({
1364
+ label: "Preference ID",
1365
+ required: true,
1366
+ readonly: true
1367
+ }),
1368
+ created_at: import_data12.Field.datetime({
1369
+ label: "Created At",
1370
+ defaultValue: "NOW()",
1371
+ readonly: true
1372
+ }),
1373
+ updated_at: import_data12.Field.datetime({
1374
+ label: "Updated At",
1375
+ defaultValue: "NOW()",
1376
+ readonly: true
1377
+ }),
1378
+ user_id: import_data12.Field.text({
1379
+ label: "User ID",
1380
+ required: true,
1381
+ maxLength: 255,
1382
+ description: "Owner user of this preference"
1383
+ }),
1384
+ key: import_data12.Field.text({
1385
+ label: "Key",
1386
+ required: true,
1387
+ maxLength: 255,
1388
+ description: "Preference key (e.g., theme, locale, plugin.ai.auto_save)"
1389
+ }),
1390
+ value: import_data12.Field.json({
1391
+ label: "Value",
1392
+ description: "Preference value (any JSON-serializable type)"
1393
+ })
1394
+ },
1395
+ indexes: [
1396
+ { fields: ["user_id", "key"], unique: true },
1397
+ { fields: ["user_id"], unique: false }
1398
+ ],
1399
+ enable: {
1400
+ trackHistory: false,
1401
+ searchable: false,
1402
+ apiEnabled: true,
1403
+ apiMethods: ["get", "list", "create", "update", "delete"],
1404
+ trash: false,
1405
+ mru: false
1406
+ }
1407
+ });
1408
+
1283
1409
  // src/auth-plugin.ts
1284
1410
  var AuthPlugin = class {
1285
1411
  constructor(options = {}) {
@@ -1325,7 +1451,8 @@ var AuthPlugin = class {
1325
1451
  SysTeam,
1326
1452
  SysTeamMember,
1327
1453
  SysApiKey,
1328
- SysTwoFactor
1454
+ SysTwoFactor,
1455
+ SysUserPreference
1329
1456
  ]
1330
1457
  });
1331
1458
  try {
@@ -1425,6 +1552,25 @@ var AuthPlugin = class {
1425
1552
  );
1426
1553
  }
1427
1554
  const rawApp = httpServer.getRawApp();
1555
+ rawApp.get(`${basePath}/config`, async (c) => {
1556
+ try {
1557
+ const config = this.authManager.getPublicConfig();
1558
+ return c.json({
1559
+ success: true,
1560
+ data: config
1561
+ });
1562
+ } catch (error) {
1563
+ const err = error instanceof Error ? error : new Error(String(error));
1564
+ ctx.logger.error("Auth config error:", err);
1565
+ return c.json({
1566
+ success: false,
1567
+ error: {
1568
+ code: "auth_config_error",
1569
+ message: err.message
1570
+ }
1571
+ }, 500);
1572
+ }
1573
+ });
1428
1574
  rawApp.all(`${basePath}/*`, async (c) => {
1429
1575
  try {
1430
1576
  const response = await this.authManager.handleRequest(c.req.raw);
@@ -1486,6 +1632,7 @@ var AuthPlugin = class {
1486
1632
  SysTeamMember,
1487
1633
  SysTwoFactor,
1488
1634
  SysUser,
1635
+ SysUserPreference,
1489
1636
  SysVerification,
1490
1637
  buildOrganizationPluginSchema,
1491
1638
  buildTwoFactorPluginSchema,