@spfn/auth 0.2.0-beta.42 → 0.2.0-beta.43

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.
@@ -44,7 +44,7 @@ interface AuthSession {
44
44
  }
45
45
  interface ProfileInfo {
46
46
  profileId: number;
47
- displayName: string;
47
+ displayName: string | null;
48
48
  firstName: string | null;
49
49
  lastName: string | null;
50
50
  avatarUrl: string | null;
@@ -545,7 +545,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
545
545
  id: number;
546
546
  name: string;
547
547
  displayName: string;
548
- category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
548
+ category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
549
549
  }[];
550
550
  userId: number;
551
551
  email: string | null;
package/dist/config.js CHANGED
@@ -280,7 +280,7 @@ var authEnvSchema = defineEnvSchema({
280
280
  ...envString({
281
281
  description: "URL to redirect after OAuth error. Use {error} placeholder for error message.",
282
282
  required: false,
283
- default: "http://localhost:3000/auth/error?error={error}",
283
+ default: "/auth/error?error={error}",
284
284
  examples: [
285
285
  "https://app.example.com/auth/error?error={error}",
286
286
  "http://localhost:3000/auth/error?error={error}"
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["/**\n * Core Package Configuration\n *\n * @example\n * ```typescript\n * import { registry } from '@spfn/core/config';\n *\n * const env = registry.validate();\n * console.log(env.DB_POOL_MAX);\n * ```\n *\n * @module config\n */\n\nimport { createEnvRegistry } from '@spfn/core/env';\nimport { authEnvSchema } from './schema';\n\nexport { authEnvSchema as envSchema } from './schema';\n\n/**\n * Environment registry\n */\nconst registry = createEnvRegistry(authEnvSchema);\nexport const env = registry.validate();","/**\n * Auth Environment Variable Schema\n *\n * Centralized schema definition for all environment variables used in @spfn/auth.\n * This provides type safety, validation, and documentation for Auth configuration.\n *\n * @module config/schema\n */\n\nimport {\n defineEnvSchema,\n envString,\n envNumber,\n createSecureSecretParser,\n createPasswordParser,\n} from '@spfn/core/env';\n\n/**\n * Auth environment variable schema\n *\n * Defines all Auth environment variables with:\n * - Type information\n * - Default values\n * - Validation rules\n * - Documentation\n *\n * @example\n * ```typescript\n * import { authEnvSchema } from '@spfn/auth/config';\n *\n * // Access schema information\n * console.log(authEnvSchema.SPFN_AUTH_SESSION_SECRET.description);\n * console.log(authEnvSchema.SPFN_AUTH_JWT_EXPIRES_IN.default);\n * ```\n */\nexport const authEnvSchema = defineEnvSchema({\n // ============================================================================\n // Session Configuration\n // ============================================================================\n SPFN_AUTH_SESSION_SECRET: {\n ...envString({\n description: 'Session encryption secret (minimum 32 characters for AES-256)',\n required: true,\n fallbackKeys: ['SESSION_SECRET'],\n validator: createSecureSecretParser({\n minLength: 32,\n minUniqueChars: 16,\n minEntropy: 3.5,\n }),\n sensitive: true,\n nextjs: true, // Required for Next.js RSC session validation\n examples: [\n 'my-super-secret-session-key-at-least-32-chars-long',\n 'use-a-cryptographically-secure-random-string-here',\n ],\n }),\n },\n\n SPFN_AUTH_SESSION_TTL: {\n ...envString({\n description: 'Session TTL (time to live) - supports duration strings like \\'7d\\', \\'12h\\', \\'45m\\'',\n default: '7d',\n required: false,\n nextjs: true, // May be needed for session validation in Next.js RSC\n examples: ['7d', '30d', '12h', '45m', '3600'],\n }),\n },\n\n // ============================================================================\n // JWT Configuration\n // ============================================================================\n SPFN_AUTH_JWT_SECRET: {\n ...envString({\n description: 'JWT signing secret for server-signed tokens (legacy mode)',\n default: 'dev-secret-key-change-in-production',\n required: false,\n examples: [\n 'your-jwt-secret-key-here',\n 'use-different-from-session-secret',\n ],\n }),\n },\n\n SPFN_AUTH_JWT_EXPIRES_IN: {\n ...envString({\n description: 'JWT token expiration time (e.g., \\'7d\\', \\'24h\\', \\'1h\\')',\n default: '7d',\n required: false,\n examples: ['7d', '24h', '1h', '30m'],\n }),\n },\n\n // ============================================================================\n // Security Configuration\n // ============================================================================\n SPFN_AUTH_BCRYPT_SALT_ROUNDS: {\n ...envNumber({\n description: 'Bcrypt salt rounds (cost factor, higher = more secure but slower)',\n default: 10,\n required: false,\n examples: [10, 12, 14],\n }),\n key: 'SPFN_AUTH_BCRYPT_SALT_ROUNDS',\n },\n\n SPFN_AUTH_VERIFICATION_TOKEN_SECRET: {\n ...envString({\n description: 'Verification token secret for email verification, password reset, etc.',\n required: true,\n examples: [\n 'your-verification-token-secret',\n 'can-be-different-from-jwt-secret',\n ],\n }),\n },\n\n // ============================================================================\n // Admin Account Configuration\n // ============================================================================\n SPFN_AUTH_ADMIN_ACCOUNTS: {\n ...envString({\n description: 'JSON array of admin accounts (recommended for multiple admins)',\n required: false,\n examples: [\n '[{\"email\":\"admin@example.com\",\"password\":\"secure-pass\",\"role\":\"admin\"}]',\n '[{\"email\":\"super@example.com\",\"password\":\"pass1\",\"role\":\"superadmin\"},{\"email\":\"admin@example.com\",\"password\":\"pass2\",\"role\":\"admin\"}]',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAILS: {\n ...envString({\n description: 'Comma-separated list of admin emails (legacy CSV format)',\n required: false,\n examples: [\n 'admin@example.com,user@example.com',\n 'super@example.com,admin@example.com,user@example.com',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORDS: {\n ...envString({\n description: 'Comma-separated list of admin passwords (legacy CSV format)',\n required: false,\n examples: [\n 'admin-pass,user-pass',\n 'super-pass,admin-pass,user-pass',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_ROLES: {\n ...envString({\n description: 'Comma-separated list of admin roles (legacy CSV format)',\n required: false,\n examples: [\n 'admin,user',\n 'superadmin,admin,user',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAIL: {\n ...envString({\n description: 'Single admin email (simplest format)',\n required: false,\n examples: ['admin@example.com'],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORD: {\n ...envString({\n description: 'Single admin password (simplest format)',\n required: false,\n validator: createPasswordParser({\n minLength: 8,\n requireUppercase: true,\n requireLowercase: true,\n requireNumber: true,\n requireSpecial: true,\n }),\n sensitive: true,\n examples: ['SecureAdmin123!'],\n }),\n },\n\n // ============================================================================\n // Username Configuration\n // ============================================================================\n SPFN_AUTH_RESERVED_USERNAMES: {\n ...envString({\n description: 'Comma-separated list of reserved usernames that cannot be registered',\n required: false,\n default: 'admin,root,system,support,help,moderator,superadmin',\n examples: [\n 'admin,root,system,support,help',\n 'admin,root,system,support,help,moderator,superadmin,operator',\n ],\n }),\n },\n\n SPFN_AUTH_USERNAME_MIN_LENGTH: {\n ...envNumber({\n description: 'Minimum username length',\n default: 3,\n required: false,\n examples: [2, 3, 4],\n }),\n },\n\n SPFN_AUTH_USERNAME_MAX_LENGTH: {\n ...envNumber({\n description: 'Maximum username length',\n default: 30,\n required: false,\n examples: [20, 30, 50],\n }),\n },\n\n // ============================================================================\n // API Configuration\n // ============================================================================\n SPFN_API_URL: {\n ...envString({\n description: 'Internal API URL for server-to-server communication',\n default: 'http://localhost:8790',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_API_URL: {\n ...envString({\n description: 'Public-facing API URL used for browser-facing redirects (e.g. OAuth callback). Falls back to SPFN_API_URL if not set.',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n SPFN_APP_URL: {\n ...envString({\n description: 'Next.js application URL (internal). Used for server-to-server communication.',\n default: 'http://localhost:3000',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_APP_URL: {\n ...envString({\n description: 'Public-facing Next.js app URL for browser redirects (e.g. OAuth redirect). Falls back to SPFN_APP_URL if not set.',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Google\n // ============================================================================\n SPFN_AUTH_GOOGLE_CLIENT_ID: {\n ...envString({\n description: 'Google OAuth 2.0 Client ID. When set, Google OAuth routes are automatically enabled.',\n required: false,\n examples: ['123456789-abc123.apps.googleusercontent.com'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_CLIENT_SECRET: {\n ...envString({\n description: 'Google OAuth 2.0 Client Secret',\n required: false,\n sensitive: true,\n examples: ['GOCSPX-abcdefghijklmnop'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_SCOPES: {\n ...envString({\n description: 'Comma-separated Google OAuth scopes. Defaults to \"email,profile\" if not set.',\n required: false,\n examples: [\n 'email,profile',\n 'email,profile,https://www.googleapis.com/auth/gmail.readonly',\n 'email,profile,https://www.googleapis.com/auth/calendar.readonly',\n ],\n }),\n },\n\n SPFN_AUTH_GOOGLE_REDIRECT_URI: {\n ...envString({\n description: 'Google OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_API_URL || SPFN_API_URL}/_auth/oauth/google/callback',\n required: false,\n examples: [\n 'https://api.example.com/_auth/oauth/google/callback',\n 'http://localhost:8790/_auth/oauth/google/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_SUCCESS_URL: {\n ...envString({\n description: 'OAuth callback page URL. This page should use OAuthCallback component to finalize session.',\n required: false,\n default: '/auth/callback',\n examples: [\n '/auth/callback',\n 'https://app.example.com/auth/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_ERROR_URL: {\n ...envString({\n description: 'URL to redirect after OAuth error. Use {error} placeholder for error message.',\n required: false,\n default: 'http://localhost:3000/auth/error?error={error}',\n examples: [\n 'https://app.example.com/auth/error?error={error}',\n 'http://localhost:3000/auth/error?error={error}',\n ],\n }),\n },\n});"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["/**\n * Core Package Configuration\n *\n * @example\n * ```typescript\n * import { registry } from '@spfn/core/config';\n *\n * const env = registry.validate();\n * console.log(env.DB_POOL_MAX);\n * ```\n *\n * @module config\n */\n\nimport { createEnvRegistry } from '@spfn/core/env';\nimport { authEnvSchema } from './schema';\n\nexport { authEnvSchema as envSchema } from './schema';\n\n/**\n * Environment registry\n */\nconst registry = createEnvRegistry(authEnvSchema);\nexport const env = registry.validate();","/**\n * Auth Environment Variable Schema\n *\n * Centralized schema definition for all environment variables used in @spfn/auth.\n * This provides type safety, validation, and documentation for Auth configuration.\n *\n * @module config/schema\n */\n\nimport {\n defineEnvSchema,\n envString,\n envNumber,\n createSecureSecretParser,\n createPasswordParser,\n} from '@spfn/core/env';\n\n/**\n * Auth environment variable schema\n *\n * Defines all Auth environment variables with:\n * - Type information\n * - Default values\n * - Validation rules\n * - Documentation\n *\n * @example\n * ```typescript\n * import { authEnvSchema } from '@spfn/auth/config';\n *\n * // Access schema information\n * console.log(authEnvSchema.SPFN_AUTH_SESSION_SECRET.description);\n * console.log(authEnvSchema.SPFN_AUTH_JWT_EXPIRES_IN.default);\n * ```\n */\nexport const authEnvSchema = defineEnvSchema({\n // ============================================================================\n // Session Configuration\n // ============================================================================\n SPFN_AUTH_SESSION_SECRET: {\n ...envString({\n description: 'Session encryption secret (minimum 32 characters for AES-256)',\n required: true,\n fallbackKeys: ['SESSION_SECRET'],\n validator: createSecureSecretParser({\n minLength: 32,\n minUniqueChars: 16,\n minEntropy: 3.5,\n }),\n sensitive: true,\n nextjs: true, // Required for Next.js RSC session validation\n examples: [\n 'my-super-secret-session-key-at-least-32-chars-long',\n 'use-a-cryptographically-secure-random-string-here',\n ],\n }),\n },\n\n SPFN_AUTH_SESSION_TTL: {\n ...envString({\n description: 'Session TTL (time to live) - supports duration strings like \\'7d\\', \\'12h\\', \\'45m\\'',\n default: '7d',\n required: false,\n nextjs: true, // May be needed for session validation in Next.js RSC\n examples: ['7d', '30d', '12h', '45m', '3600'],\n }),\n },\n\n // ============================================================================\n // JWT Configuration\n // ============================================================================\n SPFN_AUTH_JWT_SECRET: {\n ...envString({\n description: 'JWT signing secret for server-signed tokens (legacy mode)',\n default: 'dev-secret-key-change-in-production',\n required: false,\n examples: [\n 'your-jwt-secret-key-here',\n 'use-different-from-session-secret',\n ],\n }),\n },\n\n SPFN_AUTH_JWT_EXPIRES_IN: {\n ...envString({\n description: 'JWT token expiration time (e.g., \\'7d\\', \\'24h\\', \\'1h\\')',\n default: '7d',\n required: false,\n examples: ['7d', '24h', '1h', '30m'],\n }),\n },\n\n // ============================================================================\n // Security Configuration\n // ============================================================================\n SPFN_AUTH_BCRYPT_SALT_ROUNDS: {\n ...envNumber({\n description: 'Bcrypt salt rounds (cost factor, higher = more secure but slower)',\n default: 10,\n required: false,\n examples: [10, 12, 14],\n }),\n key: 'SPFN_AUTH_BCRYPT_SALT_ROUNDS',\n },\n\n SPFN_AUTH_VERIFICATION_TOKEN_SECRET: {\n ...envString({\n description: 'Verification token secret for email verification, password reset, etc.',\n required: true,\n examples: [\n 'your-verification-token-secret',\n 'can-be-different-from-jwt-secret',\n ],\n }),\n },\n\n // ============================================================================\n // Admin Account Configuration\n // ============================================================================\n SPFN_AUTH_ADMIN_ACCOUNTS: {\n ...envString({\n description: 'JSON array of admin accounts (recommended for multiple admins)',\n required: false,\n examples: [\n '[{\"email\":\"admin@example.com\",\"password\":\"secure-pass\",\"role\":\"admin\"}]',\n '[{\"email\":\"super@example.com\",\"password\":\"pass1\",\"role\":\"superadmin\"},{\"email\":\"admin@example.com\",\"password\":\"pass2\",\"role\":\"admin\"}]',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAILS: {\n ...envString({\n description: 'Comma-separated list of admin emails (legacy CSV format)',\n required: false,\n examples: [\n 'admin@example.com,user@example.com',\n 'super@example.com,admin@example.com,user@example.com',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORDS: {\n ...envString({\n description: 'Comma-separated list of admin passwords (legacy CSV format)',\n required: false,\n examples: [\n 'admin-pass,user-pass',\n 'super-pass,admin-pass,user-pass',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_ROLES: {\n ...envString({\n description: 'Comma-separated list of admin roles (legacy CSV format)',\n required: false,\n examples: [\n 'admin,user',\n 'superadmin,admin,user',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAIL: {\n ...envString({\n description: 'Single admin email (simplest format)',\n required: false,\n examples: ['admin@example.com'],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORD: {\n ...envString({\n description: 'Single admin password (simplest format)',\n required: false,\n validator: createPasswordParser({\n minLength: 8,\n requireUppercase: true,\n requireLowercase: true,\n requireNumber: true,\n requireSpecial: true,\n }),\n sensitive: true,\n examples: ['SecureAdmin123!'],\n }),\n },\n\n // ============================================================================\n // Username Configuration\n // ============================================================================\n SPFN_AUTH_RESERVED_USERNAMES: {\n ...envString({\n description: 'Comma-separated list of reserved usernames that cannot be registered',\n required: false,\n default: 'admin,root,system,support,help,moderator,superadmin',\n examples: [\n 'admin,root,system,support,help',\n 'admin,root,system,support,help,moderator,superadmin,operator',\n ],\n }),\n },\n\n SPFN_AUTH_USERNAME_MIN_LENGTH: {\n ...envNumber({\n description: 'Minimum username length',\n default: 3,\n required: false,\n examples: [2, 3, 4],\n }),\n },\n\n SPFN_AUTH_USERNAME_MAX_LENGTH: {\n ...envNumber({\n description: 'Maximum username length',\n default: 30,\n required: false,\n examples: [20, 30, 50],\n }),\n },\n\n // ============================================================================\n // API Configuration\n // ============================================================================\n SPFN_API_URL: {\n ...envString({\n description: 'Internal API URL for server-to-server communication',\n default: 'http://localhost:8790',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_API_URL: {\n ...envString({\n description: 'Public-facing API URL used for browser-facing redirects (e.g. OAuth callback). Falls back to SPFN_API_URL if not set.',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n SPFN_APP_URL: {\n ...envString({\n description: 'Next.js application URL (internal). Used for server-to-server communication.',\n default: 'http://localhost:3000',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_APP_URL: {\n ...envString({\n description: 'Public-facing Next.js app URL for browser redirects (e.g. OAuth redirect). Falls back to SPFN_APP_URL if not set.',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Google\n // ============================================================================\n SPFN_AUTH_GOOGLE_CLIENT_ID: {\n ...envString({\n description: 'Google OAuth 2.0 Client ID. When set, Google OAuth routes are automatically enabled.',\n required: false,\n examples: ['123456789-abc123.apps.googleusercontent.com'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_CLIENT_SECRET: {\n ...envString({\n description: 'Google OAuth 2.0 Client Secret',\n required: false,\n sensitive: true,\n examples: ['GOCSPX-abcdefghijklmnop'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_SCOPES: {\n ...envString({\n description: 'Comma-separated Google OAuth scopes. Defaults to \"email,profile\" if not set.',\n required: false,\n examples: [\n 'email,profile',\n 'email,profile,https://www.googleapis.com/auth/gmail.readonly',\n 'email,profile,https://www.googleapis.com/auth/calendar.readonly',\n ],\n }),\n },\n\n SPFN_AUTH_GOOGLE_REDIRECT_URI: {\n ...envString({\n description: 'Google OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_API_URL || SPFN_API_URL}/_auth/oauth/google/callback',\n required: false,\n examples: [\n 'https://api.example.com/_auth/oauth/google/callback',\n 'http://localhost:8790/_auth/oauth/google/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_SUCCESS_URL: {\n ...envString({\n description: 'OAuth callback page URL. This page should use OAuthCallback component to finalize session.',\n required: false,\n default: '/auth/callback',\n examples: [\n '/auth/callback',\n 'https://app.example.com/auth/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_ERROR_URL: {\n ...envString({\n description: 'URL to redirect after OAuth error. Use {error} placeholder for error message.',\n required: false,\n default: '/auth/error?error={error}',\n examples: [\n 'https://app.example.com/auth/error?error={error}',\n 'http://localhost:3000/auth/error?error={error}',\n ],\n }),\n },\n});"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _spfn_core_nextjs from '@spfn/core/nextjs';
2
- import { R as RoleConfig, P as PermissionConfig, C as CheckAccountExistsResult, S as SendVerificationCodeResult, a as RegisterResult, L as LoginResult, b as RotateKeyResult, O as OAuthStartResult, U as UserProfile, c as ProfileInfo, m as mainAuthRouter } from './authenticate-gnTzrnU-.js';
3
- export { k as AuthInitOptions, A as AuthSession, I as INVITATION_STATUSES, n as InvitationStatus, K as KEY_ALGORITHM, l as KeyAlgorithmType, i as PERMISSION_CATEGORIES, j as PermissionCategory, e as SOCIAL_PROVIDERS, p as SocialProvider, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, f as VerificationPurpose, V as VerificationTargetType } from './authenticate-gnTzrnU-.js';
2
+ import { R as RoleConfig, P as PermissionConfig, C as CheckAccountExistsResult, S as SendVerificationCodeResult, a as RegisterResult, L as LoginResult, b as RotateKeyResult, O as OAuthStartResult, U as UserProfile, c as ProfileInfo, m as mainAuthRouter } from './authenticate-CAJr3A4H.js';
3
+ export { k as AuthInitOptions, A as AuthSession, I as INVITATION_STATUSES, n as InvitationStatus, K as KEY_ALGORITHM, l as KeyAlgorithmType, i as PERMISSION_CATEGORIES, j as PermissionCategory, e as SOCIAL_PROVIDERS, p as SocialProvider, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, f as VerificationPurpose, V as VerificationTargetType } from './authenticate-CAJr3A4H.js';
4
4
  import * as _spfn_core_route from '@spfn/core/route';
5
5
  import { HttpMethod } from '@spfn/core/route';
6
6
  import * as _sinclair_typebox from '@sinclair/typebox';
@@ -169,7 +169,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
169
169
  id: number;
170
170
  name: string;
171
171
  displayName: string;
172
- category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
172
+ category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
173
173
  }[];
174
174
  userId: number;
175
175
  email: string | null;
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, p as SocialProvider, q as AuthContext } from './authenticate-gnTzrnU-.js';
2
- export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, a6 as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, a2 as OAuthCallbackParams, a3 as OAuthCallbackResult, a1 as OAuthStartParams, O as OAuthStartResult, a8 as PasswordSchema, a7 as PhoneSchema, x as RegisterParams, Q as RegisterPublicKeyParams, a as RegisterResult, W as RevokeKeyParams, T as RotateKeyParams, b as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, a9 as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, aa as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, a4 as authenticate, Z as buildOAuthErrorUrl, v as changePasswordService, r as checkAccountExistsService, $ as getEnabledOAuthProviders, a0 as getGoogleAccessToken, _ as isOAuthProviderEnabled, t as loginService, u as logoutService, Y as oauthCallbackService, X as oauthStartService, a5 as optionalAuth, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './authenticate-gnTzrnU-.js';
1
+ import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, p as SocialProvider, q as AuthContext } from './authenticate-CAJr3A4H.js';
2
+ export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, a6 as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, a2 as OAuthCallbackParams, a3 as OAuthCallbackResult, a1 as OAuthStartParams, O as OAuthStartResult, a8 as PasswordSchema, a7 as PhoneSchema, x as RegisterParams, Q as RegisterPublicKeyParams, a as RegisterResult, W as RevokeKeyParams, T as RotateKeyParams, b as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, a9 as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, aa as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, a4 as authenticate, Z as buildOAuthErrorUrl, v as changePasswordService, r as checkAccountExistsService, $ as getEnabledOAuthProviders, a0 as getGoogleAccessToken, _ as isOAuthProviderEnabled, t as loginService, u as logoutService, Y as oauthCallbackService, X as oauthStartService, a5 as optionalAuth, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './authenticate-CAJr3A4H.js';
3
3
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
4
4
  import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
5
5
  import { BaseRepository } from '@spfn/core/db';
@@ -1306,7 +1306,7 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
1306
1306
  id: number;
1307
1307
  name: string;
1308
1308
  displayName: string;
1309
- category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
1309
+ category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
1310
1310
  }[];
1311
1311
  userId: number;
1312
1312
  email: string | null;
@@ -1489,7 +1489,7 @@ declare const userProfiles: drizzle_orm_pg_core.PgTableWithColumns<{
1489
1489
  columnType: "PgText";
1490
1490
  data: string;
1491
1491
  driverParam: string;
1492
- notNull: true;
1492
+ notNull: false;
1493
1493
  hasDefault: false;
1494
1494
  isPrimaryKey: false;
1495
1495
  isAutoincrement: false;
@@ -2445,7 +2445,7 @@ declare const permissions: drizzle_orm_pg_core.PgTableWithColumns<{
2445
2445
  tableName: "permissions";
2446
2446
  dataType: "string";
2447
2447
  columnType: "PgText";
2448
- data: "custom" | "user" | "auth" | "rbac" | "system";
2448
+ data: "auth" | "custom" | "user" | "rbac" | "system";
2449
2449
  driverParam: string;
2450
2450
  notNull: false;
2451
2451
  hasDefault: false;
@@ -2943,16 +2943,16 @@ declare class UsersRepository extends BaseRepository {
2943
2943
  * Write primary 사용
2944
2944
  */
2945
2945
  create(data: NewUser): Promise<{
2946
- username: string | null;
2947
- status: "active" | "inactive" | "suspended";
2948
2946
  email: string | null;
2949
2947
  phone: string | null;
2950
2948
  id: number;
2951
- createdAt: Date;
2952
- updatedAt: Date;
2949
+ username: string | null;
2953
2950
  passwordHash: string | null;
2954
2951
  passwordChangeRequired: boolean;
2955
2952
  roleId: number;
2953
+ createdAt: Date;
2954
+ updatedAt: Date;
2955
+ status: "active" | "inactive" | "suspended";
2956
2956
  emailVerifiedAt: Date | null;
2957
2957
  phoneVerifiedAt: Date | null;
2958
2958
  lastLoginAt: Date | null;
@@ -3019,16 +3019,16 @@ declare class UsersRepository extends BaseRepository {
3019
3019
  * Write primary 사용
3020
3020
  */
3021
3021
  deleteById(id: number): Promise<{
3022
- username: string | null;
3023
- status: "active" | "inactive" | "suspended";
3024
3022
  email: string | null;
3025
3023
  phone: string | null;
3026
3024
  id: number;
3027
- createdAt: Date;
3028
- updatedAt: Date;
3025
+ username: string | null;
3029
3026
  passwordHash: string | null;
3030
3027
  passwordChangeRequired: boolean;
3031
3028
  roleId: number;
3029
+ createdAt: Date;
3030
+ updatedAt: Date;
3031
+ status: "active" | "inactive" | "suspended";
3032
3032
  emailVerifiedAt: Date | null;
3033
3033
  phoneVerifiedAt: Date | null;
3034
3034
  lastLoginAt: Date | null;
@@ -3051,7 +3051,7 @@ declare class UsersRepository extends BaseRepository {
3051
3051
  id: number;
3052
3052
  name: string;
3053
3053
  displayName: string;
3054
- category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
3054
+ category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
3055
3055
  }[];
3056
3056
  }>;
3057
3057
  /**
@@ -3163,16 +3163,16 @@ declare class KeysRepository extends BaseRepository {
3163
3163
  * Write primary 사용
3164
3164
  */
3165
3165
  create(data: NewUserPublicKey): Promise<{
3166
- userId: number;
3166
+ publicKey: string;
3167
3167
  keyId: string;
3168
+ fingerprint: string;
3169
+ algorithm: "ES256" | "RS256";
3170
+ userId: number;
3168
3171
  id: number;
3169
3172
  isActive: boolean;
3170
3173
  createdAt: Date;
3171
- publicKey: string;
3172
- algorithm: "ES256" | "RS256";
3173
- fingerprint: string;
3174
- lastUsedAt: Date | null;
3175
3174
  expiresAt: Date | null;
3175
+ lastUsedAt: Date | null;
3176
3176
  revokedAt: Date | null;
3177
3177
  revokedReason: string | null;
3178
3178
  }>;
@@ -3199,16 +3199,16 @@ declare class KeysRepository extends BaseRepository {
3199
3199
  * Write primary 사용
3200
3200
  */
3201
3201
  deleteByKeyIdAndUserId(keyId: string, userId: number): Promise<{
3202
- userId: number;
3202
+ publicKey: string;
3203
3203
  keyId: string;
3204
+ fingerprint: string;
3205
+ algorithm: "ES256" | "RS256";
3206
+ userId: number;
3204
3207
  id: number;
3205
3208
  isActive: boolean;
3206
3209
  createdAt: Date;
3207
- publicKey: string;
3208
- algorithm: "ES256" | "RS256";
3209
- fingerprint: string;
3210
- lastUsedAt: Date | null;
3211
3210
  expiresAt: Date | null;
3211
+ lastUsedAt: Date | null;
3212
3212
  revokedAt: Date | null;
3213
3213
  revokedReason: string | null;
3214
3214
  }>;
@@ -3323,14 +3323,14 @@ declare class VerificationCodesRepository extends BaseRepository {
3323
3323
  * Write primary 사용
3324
3324
  */
3325
3325
  create(data: NewVerificationCode): Promise<{
3326
+ target: string;
3327
+ targetType: "email" | "phone";
3328
+ purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
3329
+ code: string;
3326
3330
  id: number;
3327
3331
  createdAt: Date;
3328
3332
  updatedAt: Date;
3329
3333
  expiresAt: Date;
3330
- target: string;
3331
- targetType: "email" | "phone";
3332
- code: string;
3333
- purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
3334
3334
  usedAt: Date | null;
3335
3335
  attempts: number;
3336
3336
  }>;
@@ -3519,7 +3519,7 @@ declare class PermissionsRepository extends BaseRepository {
3519
3519
  name: string;
3520
3520
  displayName: string;
3521
3521
  description: string | null;
3522
- category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3522
+ category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3523
3523
  isBuiltin: boolean;
3524
3524
  isSystem: boolean;
3525
3525
  isActive: boolean;
@@ -3535,7 +3535,7 @@ declare class PermissionsRepository extends BaseRepository {
3535
3535
  name: string;
3536
3536
  displayName: string;
3537
3537
  description: string | null;
3538
- category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3538
+ category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3539
3539
  isBuiltin: boolean;
3540
3540
  isSystem: boolean;
3541
3541
  isActive: boolean;
@@ -3575,7 +3575,7 @@ declare class PermissionsRepository extends BaseRepository {
3575
3575
  name: string;
3576
3576
  displayName: string;
3577
3577
  description: string | null;
3578
- category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3578
+ category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3579
3579
  isBuiltin: boolean;
3580
3580
  isSystem: boolean;
3581
3581
  isActive: boolean;
@@ -3586,6 +3586,7 @@ declare class PermissionsRepository extends BaseRepository {
3586
3586
  */
3587
3587
  deleteById(id: number): Promise<{
3588
3588
  description: string | null;
3589
+ metadata: Record<string, any> | null;
3589
3590
  id: number;
3590
3591
  name: string;
3591
3592
  displayName: string;
@@ -3594,8 +3595,7 @@ declare class PermissionsRepository extends BaseRepository {
3594
3595
  isActive: boolean;
3595
3596
  createdAt: Date;
3596
3597
  updatedAt: Date;
3597
- metadata: Record<string, any> | null;
3598
- category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3598
+ category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3599
3599
  }>;
3600
3600
  }
3601
3601
  declare const permissionsRepository: PermissionsRepository;
@@ -3640,9 +3640,9 @@ declare class RolePermissionsRepository extends BaseRepository {
3640
3640
  */
3641
3641
  createMany(data: NewRolePermission[]): Promise<{
3642
3642
  id: number;
3643
+ roleId: number;
3643
3644
  createdAt: Date;
3644
3645
  updatedAt: Date;
3645
- roleId: number;
3646
3646
  permissionId: number;
3647
3647
  }[]>;
3648
3648
  /**
@@ -3658,9 +3658,9 @@ declare class RolePermissionsRepository extends BaseRepository {
3658
3658
  */
3659
3659
  setPermissionsForRole(roleId: number, permissionIds: number[]): Promise<{
3660
3660
  id: number;
3661
+ roleId: number;
3661
3662
  createdAt: Date;
3662
3663
  updatedAt: Date;
3663
- roleId: number;
3664
3664
  permissionId: number;
3665
3665
  }[]>;
3666
3666
  }
@@ -3725,10 +3725,10 @@ declare class UserPermissionsRepository extends BaseRepository {
3725
3725
  id: number;
3726
3726
  createdAt: Date;
3727
3727
  updatedAt: Date;
3728
- expiresAt: Date | null;
3729
3728
  permissionId: number;
3730
- granted: boolean;
3729
+ expiresAt: Date | null;
3731
3730
  reason: string | null;
3731
+ granted: boolean;
3732
3732
  }>;
3733
3733
  /**
3734
3734
  * 사용자 권한 오버라이드 업데이트
@@ -3751,10 +3751,10 @@ declare class UserPermissionsRepository extends BaseRepository {
3751
3751
  id: number;
3752
3752
  createdAt: Date;
3753
3753
  updatedAt: Date;
3754
- expiresAt: Date | null;
3755
3754
  permissionId: number;
3756
- granted: boolean;
3755
+ expiresAt: Date | null;
3757
3756
  reason: string | null;
3757
+ granted: boolean;
3758
3758
  }>;
3759
3759
  /**
3760
3760
  * 사용자의 모든 권한 오버라이드 삭제
@@ -3786,7 +3786,7 @@ declare class UserProfilesRepository extends BaseRepository {
3786
3786
  updatedAt: Date;
3787
3787
  id: number;
3788
3788
  userId: number;
3789
- displayName: string;
3789
+ displayName: string | null;
3790
3790
  firstName: string | null;
3791
3791
  lastName: string | null;
3792
3792
  avatarUrl: string | null;
@@ -3813,7 +3813,7 @@ declare class UserProfilesRepository extends BaseRepository {
3813
3813
  updatedAt: Date;
3814
3814
  id: number;
3815
3815
  userId: number;
3816
- displayName: string;
3816
+ displayName: string | null;
3817
3817
  firstName: string | null;
3818
3818
  lastName: string | null;
3819
3819
  avatarUrl: string | null;
@@ -3832,9 +3832,10 @@ declare class UserProfilesRepository extends BaseRepository {
3832
3832
  * 프로필 생성
3833
3833
  */
3834
3834
  create(data: NewUserProfile): Promise<{
3835
+ metadata: Record<string, any> | null;
3835
3836
  userId: number;
3836
3837
  id: number;
3837
- displayName: string;
3838
+ displayName: string | null;
3838
3839
  createdAt: Date;
3839
3840
  updatedAt: Date;
3840
3841
  firstName: string | null;
@@ -3849,7 +3850,6 @@ declare class UserProfilesRepository extends BaseRepository {
3849
3850
  location: string | null;
3850
3851
  company: string | null;
3851
3852
  jobTitle: string | null;
3852
- metadata: Record<string, any> | null;
3853
3853
  }>;
3854
3854
  /**
3855
3855
  * 프로필 업데이트 (by ID)
@@ -3859,7 +3859,7 @@ declare class UserProfilesRepository extends BaseRepository {
3859
3859
  updatedAt: Date;
3860
3860
  id: number;
3861
3861
  userId: number;
3862
- displayName: string;
3862
+ displayName: string | null;
3863
3863
  firstName: string | null;
3864
3864
  lastName: string | null;
3865
3865
  avatarUrl: string | null;
@@ -3882,7 +3882,7 @@ declare class UserProfilesRepository extends BaseRepository {
3882
3882
  updatedAt: Date;
3883
3883
  id: number;
3884
3884
  userId: number;
3885
- displayName: string;
3885
+ displayName: string | null;
3886
3886
  firstName: string | null;
3887
3887
  lastName: string | null;
3888
3888
  avatarUrl: string | null;
@@ -3901,9 +3901,10 @@ declare class UserProfilesRepository extends BaseRepository {
3901
3901
  * 프로필 삭제 (by ID)
3902
3902
  */
3903
3903
  deleteById(id: number): Promise<{
3904
+ metadata: Record<string, any> | null;
3904
3905
  userId: number;
3905
3906
  id: number;
3906
- displayName: string;
3907
+ displayName: string | null;
3907
3908
  createdAt: Date;
3908
3909
  updatedAt: Date;
3909
3910
  firstName: string | null;
@@ -3918,15 +3919,15 @@ declare class UserProfilesRepository extends BaseRepository {
3918
3919
  location: string | null;
3919
3920
  company: string | null;
3920
3921
  jobTitle: string | null;
3921
- metadata: Record<string, any> | null;
3922
3922
  }>;
3923
3923
  /**
3924
3924
  * 프로필 삭제 (by User ID)
3925
3925
  */
3926
3926
  deleteByUserId(userId: number): Promise<{
3927
+ metadata: Record<string, any> | null;
3927
3928
  userId: number;
3928
3929
  id: number;
3929
- displayName: string;
3930
+ displayName: string | null;
3930
3931
  createdAt: Date;
3931
3932
  updatedAt: Date;
3932
3933
  firstName: string | null;
@@ -3941,7 +3942,6 @@ declare class UserProfilesRepository extends BaseRepository {
3941
3942
  location: string | null;
3942
3943
  company: string | null;
3943
3944
  jobTitle: string | null;
3944
- metadata: Record<string, any> | null;
3945
3945
  }>;
3946
3946
  /**
3947
3947
  * 프로필 Upsert (by User ID)
@@ -3950,9 +3950,10 @@ declare class UserProfilesRepository extends BaseRepository {
3950
3950
  * 새로 생성 시 displayName은 필수 (없으면 'User'로 설정)
3951
3951
  */
3952
3952
  upsertByUserId(userId: number, data: Partial<Omit<NewUserProfile, 'userId'>>): Promise<{
3953
+ metadata: Record<string, any> | null;
3953
3954
  userId: number;
3954
3955
  id: number;
3955
- displayName: string;
3956
+ displayName: string | null;
3956
3957
  createdAt: Date;
3957
3958
  updatedAt: Date;
3958
3959
  firstName: string | null;
@@ -3967,7 +3968,6 @@ declare class UserProfilesRepository extends BaseRepository {
3967
3968
  location: string | null;
3968
3969
  company: string | null;
3969
3970
  jobTitle: string | null;
3970
- metadata: Record<string, any> | null;
3971
3971
  }>;
3972
3972
  /**
3973
3973
  * User ID로 프로필 데이터 조회 (formatted)
@@ -3976,7 +3976,7 @@ declare class UserProfilesRepository extends BaseRepository {
3976
3976
  */
3977
3977
  fetchProfileData(userId: number): Promise<{
3978
3978
  profileId: number;
3979
- displayName: string;
3979
+ displayName: string | null;
3980
3980
  firstName: string | null;
3981
3981
  lastName: string | null;
3982
3982
  avatarUrl: string | null;
@@ -4094,16 +4094,16 @@ declare class InvitationsRepository extends BaseRepository {
4094
4094
  * 초대 생성
4095
4095
  */
4096
4096
  create(data: NewInvitation): Promise<{
4097
- status: "pending" | "accepted" | "expired" | "cancelled";
4098
4097
  email: string;
4098
+ metadata: Record<string, any> | null;
4099
4099
  id: number;
4100
+ roleId: number;
4100
4101
  createdAt: Date;
4101
4102
  updatedAt: Date;
4102
- roleId: number;
4103
- metadata: Record<string, any> | null;
4104
- expiresAt: Date;
4103
+ status: "pending" | "accepted" | "expired" | "cancelled";
4105
4104
  token: string;
4106
4105
  invitedBy: number;
4106
+ expiresAt: Date;
4107
4107
  acceptedAt: Date | null;
4108
4108
  cancelledAt: Date | null;
4109
4109
  }>;
@@ -4128,16 +4128,16 @@ declare class InvitationsRepository extends BaseRepository {
4128
4128
  * 초대 삭제
4129
4129
  */
4130
4130
  deleteById(id: number): Promise<{
4131
- status: "pending" | "accepted" | "expired" | "cancelled";
4132
4131
  email: string;
4132
+ metadata: Record<string, any> | null;
4133
4133
  id: number;
4134
+ roleId: number;
4134
4135
  createdAt: Date;
4135
4136
  updatedAt: Date;
4136
- roleId: number;
4137
- metadata: Record<string, any> | null;
4138
- expiresAt: Date;
4137
+ status: "pending" | "accepted" | "expired" | "cancelled";
4139
4138
  token: string;
4140
4139
  invitedBy: number;
4140
+ expiresAt: Date;
4141
4141
  acceptedAt: Date | null;
4142
4142
  cancelledAt: Date | null;
4143
4143
  }>;
@@ -4802,16 +4802,16 @@ declare function getOptionalAuth(c: Context | {
4802
4802
  declare function getUser(c: Context | {
4803
4803
  raw: Context;
4804
4804
  }): {
4805
- username: string | null;
4806
- status: "active" | "inactive" | "suspended";
4807
4805
  email: string | null;
4808
4806
  phone: string | null;
4809
4807
  id: number;
4810
- createdAt: Date;
4811
- updatedAt: Date;
4808
+ username: string | null;
4812
4809
  passwordHash: string | null;
4813
4810
  passwordChangeRequired: boolean;
4814
4811
  roleId: number;
4812
+ createdAt: Date;
4813
+ updatedAt: Date;
4814
+ status: "active" | "inactive" | "suspended";
4815
4815
  emailVerifiedAt: Date | null;
4816
4816
  phoneVerifiedAt: Date | null;
4817
4817
  lastLoginAt: Date | null;
@@ -5341,9 +5341,9 @@ declare const invitationCreatedEvent: _spfn_core_event.EventDef<{
5341
5341
  } | undefined;
5342
5342
  email: string;
5343
5343
  roleId: number;
5344
- expiresAt: string;
5345
5344
  token: string;
5346
5345
  invitedBy: string;
5346
+ expiresAt: string;
5347
5347
  invitationId: string;
5348
5348
  isResend: boolean;
5349
5349
  }>;
package/dist/server.js CHANGED
@@ -4653,8 +4653,8 @@ var init_user_profiles = __esm({
4653
4653
  // Foreign key to users table
4654
4654
  userId: foreignKey2("user", () => users.id).unique(),
4655
4655
  // Display Information
4656
- // Display name shown in UI (required)
4657
- displayName: text3("display_name").notNull(),
4656
+ // Display name shown in UI (optional)
4657
+ displayName: text3("display_name"),
4658
4658
  // First name (optional)
4659
4659
  firstName: text3("first_name"),
4660
4660
  // Last name (optional)
@@ -7813,7 +7813,7 @@ async function updateUserProfileService(userId, params) {
7813
7813
  const userIdNum = typeof userId === "string" ? Number(userId) : Number(userId);
7814
7814
  const updateData = {};
7815
7815
  if (params.displayName !== void 0) {
7816
- updateData.displayName = emptyToNull(params.displayName) || "User";
7816
+ updateData.displayName = emptyToNull(params.displayName);
7817
7817
  }
7818
7818
  if (params.firstName !== void 0) {
7819
7819
  updateData.firstName = emptyToNull(params.firstName);
@@ -7854,10 +7854,6 @@ async function updateUserProfileService(userId, params) {
7854
7854
  if (params.metadata !== void 0) {
7855
7855
  updateData.metadata = params.metadata;
7856
7856
  }
7857
- const existing = await userProfilesRepository.findByUserId(userIdNum);
7858
- if (!existing && !updateData.displayName) {
7859
- updateData.displayName = "User";
7860
- }
7861
7857
  await userProfilesRepository.upsertByUserId(userIdNum, updateData);
7862
7858
  const profile = await userProfilesRepository.fetchProfileData(userIdNum);
7863
7859
  return profile;