@open-mercato/enterprise 0.4.11-develop.2631.481e9df5b0 → 0.5.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/modules/record_locks/lib/recordLockService.js +1 -1
- package/dist/modules/record_locks/lib/recordLockService.js.map +1 -1
- package/dist/modules/security/api/admin/route.js +5 -0
- package/dist/modules/security/api/admin/route.js.map +2 -2
- package/dist/modules/security/lib/providers/PasskeyProvider.js +2 -2
- package/dist/modules/security/lib/providers/PasskeyProvider.js.map +2 -2
- package/dist/modules/sso/api/callback/oidc/route.js +5 -0
- package/dist/modules/sso/api/callback/oidc/route.js.map +2 -2
- package/dist/modules/sso/api/hrd/route.js +4 -0
- package/dist/modules/sso/api/hrd/route.js.map +2 -2
- package/dist/modules/sso/api/initiate/route.js +4 -0
- package/dist/modules/sso/api/initiate/route.js.map +2 -2
- package/package.json +17 -13
- package/src/modules/security/api/admin/route.ts +5 -0
- package/src/modules/security/lib/providers/PasskeyProvider.ts +4 -4
- package/src/modules/sso/api/callback/oidc/route.ts +5 -0
- package/src/modules/sso/api/hrd/route.ts +4 -0
- package/src/modules/sso/api/initiate/route.ts +4 -0
|
@@ -106,7 +106,7 @@ function shouldSkipConflictField(path) {
|
|
|
106
106
|
if (!segments.length) return true;
|
|
107
107
|
return SKIPPED_CONFLICT_FIELDS.has(segments[segments.length - 1] ?? "");
|
|
108
108
|
}
|
|
109
|
-
const MISSING_CONFLICT_VALUE = Symbol("record_lock_conflict_missing_value");
|
|
109
|
+
const MISSING_CONFLICT_VALUE = /* @__PURE__ */ Symbol("record_lock_conflict_missing_value");
|
|
110
110
|
function isRecordValue(value) {
|
|
111
111
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
112
112
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/record_locks/lib/recordLockService.ts"],
|
|
4
4
|
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport { UniqueConstraintViolationException, type FilterQuery } from '@mikro-orm/core'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Knex } from 'knex'\nimport type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'\nimport type { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { emitRecordLocksEvent } from '../events'\nimport {\n RecordLock,\n RecordLockConflict,\n type RecordLockStatus,\n type RecordLockReleaseReason,\n type RecordLockConflictResolution,\n type RecordLockConflictStatus,\n} from '../data/entities'\nimport {\n recordLockMutationHeaderSchema,\n type RecordLockMutationHeaders,\n type RecordLockReleaseInput as RecordLockReleasePayloadInput,\n type RecordLockSettingsInput,\n} from '../data/validators'\nimport {\n DEFAULT_RECORD_LOCK_SETTINGS,\n RECORD_LOCKS_MODULE_ID,\n RECORD_LOCKS_SETTINGS_NAME,\n isRecordLockingEnabledForResource,\n normalizeRecordLockSettings,\n type RecordLockSettings,\n type RecordLockStrategy,\n} from './config'\n\nconst ACTIVE_LOCK_STATUS: RecordLockStatus = 'active'\nconst ACTIVE_SCOPE_UNIQUE_CONSTRAINTS = new Set([\n 'record_locks_active_scope_org_unique',\n 'record_locks_active_scope_tenant_unique',\n 'record_locks_active_scope_user_org_unique',\n 'record_locks_active_scope_user_tenant_unique',\n])\nconst LOCK_CONTENTION_EVENT_TTL_MS = 15_000\nconst PARTICIPANT_REJOIN_AFTER_SAVE_SUPPRESS_MS = 20_000\nconst LOCK_CONTENTION_EVENT_MAX_ENTRIES = 2_000\nconst lockContentionEventThrottle = new Map<string, number>()\nconst LOCK_CLEANUP_INTERVAL_MS = 5 * 60 * 1000\nconst LOCK_RETENTION_MS = 3 * 24 * 60 * 60 * 1000\nconst RESOLVED_CONFLICT_RETENTION_MS = 7 * 24 * 60 * 60 * 1000\nconst PENDING_CONFLICT_RETENTION_MS = 24 * 60 * 60 * 1000\nconst LOCK_CLEANUP_STATE_TTL_MS = 24 * 60 * 60 * 1000\nconst LOCK_CLEANUP_STATE_MAX_ENTRIES = 2_000\nconst lockCleanupStateByTenant = new Map<string, { lastRunAt: number; inFlight: boolean; lastSeenAt: number }>()\n\nexport type RecordLockScope = {\n tenantId: string\n organizationId?: string | null\n userId: string\n}\n\nexport type RecordLockResource = {\n resourceKind: string\n resourceId: string\n}\n\nexport type RecordLockAcquireInput = RecordLockScope & RecordLockResource & {\n lockedByIp?: string | null\n}\n\nexport type RecordLockHeartbeatInput = RecordLockScope & RecordLockResource & {\n token: string\n}\n\nexport type RecordLockReleaseInput = RecordLockScope & RecordLockResource & {\n token?: string\n reason?: Exclude<RecordLockReleaseReason, 'expired' | 'force'>\n} & Pick<RecordLockReleasePayloadInput, 'conflictId' | 'resolution'>\n\nexport type RecordLockForceReleaseInput = RecordLockScope & RecordLockResource & {\n reason?: string | null\n}\n\nexport type RecordLockMutationValidationInput = RecordLockScope & RecordLockResource & {\n method: 'PUT' | 'DELETE'\n headers: Partial<RecordLockMutationHeaders>\n mutationPayload?: Record<string, unknown> | null\n}\n\nexport type RecordLockConflictChange = {\n field: string\n displayValue: unknown\n baseValue: unknown\n incomingValue: unknown\n mineValue: unknown\n}\n\nexport type RecordLockConflictPayload = {\n id: string\n resourceKind: string\n resourceId: string\n baseActionLogId: string | null\n incomingActionLogId: string | null\n allowIncomingOverride: boolean\n canOverrideIncoming: boolean\n resolutionOptions: Array<'accept_mine'>\n changes: RecordLockConflictChange[]\n}\n\nexport type RecordLockView = {\n id: string\n resourceKind: string\n resourceId: string\n token: string | null\n strategy: RecordLockStrategy\n status: RecordLockStatus\n lockedByUserId: string\n lockedByIp: string | null\n baseActionLogId: string | null\n lockedAt: string\n lastHeartbeatAt: string\n expiresAt: string\n participants: RecordLockParticipantView[]\n activeParticipantCount: number\n}\n\nexport type RecordLockParticipantView = {\n userId: string\n lockedByIp: string | null\n lockedAt: string\n lastHeartbeatAt: string\n expiresAt: string\n}\n\nexport type RecordLockAcquireResult = {\n ok: true\n enabled: boolean\n resourceEnabled: boolean\n strategy: RecordLockStrategy\n allowForceUnlock: boolean\n heartbeatSeconds: number\n acquired: boolean\n latestActionLogId: string | null\n lock: RecordLockView | null\n}\n\nexport type RecordLockAcquireFailure = RecordLockValidationFailure & {\n allowForceUnlock: boolean\n}\n\nexport type RecordLockHeartbeatResult = {\n ok: true\n expiresAt: string | null\n}\n\nexport type RecordLockReleaseResult = {\n ok: true\n released: boolean\n conflictResolved: boolean\n}\n\nexport type RecordLockForceReleaseResult = {\n ok: true\n released: boolean\n lock: RecordLockView | null\n}\n\nexport type RecordLockValidationSuccess = {\n ok: true\n enabled: boolean\n resourceEnabled: boolean\n strategy: RecordLockStrategy\n shouldReleaseOnSuccess: boolean\n lock: RecordLockView | null\n latestActionLogId: string | null\n}\n\nexport type RecordLockValidationFailure = {\n ok: false\n status: 409 | 423\n error: string\n code: 'record_lock_conflict' | 'record_locked'\n lock: RecordLockView | null\n conflict?: RecordLockConflictPayload\n}\n\nexport type RecordLockValidationResult = RecordLockValidationSuccess | RecordLockValidationFailure\n\nexport type RecordLockServiceDeps = {\n em: EntityManager\n moduleConfigService?: ModuleConfigService | null\n actionLogService?: ActionLogService | null\n rbacService?: RbacService | null\n}\n\nexport type ParsedRecordLockHeaders = Partial<RecordLockMutationHeaders>\n\nfunction normalizeDate(value: Date): string {\n return value.toISOString()\n}\n\nfunction trimToNull(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nfunction normalizeScopeOrganization(value: string | null | undefined): string | null {\n const trimmed = trimToNull(value)\n return trimmed ?? null\n}\n\nfunction shouldEmitLockContentionEvent(input: {\n tenantId: string\n organizationId?: string | null\n resourceKind: string\n resourceId: string\n lockedByUserId: string\n attemptedByUserId: string\n}): boolean {\n if (process.env.NODE_ENV === 'test') return true\n const now = Date.now()\n const key = [\n input.tenantId,\n normalizeScopeOrganization(input.organizationId) ?? 'global',\n input.resourceKind,\n input.resourceId,\n input.lockedByUserId,\n input.attemptedByUserId,\n ].join('|')\n\n const lastEmittedAt = lockContentionEventThrottle.get(key)\n if (typeof lastEmittedAt === 'number' && now - lastEmittedAt < LOCK_CONTENTION_EVENT_TTL_MS) {\n return false\n }\n\n lockContentionEventThrottle.set(key, now)\n\n for (const [cachedKey, cachedAt] of lockContentionEventThrottle.entries()) {\n if (now - cachedAt > LOCK_CONTENTION_EVENT_TTL_MS) {\n lockContentionEventThrottle.delete(cachedKey)\n }\n }\n if (lockContentionEventThrottle.size > LOCK_CONTENTION_EVENT_MAX_ENTRIES) {\n const oldest = Array.from(lockContentionEventThrottle.entries())\n .sort((left, right) => left[1] - right[1])\n .slice(0, lockContentionEventThrottle.size - LOCK_CONTENTION_EVENT_MAX_ENTRIES)\n for (const [staleKey] of oldest) lockContentionEventThrottle.delete(staleKey)\n }\n\n return true\n}\n\nfunction isActiveLockScopeUniqueViolation(error: unknown): boolean {\n if (error instanceof UniqueConstraintViolationException) {\n const errorWithConstraint = error as unknown as { constraint?: unknown }\n const constraint = typeof errorWithConstraint.constraint === 'string'\n ? errorWithConstraint.constraint\n : null\n if (constraint && ACTIVE_SCOPE_UNIQUE_CONSTRAINTS.has(constraint)) return true\n }\n if (!error || typeof error !== 'object') return false\n const code = (error as { code?: unknown }).code\n if (code !== '23505') return false\n const message = typeof (error as { message?: unknown }).message === 'string'\n ? (error as { message: string }).message.toLowerCase()\n : ''\n for (const constraint of ACTIVE_SCOPE_UNIQUE_CONSTRAINTS) {\n if (message.includes(constraint)) return true\n }\n return false\n}\n\nfunction getKnex(em: EntityManager): Knex {\n return (em.getConnection() as unknown as { getKnex: () => Knex }).getKnex()\n}\n\nconst SKIPPED_CONFLICT_FIELDS = new Set([\n 'updatedAt',\n 'updated_at',\n 'createdAt',\n 'created_at',\n 'deletedAt',\n 'deleted_at',\n])\n\nfunction shouldSkipConflictField(path: string): boolean {\n if (!path.trim().length) return true\n if (SKIPPED_CONFLICT_FIELDS.has(path)) return true\n const segments = path.split('.').filter((segment) => segment.length > 0)\n if (!segments.length) return true\n return SKIPPED_CONFLICT_FIELDS.has(segments[segments.length - 1] ?? '')\n}\n\nconst MISSING_CONFLICT_VALUE = Symbol('record_lock_conflict_missing_value')\n\nfunction isRecordValue(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === 'object' && !Array.isArray(value))\n}\n\nfunction toIsoDate(value: unknown): string | null {\n if (value instanceof Date) {\n if (Number.isNaN(value.getTime())) return null\n return value.toISOString()\n }\n if (typeof value === 'string') {\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString()\n }\n return null\n}\n\nfunction valuesEqual(a: unknown, b: unknown, seen?: Set<unknown>): boolean {\n if (Object.is(a, b)) return true\n\n if (a instanceof Date || b instanceof Date) {\n const left = toIsoDate(a)\n const right = toIsoDate(b)\n return left !== null && right !== null && left === right\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let index = 0; index < a.length; index += 1) {\n if (!valuesEqual(a[index], b[index], seen)) return false\n }\n return true\n }\n\n if (isRecordValue(a) && isRecordValue(b)) {\n if (!seen) seen = new Set()\n if (seen.has(a) || seen.has(b)) return false\n seen.add(a)\n seen.add(b)\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) return false\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n if (!valuesEqual(a[key], b[key], seen)) return false\n }\n return true\n }\n\n return false\n}\n\nfunction readPathValue(source: unknown, path: string): unknown | typeof MISSING_CONFLICT_VALUE {\n if (!path.trim().length || !isRecordValue(source)) return MISSING_CONFLICT_VALUE\n if (Object.prototype.hasOwnProperty.call(source, path)) return source[path]\n\n const segments = path.split('.').filter((segment) => segment.length > 0)\n if (!segments.length) return MISSING_CONFLICT_VALUE\n\n let current: unknown = source\n for (const segment of segments) {\n if (!isRecordValue(current)) return MISSING_CONFLICT_VALUE\n if (!Object.prototype.hasOwnProperty.call(current, segment)) return MISSING_CONFLICT_VALUE\n current = current[segment]\n }\n return current\n}\n\nfunction buildPathVariants(path: string): string[] {\n const trimmed = path.trim()\n if (!trimmed.length) return []\n\n const segments = trimmed.split('.').filter((segment) => segment.length > 0)\n if (segments.length <= 1) return [trimmed]\n\n const variants = new Set<string>([trimmed])\n for (let index = 1; index < segments.length; index += 1) {\n variants.add(segments.slice(index).join('.'))\n }\n return Array.from(variants)\n}\n\nfunction readPathValueLoose(source: unknown, path: string): unknown | typeof MISSING_CONFLICT_VALUE {\n const variants = buildPathVariants(path)\n for (const variant of variants) {\n const value = readPathValue(source, variant)\n if (value !== MISSING_CONFLICT_VALUE) return value\n }\n return MISSING_CONFLICT_VALUE\n}\n\nfunction normalizeConflictValue(value: unknown): unknown {\n return value === undefined ? null : value\n}\n\nfunction formatNotificationValue(value: unknown): string {\n if (value === null || value === undefined) return '-'\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n if (value instanceof Date) return value.toISOString()\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\nfunction formatChangedFieldLabel(rawField: string): string {\n const trimmedField = rawField.trim()\n const withoutNamespace = trimmedField.includes('::') ? (trimmedField.split('::').pop() ?? trimmedField) : trimmedField\n const withoutPrefix = withoutNamespace.includes('.') ? (withoutNamespace.split('.').pop() ?? withoutNamespace) : withoutNamespace\n const words = withoutPrefix\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[._-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .split(' ')\n .filter(Boolean)\n\n if (!words.length) return trimmedField\n return words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n}\n\nexport function readRecordLockHeaders(headers: Headers): ParsedRecordLockHeaders {\n const raw = {\n resourceKind: trimToNull(headers.get('x-om-record-lock-kind')) ?? undefined,\n resourceId: trimToNull(headers.get('x-om-record-lock-resource-id')) ?? undefined,\n token: trimToNull(headers.get('x-om-record-lock-token')) ?? undefined,\n baseLogId: trimToNull(headers.get('x-om-record-lock-base-log-id')) ?? undefined,\n resolution: trimToNull(headers.get('x-om-record-lock-resolution')) ?? undefined,\n conflictId: trimToNull(headers.get('x-om-record-lock-conflict-id')) ?? undefined,\n }\n\n const parsed = recordLockMutationHeaderSchema.partial().safeParse(raw)\n if (!parsed.success) return {}\n return parsed.data\n}\n\nexport class RecordLockService {\n private readonly em: EntityManager\n\n private readonly moduleConfigService: ModuleConfigService | null\n\n private readonly actionLogService: ActionLogService | null\n\n private readonly rbacService: RbacService | null\n\n constructor(deps: RecordLockServiceDeps) {\n this.em = deps.em\n this.moduleConfigService = deps.moduleConfigService ?? null\n this.actionLogService = deps.actionLogService ?? null\n this.rbacService = deps.rbacService ?? null\n }\n\n async getSettings(): Promise<RecordLockSettings> {\n if (!this.moduleConfigService) return DEFAULT_RECORD_LOCK_SETTINGS\n\n const value = await this.moduleConfigService.getValue<RecordLockSettings>(\n RECORD_LOCKS_MODULE_ID,\n RECORD_LOCKS_SETTINGS_NAME,\n { defaultValue: DEFAULT_RECORD_LOCK_SETTINGS },\n )\n\n return normalizeRecordLockSettings(value ?? DEFAULT_RECORD_LOCK_SETTINGS)\n }\n\n async saveSettings(input: RecordLockSettingsInput): Promise<RecordLockSettings> {\n const settings = normalizeRecordLockSettings(input)\n if (!this.moduleConfigService) return settings\n\n await this.moduleConfigService.setValue(RECORD_LOCKS_MODULE_ID, RECORD_LOCKS_SETTINGS_NAME, settings)\n return settings // NOSONAR \u2014 both paths return settings by design; the branch controls persistence\n }\n\n async acquire(input: RecordLockAcquireInput): Promise<RecordLockAcquireResult | RecordLockAcquireFailure> {\n this.scheduleCleanup(input.tenantId)\n const settings = await this.getSettings()\n const latest = await this.findLatestActionLogWithScopeFallback(input)\n const resourceEnabled = isRecordLockingEnabledForResource(settings, input.resourceKind)\n\n if (!resourceEnabled) {\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: false,\n strategy: settings.strategy,\n allowForceUnlock: settings.allowForceUnlock,\n heartbeatSeconds: settings.heartbeatSeconds,\n acquired: false,\n latestActionLogId: latest?.id ?? null,\n lock: null,\n }\n }\n\n const now = new Date()\n let activeLocks = await this.findActiveLocks(input, now)\n const ownedActiveLock = activeLocks.find((lock) => lock.lockedByUserId === input.userId) ?? null\n const competingActiveLock = activeLocks.find((lock) => lock.lockedByUserId !== input.userId) ?? null\n\n if (settings.strategy === 'pessimistic' && !ownedActiveLock && competingActiveLock) {\n const lockView = this.toLockView(competingActiveLock, false, activeLocks)\n if (shouldEmitLockContentionEvent({\n tenantId: competingActiveLock.tenantId,\n organizationId: competingActiveLock.organizationId,\n resourceKind: competingActiveLock.resourceKind,\n resourceId: competingActiveLock.resourceId,\n lockedByUserId: competingActiveLock.lockedByUserId,\n attemptedByUserId: input.userId,\n })) {\n await emitRecordLocksEvent('record_locks.lock.contended', {\n lockId: competingActiveLock.id,\n resourceKind: competingActiveLock.resourceKind,\n resourceId: competingActiveLock.resourceId,\n tenantId: competingActiveLock.tenantId,\n organizationId: competingActiveLock.organizationId,\n lockedByUserId: competingActiveLock.lockedByUserId,\n attemptedByUserId: input.userId,\n })\n }\n return {\n ok: false,\n status: 423,\n error: 'Record is currently locked by another user',\n code: 'record_locked',\n allowForceUnlock: settings.allowForceUnlock,\n lock: lockView,\n }\n }\n\n if (ownedActiveLock) {\n ownedActiveLock.strategy = settings.strategy\n ownedActiveLock.lockedByIp = input.lockedByIp ?? ownedActiveLock.lockedByIp ?? null\n ownedActiveLock.lastHeartbeatAt = now\n ownedActiveLock.expiresAt = new Date(now.getTime() + settings.timeoutSeconds * 1000)\n await this.em.flush()\n\n activeLocks = await this.findActiveLocks(input, now)\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n allowForceUnlock: settings.allowForceUnlock,\n heartbeatSeconds: settings.heartbeatSeconds,\n acquired: false,\n latestActionLogId: latest?.id ?? null,\n lock: this.toLockView(ownedActiveLock, true, activeLocks),\n }\n }\n\n const lock = this.em.create(RecordLock, {\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n token: randomUUID(),\n strategy: settings.strategy,\n status: ACTIVE_LOCK_STATUS,\n lockedByUserId: input.userId,\n lockedByIp: input.lockedByIp ?? null,\n baseActionLogId: latest?.id ?? null,\n lockedAt: now,\n lastHeartbeatAt: now,\n expiresAt: new Date(now.getTime() + settings.timeoutSeconds * 1000),\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n })\n\n this.em.persist(lock)\n let createdNewLock = true\n try {\n await this.em.flush()\n } catch (error) {\n if (!isActiveLockScopeUniqueViolation(error)) throw error\n const clear = (this.em as { clear?: () => void }).clear\n if (typeof clear === 'function') clear.call(this.em)\n const locksAfterCollision = await this.findActiveLocks(input, now)\n const competingAfterCollision = locksAfterCollision.find((item) => item.lockedByUserId !== input.userId) ?? null\n if (settings.strategy === 'pessimistic' && competingAfterCollision) {\n if (shouldEmitLockContentionEvent({\n tenantId: competingAfterCollision.tenantId,\n organizationId: competingAfterCollision.organizationId,\n resourceKind: competingAfterCollision.resourceKind,\n resourceId: competingAfterCollision.resourceId,\n lockedByUserId: competingAfterCollision.lockedByUserId,\n attemptedByUserId: input.userId,\n })) {\n await emitRecordLocksEvent('record_locks.lock.contended', {\n lockId: competingAfterCollision.id,\n resourceKind: competingAfterCollision.resourceKind,\n resourceId: competingAfterCollision.resourceId,\n tenantId: competingAfterCollision.tenantId,\n organizationId: competingAfterCollision.organizationId,\n lockedByUserId: competingAfterCollision.lockedByUserId,\n attemptedByUserId: input.userId,\n })\n }\n return {\n ok: false,\n status: 423,\n error: 'Record is currently locked by another user',\n code: 'record_locked',\n allowForceUnlock: settings.allowForceUnlock,\n lock: this.toLockView(competingAfterCollision, false, locksAfterCollision),\n }\n }\n const existingOwned = await this.findOwnedActiveLock(input)\n if (!existingOwned) throw error\n existingOwned.strategy = settings.strategy\n existingOwned.lockedByIp = input.lockedByIp ?? existingOwned.lockedByIp ?? null\n existingOwned.lastHeartbeatAt = now\n existingOwned.expiresAt = new Date(now.getTime() + settings.timeoutSeconds * 1000)\n await this.em.flush()\n createdNewLock = false\n }\n\n const activeAfterAcquire = await this.findActiveLocks(input, now)\n const ownedAfterAcquire = activeAfterAcquire.find((item) => item.lockedByUserId === input.userId)\n ?? await this.findOwnedActiveLock(input)\n ?? lock\n ?? null\n if (!ownedAfterAcquire) {\n const fallbackLock = activeAfterAcquire[0] ?? null\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n allowForceUnlock: settings.allowForceUnlock,\n heartbeatSeconds: settings.heartbeatSeconds,\n acquired: false,\n latestActionLogId: latest?.id ?? null,\n lock: fallbackLock ? this.toLockView(fallbackLock, false, activeAfterAcquire) : null,\n }\n }\n\n if (createdNewLock) {\n await emitRecordLocksEvent('record_locks.lock.acquired', {\n lockId: ownedAfterAcquire.id,\n resourceKind: ownedAfterAcquire.resourceKind,\n resourceId: ownedAfterAcquire.resourceId,\n tenantId: ownedAfterAcquire.tenantId,\n organizationId: ownedAfterAcquire.organizationId,\n lockedByUserId: ownedAfterAcquire.lockedByUserId,\n strategy: ownedAfterAcquire.strategy,\n baseActionLogId: ownedAfterAcquire.baseActionLogId,\n activeParticipantCount: activeAfterAcquire.length,\n })\n\n const recipientUserIds = activeAfterAcquire\n .filter((item) => item.lockedByUserId !== input.userId)\n .map((item) => item.lockedByUserId)\n const shouldSuppressJoinNotification = await this.hasRecentSavedRelease({\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n now,\n })\n\n if (!shouldSuppressJoinNotification) {\n await emitRecordLocksEvent('record_locks.participant.joined', {\n lockId: ownedAfterAcquire.id,\n resourceKind: ownedAfterAcquire.resourceKind,\n resourceId: ownedAfterAcquire.resourceId,\n tenantId: ownedAfterAcquire.tenantId,\n organizationId: ownedAfterAcquire.organizationId,\n joinedUserId: input.userId,\n joinedIp: ownedAfterAcquire.lockedByIp ?? null,\n recipientUserIds,\n activeParticipantCount: activeAfterAcquire.length,\n })\n }\n }\n\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n allowForceUnlock: settings.allowForceUnlock,\n heartbeatSeconds: settings.heartbeatSeconds,\n acquired: createdNewLock,\n latestActionLogId: latest?.id ?? null,\n lock: this.toLockView(ownedAfterAcquire, true, activeAfterAcquire),\n }\n }\n\n async heartbeat(input: RecordLockHeartbeatInput): Promise<RecordLockHeartbeatResult> {\n const settings = await this.getSettings()\n const resourceEnabled = isRecordLockingEnabledForResource(settings, input.resourceKind)\n if (!resourceEnabled) return { ok: true, expiresAt: null }\n\n const lock = await this.findOwnedLockByToken(input)\n if (!lock) return { ok: true, expiresAt: null }\n\n const now = new Date()\n if (lock.expiresAt <= now) {\n this.markLockReleased(lock, {\n status: 'expired',\n reason: 'expired',\n releasedByUserId: lock.lockedByUserId,\n now,\n })\n await this.em.flush()\n return { ok: true, expiresAt: null }\n }\n\n lock.lastHeartbeatAt = now\n lock.expiresAt = new Date(now.getTime() + settings.timeoutSeconds * 1000)\n await this.em.flush()\n return { ok: true, expiresAt: normalizeDate(lock.expiresAt) }\n }\n\n async release(input: RecordLockReleaseInput): Promise<RecordLockReleaseResult> {\n const settings = await this.getSettings()\n const resourceEnabled = isRecordLockingEnabledForResource(settings, input.resourceKind)\n if (!resourceEnabled) return { ok: true, released: false, conflictResolved: false }\n\n let conflictResolved = false\n if (input.reason === 'conflict_resolved' && input.conflictId && input.resolution === 'accept_incoming') {\n const conflict = await this.findConflictById(input.conflictId, input)\n if (conflict && conflict.status === 'pending' && conflict.conflictActorUserId === input.userId) {\n await this.resolveConflict(conflict, input.resolution, input.userId)\n conflictResolved = true\n }\n }\n\n const lock = input.token\n ? await this.findOwnedLockByToken(input)\n : await this.findOwnedActiveLock(input)\n if (!lock) return { ok: true, released: false, conflictResolved }\n\n const now = new Date()\n this.markLockReleased(lock, {\n status: 'released',\n reason: input.reason ?? 'cancelled',\n releasedByUserId: input.userId,\n now,\n })\n await this.em.flush()\n\n await emitRecordLocksEvent('record_locks.lock.released', {\n lockId: lock.id,\n resourceKind: lock.resourceKind,\n resourceId: lock.resourceId,\n tenantId: lock.tenantId,\n organizationId: lock.organizationId,\n lockedByUserId: lock.lockedByUserId,\n releasedByUserId: input.userId,\n reason: lock.releaseReason,\n })\n\n if (lock.releaseReason === 'unmount') {\n const remainingActiveLocks = await this.findActiveLocks(input, now)\n const recipientUserIds = remainingActiveLocks\n .map((activeLock) => activeLock.lockedByUserId)\n .filter((userId) => userId !== lock.lockedByUserId)\n\n if (recipientUserIds.length) {\n await emitRecordLocksEvent('record_locks.participant.left', {\n lockId: lock.id,\n resourceKind: lock.resourceKind,\n resourceId: lock.resourceId,\n tenantId: lock.tenantId,\n organizationId: lock.organizationId,\n leftUserId: lock.lockedByUserId,\n reason: 'unmount',\n recipientUserIds,\n activeParticipantCount: remainingActiveLocks.length,\n })\n }\n }\n\n return { ok: true, released: true, conflictResolved }\n }\n\n async forceRelease(input: RecordLockForceReleaseInput): Promise<RecordLockForceReleaseResult> {\n const settings = await this.getSettings()\n const resourceEnabled = isRecordLockingEnabledForResource(settings, input.resourceKind)\n const canForceRelease = await this.canUserForceRelease(input, settings)\n if (!resourceEnabled || !settings.allowForceUnlock || !canForceRelease) {\n return { ok: true, released: false, lock: null }\n }\n\n const now = new Date()\n const activeLocks = this.sortLocksByJoinOrder(await this.findActiveLocks(input, now))\n const lock = activeLocks[0] ?? null\n if (!lock) return { ok: true, released: false, lock: null }\n\n this.markLockReleased(lock, {\n status: 'force_released',\n reason: 'force',\n releasedByUserId: input.userId,\n now,\n })\n await this.em.flush()\n\n await emitRecordLocksEvent('record_locks.lock.force_released', {\n lockId: lock.id,\n resourceKind: lock.resourceKind,\n resourceId: lock.resourceId,\n tenantId: lock.tenantId,\n organizationId: lock.organizationId,\n lockedByUserId: lock.lockedByUserId,\n releasedByUserId: input.userId,\n reason: input.reason ?? null,\n })\n\n const remainingLocks = this.sortLocksByJoinOrder(activeLocks.filter((item) => item.id !== lock.id))\n const nextInQueue = remainingLocks[0] ?? null\n return { ok: true, released: true, lock: nextInQueue ? this.toLockView(nextInQueue, false, remainingLocks) : null }\n }\n\n async validateMutation(input: RecordLockMutationValidationInput): Promise<RecordLockValidationResult> {\n this.scheduleCleanup(input.tenantId)\n const settings = await this.getSettings()\n const resourceEnabled = isRecordLockingEnabledForResource(settings, input.resourceKind)\n const canOverrideIncoming = await this.canUserOverrideIncoming(input, settings)\n\n if (!resourceEnabled) {\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: false,\n strategy: settings.strategy,\n shouldReleaseOnSuccess: false,\n lock: null,\n latestActionLogId: null,\n }\n }\n\n const parsedHeaders = this.normalizeMutationHeaders(input.headers)\n const keepMineResolution = parsedHeaders.resolution === 'accept_mine' || parsedHeaders.resolution === 'merged'\n ? parsedHeaders.resolution\n : null\n const hasKeepMineIntent = keepMineResolution !== null\n const now = new Date()\n const activeLocks = await this.findActiveLocks(input, now)\n const ownedActiveLock = activeLocks.find((lock) => lock.lockedByUserId === input.userId) ?? null\n const competingLock = activeLocks.find((lock) => lock.lockedByUserId !== input.userId) ?? null\n const latest = await this.findLatestActionLogWithScopeFallback(input)\n const shouldReleaseOnSuccess = Boolean(\n ownedActiveLock\n && (!parsedHeaders.token || ownedActiveLock.token === parsedHeaders.token),\n )\n\n if (settings.strategy === 'pessimistic') {\n if (competingLock && !ownedActiveLock) {\n return {\n ok: false,\n status: 423,\n error: 'Record is currently locked by another user',\n code: 'record_locked',\n lock: this.toLockView(competingLock, false, activeLocks),\n }\n }\n\n if (ownedActiveLock) {\n if (parsedHeaders.token && ownedActiveLock.token !== parsedHeaders.token) {\n return {\n ok: false,\n status: 423,\n error: 'Valid lock token is required for this mutation',\n code: 'record_locked',\n lock: this.toLockView(ownedActiveLock, false, activeLocks),\n }\n }\n }\n\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n shouldReleaseOnSuccess,\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n latestActionLogId: latest?.id ?? null,\n }\n }\n\n const existingConflict = parsedHeaders.conflictId\n ? await this.findConflictById(parsedHeaders.conflictId, input)\n : null\n\n if (existingConflict) {\n const canResolveExistingConflict = existingConflict.status === 'pending'\n && existingConflict.conflictActorUserId === input.userId\n\n if (parsedHeaders.resolution === 'accept_mine' || parsedHeaders.resolution === 'merged') {\n const isAlreadyResolvedByRequester = existingConflict.conflictActorUserId === input.userId\n && existingConflict.status !== 'pending'\n && existingConflict.resolution === parsedHeaders.resolution\n\n if (!canResolveExistingConflict && !isAlreadyResolvedByRequester) {\n return {\n ok: false,\n status: 409,\n error: 'Record conflict requires resolution before saving',\n code: 'record_lock_conflict',\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n conflict: await this.toConflictPayload(existingConflict, input.mutationPayload ?? null, settings.allowIncomingOverride, canOverrideIncoming),\n }\n }\n if (!canOverrideIncoming) {\n return {\n ok: false,\n status: 409,\n error: 'Record conflict requires resolution before saving',\n code: 'record_lock_conflict',\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n conflict: await this.toConflictPayload(existingConflict, input.mutationPayload ?? null, settings.allowIncomingOverride, canOverrideIncoming),\n }\n }\n if (canResolveExistingConflict) {\n await this.resolveConflict(existingConflict, parsedHeaders.resolution, input.userId)\n }\n } else {\n return {\n ok: false,\n status: 409,\n error: 'Record conflict requires resolution before saving',\n code: 'record_lock_conflict',\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n conflict: await this.toConflictPayload(existingConflict, input.mutationPayload ?? null, settings.allowIncomingOverride, canOverrideIncoming),\n }\n }\n }\n\n if (!existingConflict) {\n const baseActionLogId = parsedHeaders.baseLogId\n ?? (ownedActiveLock ? ownedActiveLock.baseActionLogId : null)\n\n const hasConflictingBaseLog = Boolean(\n latest?.id\n && baseActionLogId\n && latest.id !== baseActionLogId\n )\n const hasConflictingWriteAfterLockStart = Boolean(\n latest?.id\n && !baseActionLogId\n && ownedActiveLock\n && latest.createdAt instanceof Date\n && ownedActiveLock.lockedAt instanceof Date\n && latest.createdAt.getTime() > ownedActiveLock.lockedAt.getTime()\n && latest.actorUserId !== input.userId\n )\n const isConflictingWrite = hasConflictingBaseLog || hasConflictingWriteAfterLockStart\n\n if (isConflictingWrite) {\n if (keepMineResolution && canOverrideIncoming) {\n const autoResolvedConflict = await this.createConflict({\n scope: input,\n baseActionLogId,\n incomingActionLogId: latest?.id ?? null,\n conflictActorUserId: input.userId,\n incomingActorUserId: latest?.actorUserId ?? null,\n })\n await this.resolveConflict(autoResolvedConflict, keepMineResolution, input.userId)\n\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n shouldReleaseOnSuccess,\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n latestActionLogId: latest?.id ?? null,\n }\n }\n\n const conflict = await this.createConflict({\n scope: input,\n baseActionLogId,\n incomingActionLogId: latest?.id ?? null,\n conflictActorUserId: input.userId,\n incomingActorUserId: latest?.actorUserId ?? null,\n })\n\n return {\n ok: false,\n status: 409,\n error: 'Record conflict detected',\n code: 'record_lock_conflict',\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n conflict: await this.toConflictPayload(conflict, input.mutationPayload ?? null, settings.allowIncomingOverride, canOverrideIncoming),\n }\n }\n }\n\n return {\n ok: true,\n enabled: settings.enabled,\n resourceEnabled: true,\n strategy: settings.strategy,\n shouldReleaseOnSuccess,\n lock: ownedActiveLock ? this.toLockView(ownedActiveLock, false, activeLocks) : null,\n latestActionLogId: latest?.id ?? null,\n }\n }\n\n async releaseAfterMutation(input: RecordLockReleaseInput): Promise<void> {\n const releaseResult = await this.release({\n ...input,\n reason: input.reason ?? 'saved',\n })\n if (!releaseResult.released) return\n }\n\n async emitIncomingChangesNotificationAfterMutation(input: {\n tenantId: string\n organizationId?: string | null\n userId: string\n resourceKind: string\n resourceId: string\n method: 'PUT' | 'DELETE'\n }): Promise<void> {\n if (input.method !== 'PUT') return\n const settings = await this.getSettings()\n if (!settings.notifyOnConflict || !isRecordLockingEnabledForResource(settings, input.resourceKind)) return\n\n const now = new Date()\n let activeLocks = await this.findActiveLocks(input, now)\n if (!activeLocks.length) {\n const fallbackWhere: FilterQuery<RecordLock> = {\n tenantId: input.tenantId,\n deletedAt: null,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n status: ACTIVE_LOCK_STATUS,\n }\n const fallbackLocks = await this.em.find(RecordLock, fallbackWhere, { orderBy: { updatedAt: 'desc' } })\n activeLocks = Array.isArray(fallbackLocks) ? fallbackLocks : []\n }\n\n const recipientUserIds = new Set<string>()\n for (const lock of activeLocks) {\n if (lock.lockedByUserId !== input.userId) {\n recipientUserIds.add(lock.lockedByUserId)\n }\n }\n if (!recipientUserIds.size) {\n const fallbackWindowMs = Math.max((settings.timeoutSeconds ?? 300) * 1000, 60_000)\n const fallbackSince = new Date(now.getTime() - fallbackWindowMs)\n const recentLocks = await this.em.find(RecordLock, {\n tenantId: input.tenantId,\n deletedAt: null,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n updatedAt: { $gte: fallbackSince },\n }, { orderBy: { updatedAt: 'desc' }, limit: 50 })\n\n for (const lock of (Array.isArray(recentLocks) ? recentLocks : [])) {\n if (lock.lockedByUserId !== input.userId) {\n recipientUserIds.add(lock.lockedByUserId)\n }\n }\n }\n if (!recipientUserIds.size) return\n\n let latest = await this.findLatestActionLog(input)\n if (!latest) {\n latest = await this.findLatestActionLog({\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n })\n }\n let actorLog = latest?.actorUserId === input.userId\n ? latest\n : await this.findLatestActionLogByActor(input, input.userId)\n if (!actorLog) {\n actorLog = await this.findLatestActionLogByActor({\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n }, input.userId)\n }\n const incomingLog = actorLog ?? latest\n\n const changedFields = incomingLog\n ? this.summarizeChangedFieldsFromActionLog(incomingLog)\n : ''\n const changedRows = this.buildIncomingChangeRowsFromActionLog(incomingLog)\n const changedRowsJson = changedRows.length ? JSON.stringify(changedRows) : ''\n\n await emitRecordLocksEvent('record_locks.incoming_changes.available', {\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n incomingActorUserId: input.userId,\n incomingActionLogId: incomingLog?.id ?? null,\n recipientUserIds: Array.from(recipientUserIds),\n changedFields: changedFields || '-',\n changedRowsJson,\n })\n }\n\n async emitRecordDeletedNotificationAfterMutation(input: {\n tenantId: string\n organizationId?: string | null\n userId: string\n resourceKind: string\n resourceId: string\n method: 'PUT' | 'DELETE'\n }): Promise<void> {\n if (input.method !== 'DELETE') return\n const settings = await this.getSettings()\n if (!isRecordLockingEnabledForResource(settings, input.resourceKind)) return\n\n const now = new Date()\n let activeLocks = await this.findActiveLocks(input, now)\n if (!activeLocks.length) {\n const fallbackWhere: FilterQuery<RecordLock> = {\n tenantId: input.tenantId,\n deletedAt: null,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n status: ACTIVE_LOCK_STATUS,\n }\n const fallbackLocks = await this.em.find(RecordLock, fallbackWhere, { orderBy: { updatedAt: 'desc' } })\n activeLocks = Array.isArray(fallbackLocks) ? fallbackLocks : []\n }\n\n const recipientUserIds = new Set<string>()\n for (const lock of activeLocks) {\n if (lock.lockedByUserId !== input.userId) {\n recipientUserIds.add(lock.lockedByUserId)\n }\n }\n\n if (!recipientUserIds.size) {\n const fallbackWindowMs = Math.max((settings.timeoutSeconds ?? 300) * 1000, 60_000)\n const fallbackSince = new Date(now.getTime() - fallbackWindowMs)\n const recentLocks = await this.em.find(RecordLock, {\n tenantId: input.tenantId,\n deletedAt: null,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n updatedAt: { $gte: fallbackSince },\n }, { orderBy: { updatedAt: 'desc' }, limit: 50 })\n\n for (const lock of (Array.isArray(recentLocks) ? recentLocks : [])) {\n if (lock.lockedByUserId !== input.userId) {\n recipientUserIds.add(lock.lockedByUserId)\n }\n }\n }\n if (!recipientUserIds.size) return\n\n await emitRecordLocksEvent('record_locks.record.deleted', {\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n deletedByUserId: input.userId,\n recipientUserIds: Array.from(recipientUserIds),\n })\n }\n\n async resolveConflictById(input: {\n conflictId: string\n tenantId: string\n organizationId?: string | null\n userId: string\n resolution: 'accept_incoming' | 'accept_mine' | 'merged'\n }): Promise<boolean> {\n const settings = await this.getSettings()\n const canOverrideIncoming = await this.canUserOverrideIncoming(input, settings)\n const conflict = await this.em.findOne(RecordLockConflict, {\n id: input.conflictId,\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n deletedAt: null,\n })\n if (!conflict || conflict.status !== 'pending' || conflict.conflictActorUserId !== input.userId) {\n return false\n }\n if ((input.resolution === 'accept_mine' || input.resolution === 'merged') && !canOverrideIncoming) {\n return false\n }\n await this.resolveConflict(conflict, input.resolution, input.userId)\n return true\n }\n\n private async canUserOverrideIncoming(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId' | 'userId'>,\n settings: RecordLockSettings,\n ): Promise<boolean> {\n if (!settings.allowIncomingOverride) return false\n if (!this.rbacService) return false\n\n try {\n return await this.rbacService.userHasAllFeatures(\n input.userId,\n ['record_locks.override_incoming'],\n {\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n },\n )\n } catch {\n return false\n }\n }\n\n private async canUserForceRelease(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId' | 'userId'>,\n settings: RecordLockSettings,\n ): Promise<boolean> {\n if (!settings.allowForceUnlock) return false\n if (!this.rbacService) return false\n\n try {\n return await this.rbacService.userHasAllFeatures(\n input.userId,\n ['record_locks.force_release'],\n {\n tenantId: input.tenantId,\n organizationId: normalizeScopeOrganization(input.organizationId),\n },\n )\n } catch {\n return false\n }\n }\n\n private pruneLockCleanupState(now: number): void {\n for (const [tenantId, state] of lockCleanupStateByTenant.entries()) {\n if (!state.inFlight && now - state.lastSeenAt > LOCK_CLEANUP_STATE_TTL_MS) {\n lockCleanupStateByTenant.delete(tenantId)\n }\n }\n\n if (lockCleanupStateByTenant.size <= LOCK_CLEANUP_STATE_MAX_ENTRIES) return\n\n const removable = Array.from(lockCleanupStateByTenant.entries())\n .filter(([, state]) => !state.inFlight)\n .sort((left, right) => left[1].lastSeenAt - right[1].lastSeenAt)\n const overflow = lockCleanupStateByTenant.size - LOCK_CLEANUP_STATE_MAX_ENTRIES\n for (const [tenantId] of removable.slice(0, Math.max(0, overflow))) {\n lockCleanupStateByTenant.delete(tenantId)\n }\n }\n\n private scheduleCleanup(tenantId: string): void {\n const now = Date.now()\n this.pruneLockCleanupState(now)\n const state = lockCleanupStateByTenant.get(tenantId) ?? { lastRunAt: 0, inFlight: false, lastSeenAt: now }\n state.lastSeenAt = now\n lockCleanupStateByTenant.set(tenantId, state)\n if (state.inFlight) return\n if (now - state.lastRunAt < LOCK_CLEANUP_INTERVAL_MS) return\n\n state.inFlight = true\n state.lastRunAt = now\n lockCleanupStateByTenant.set(tenantId, state)\n\n void this.cleanupHistoricalRecords(tenantId).finally(() => {\n const current = lockCleanupStateByTenant.get(tenantId)\n if (!current) return\n current.inFlight = false\n lockCleanupStateByTenant.set(tenantId, current)\n })\n }\n\n private async cleanupHistoricalRecords(tenantId: string): Promise<void> {\n try {\n const knex = getKnex(this.em)\n const now = Date.now()\n const lockCutoff = new Date(now - LOCK_RETENTION_MS)\n const resolvedConflictCutoff = new Date(now - RESOLVED_CONFLICT_RETENTION_MS)\n const pendingConflictCutoff = new Date(now - PENDING_CONFLICT_RETENTION_MS)\n const deletedAt = new Date(now)\n\n await knex('record_locks')\n .where({ tenant_id: tenantId })\n .whereNull('deleted_at')\n .whereNot('status', ACTIVE_LOCK_STATUS)\n .andWhere('updated_at', '<', lockCutoff)\n .update({\n deleted_at: deletedAt,\n updated_at: deletedAt,\n })\n\n await knex('record_lock_conflicts')\n .where({ tenant_id: tenantId })\n .whereNull('deleted_at')\n .andWhere((query) => {\n query\n .where((pending) => {\n pending.where('status', 'pending').andWhere('created_at', '<', pendingConflictCutoff)\n })\n .orWhere((resolved) => {\n resolved.whereNot('status', 'pending').andWhere('updated_at', '<', resolvedConflictCutoff)\n })\n })\n .update({\n deleted_at: deletedAt,\n updated_at: deletedAt,\n })\n } catch {\n // Best-effort cleanup must never fail lock workflows.\n }\n }\n\n private normalizeMutationHeaders(headers: Partial<RecordLockMutationHeaders>): Partial<RecordLockMutationHeaders> {\n const parsed = recordLockMutationHeaderSchema.partial().safeParse(headers)\n if (!parsed.success) return {}\n return parsed.data\n }\n\n private buildScopeWhere(scope: Pick<RecordLockScope, 'tenantId' | 'organizationId'>): {\n tenantId: string\n deletedAt: null\n organizationId?: string | null\n } {\n const where: {\n tenantId: string\n deletedAt: null\n organizationId?: string | null\n } = {\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n\n if (scope.organizationId !== undefined) {\n where.organizationId = normalizeScopeOrganization(scope.organizationId)\n }\n\n return where\n }\n\n private async findActiveLocks(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n now: Date,\n ): Promise<RecordLock[]> {\n const legacyFinder = (this as unknown as {\n findActiveLock?: (args: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource, at: Date) => Promise<RecordLock | null>\n }).findActiveLock\n if (typeof legacyFinder === 'function') {\n const legacyResult = await legacyFinder(input, now)\n return legacyResult ? [legacyResult] : []\n }\n\n const where: FilterQuery<RecordLock> = {\n ...this.buildScopeWhere(input),\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n status: ACTIVE_LOCK_STATUS,\n }\n\n const locks = await this.em.find(RecordLock, where, { orderBy: { updatedAt: 'desc' } })\n if (!Array.isArray(locks) || !locks.length) return []\n\n let dirty = false\n const active: RecordLock[] = []\n const expiredLocks: RecordLock[] = []\n\n for (const lock of locks) {\n if (lock.expiresAt <= now) {\n this.markLockReleased(lock, {\n status: 'expired',\n reason: 'expired',\n releasedByUserId: lock.lockedByUserId,\n now,\n })\n dirty = true\n expiredLocks.push(lock)\n continue\n }\n\n active.push(lock)\n }\n\n if (dirty) await this.em.flush()\n if (expiredLocks.length) {\n const recipientUserIds = active.map((lock) => lock.lockedByUserId)\n for (const expiredLock of expiredLocks) {\n await emitRecordLocksEvent('record_locks.participant.left', {\n lockId: expiredLock.id,\n resourceKind: expiredLock.resourceKind,\n resourceId: expiredLock.resourceId,\n tenantId: expiredLock.tenantId,\n organizationId: expiredLock.organizationId,\n leftUserId: expiredLock.lockedByUserId,\n reason: 'expired',\n recipientUserIds,\n activeParticipantCount: active.length,\n })\n }\n }\n return active\n }\n\n private async findOwnedLockByToken(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId' | 'userId'> & RecordLockResource & { token?: string },\n ): Promise<RecordLock | null> {\n if (!input.token) return null\n\n const where: FilterQuery<RecordLock> = {\n ...this.buildScopeWhere(input),\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n token: input.token,\n lockedByUserId: input.userId,\n status: ACTIVE_LOCK_STATUS,\n }\n\n return this.em.findOne(RecordLock, where)\n }\n\n private async findOwnedActiveLock(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId' | 'userId'> & RecordLockResource,\n ): Promise<RecordLock | null> {\n const where: FilterQuery<RecordLock> = {\n ...this.buildScopeWhere(input),\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n lockedByUserId: input.userId,\n status: ACTIVE_LOCK_STATUS,\n }\n return this.em.findOne(RecordLock, where)\n }\n\n private async hasRecentSavedRelease(input: {\n tenantId: string\n organizationId?: string | null\n userId: string\n resourceKind: string\n resourceId: string\n now: Date\n }): Promise<boolean> {\n const cutoff = new Date(input.now.getTime() - PARTICIPANT_REJOIN_AFTER_SAVE_SUPPRESS_MS)\n const where: FilterQuery<RecordLock> = {\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n lockedByUserId: input.userId,\n status: 'released',\n releaseReason: 'saved',\n deletedAt: null,\n releasedAt: { $gte: cutoff },\n }\n if (input.organizationId !== undefined) {\n where.organizationId = normalizeScopeOrganization(input.organizationId)\n }\n\n const scoped = await this.em.findOne(RecordLock, where, { orderBy: { releasedAt: 'desc' } })\n if (scoped) return true\n if (input.organizationId === undefined) return false\n\n return Boolean(await this.em.findOne(RecordLock, {\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n lockedByUserId: input.userId,\n status: 'released',\n releaseReason: 'saved',\n deletedAt: null,\n releasedAt: { $gte: cutoff },\n }, { orderBy: { releasedAt: 'desc' } }))\n }\n\n private markLockReleased(\n lock: RecordLock,\n params: {\n status: RecordLockStatus\n reason: RecordLockReleaseReason\n releasedByUserId: string\n now: Date\n },\n ) {\n lock.status = params.status\n lock.releaseReason = params.reason\n lock.releasedByUserId = params.releasedByUserId\n lock.releasedAt = params.now\n lock.updatedAt = params.now\n }\n\n private async findLatestActionLog(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n ): Promise<ActionLog | null> {\n const where: FilterQuery<ActionLog> = {\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n deletedAt: null,\n }\n\n if (input.organizationId !== undefined) {\n where.organizationId = normalizeScopeOrganization(input.organizationId)\n }\n\n return this.em.findOne(ActionLog, where, { orderBy: { createdAt: 'desc' } })\n }\n\n private async findLatestActionLogWithScopeFallback(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n ): Promise<ActionLog | null> {\n const scoped = await this.findLatestActionLog(input)\n if (scoped) return scoped\n if (input.organizationId !== null) return null\n\n return this.findLatestActionLog({\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n })\n }\n\n private async findLatestActionLogByActor(\n input: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n actorUserId: string,\n ): Promise<ActionLog | null> {\n const where: FilterQuery<ActionLog> = {\n tenantId: input.tenantId,\n resourceKind: input.resourceKind,\n resourceId: input.resourceId,\n actorUserId,\n deletedAt: null,\n }\n\n if (input.organizationId !== undefined) {\n where.organizationId = normalizeScopeOrganization(input.organizationId)\n }\n\n return this.em.findOne(ActionLog, where, { orderBy: { createdAt: 'desc' } })\n }\n\n private summarizeChangedFieldsFromActionLog(log: ActionLog | null): string {\n if (!log) return ''\n\n if (isRecordValue(log.changesJson)) {\n const fromChanges = Object.keys(log.changesJson)\n .filter((field) => !shouldSkipConflictField(field))\n .slice(0, 12)\n .map(formatChangedFieldLabel)\n .join(', ')\n if (fromChanges) return fromChanges\n }\n\n const before = isRecordValue(log.snapshotBefore) ? log.snapshotBefore : null\n const after = isRecordValue(log.snapshotAfter) ? log.snapshotAfter : null\n if (!before || !after) return ''\n\n const diffPaths = new Set<string>()\n this.collectSnapshotDiffPaths(before, after, null, diffPaths, new Set<unknown>())\n\n return Array.from(diffPaths)\n .filter((field) => !shouldSkipConflictField(field))\n .sort((left, right) => left.localeCompare(right))\n .slice(0, 12)\n .map(formatChangedFieldLabel)\n .join(', ')\n }\n\n private buildIncomingChangeRowsFromActionLog(log: ActionLog | null): Array<{\n field: string\n incoming: string\n current: string\n }> {\n if (!log || !isRecordValue(log.changesJson)) return []\n\n const rows: Array<{ field: string; incoming: string; current: string }> = []\n for (const [rawField, rawChange] of Object.entries(log.changesJson)) {\n if (rows.length >= 12) break\n if (shouldSkipConflictField(rawField)) continue\n\n const change = isRecordValue(rawChange) ? rawChange : {}\n const incoming = Object.prototype.hasOwnProperty.call(change, 'to')\n ? formatNotificationValue(change.to)\n : '-'\n const current = Object.prototype.hasOwnProperty.call(change, 'from')\n ? formatNotificationValue(change.from)\n : '-'\n\n rows.push({\n field: formatChangedFieldLabel(rawField),\n incoming,\n current,\n })\n }\n\n return rows\n }\n\n private toParticipantView(lock: RecordLock): RecordLockParticipantView {\n return {\n userId: lock.lockedByUserId,\n lockedByIp: lock.lockedByIp ?? null,\n lockedAt: normalizeDate(lock.lockedAt),\n lastHeartbeatAt: normalizeDate(lock.lastHeartbeatAt),\n expiresAt: normalizeDate(lock.expiresAt),\n }\n }\n\n private sortLocksByJoinOrder(locks: RecordLock[]): RecordLock[] {\n return [...locks].sort((left, right) => {\n const leftLockedAt = left.lockedAt instanceof Date ? left.lockedAt.getTime() : 0\n const rightLockedAt = right.lockedAt instanceof Date ? right.lockedAt.getTime() : 0\n if (leftLockedAt !== rightLockedAt) return leftLockedAt - rightLockedAt\n\n const leftCreatedAt = left.createdAt instanceof Date ? left.createdAt.getTime() : 0\n const rightCreatedAt = right.createdAt instanceof Date ? right.createdAt.getTime() : 0\n if (leftCreatedAt !== rightCreatedAt) return leftCreatedAt - rightCreatedAt\n\n return left.id.localeCompare(right.id)\n })\n }\n\n private toLockView(lock: RecordLock, includeToken: boolean, activeLocks: RecordLock[] = [lock]): RecordLockView {\n const participants = activeLocks.map((item) => this.toParticipantView(item))\n return {\n id: lock.id,\n resourceKind: lock.resourceKind,\n resourceId: lock.resourceId,\n token: includeToken ? lock.token : null,\n strategy: lock.strategy,\n status: lock.status,\n lockedByUserId: lock.lockedByUserId,\n lockedByIp: lock.lockedByIp ?? null,\n baseActionLogId: lock.baseActionLogId,\n lockedAt: normalizeDate(lock.lockedAt),\n lastHeartbeatAt: normalizeDate(lock.lastHeartbeatAt),\n expiresAt: normalizeDate(lock.expiresAt),\n participants,\n activeParticipantCount: participants.length,\n }\n }\n\n private async createConflict(input: {\n scope: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource\n baseActionLogId: string | null\n incomingActionLogId: string | null\n conflictActorUserId: string\n incomingActorUserId: string | null\n }): Promise<RecordLockConflict> {\n const dedupeKey = [\n 'record_locks',\n 'conflict',\n input.scope.tenantId,\n normalizeScopeOrganization(input.scope.organizationId) ?? 'global',\n input.scope.resourceKind,\n input.scope.resourceId,\n input.conflictActorUserId,\n input.baseActionLogId ?? 'none',\n input.incomingActionLogId ?? 'none',\n ].join(':')\n\n const result = await this.em.transactional(async (tx) => {\n try {\n const knex = getKnex(tx as EntityManager)\n await knex.raw('select pg_advisory_xact_lock(hashtext(?))', [dedupeKey])\n } catch {\n // Best-effort lock; fallback to find-first behavior below.\n }\n\n const existing = await this.findPendingConflictByFingerprint(tx as EntityManager, input)\n if (existing) {\n return { conflict: existing, created: false as const }\n }\n\n const conflict = tx.create(RecordLockConflict, {\n resourceKind: input.scope.resourceKind,\n resourceId: input.scope.resourceId,\n status: 'pending',\n resolution: null,\n baseActionLogId: input.baseActionLogId,\n incomingActionLogId: input.incomingActionLogId,\n conflictActorUserId: input.conflictActorUserId,\n incomingActorUserId: input.incomingActorUserId,\n tenantId: input.scope.tenantId,\n organizationId: normalizeScopeOrganization(input.scope.organizationId),\n })\n\n tx.persist(conflict)\n await tx.flush()\n return { conflict, created: true as const }\n })\n\n if (result.created) {\n await emitRecordLocksEvent('record_locks.conflict.detected', {\n conflictId: result.conflict.id,\n resourceKind: result.conflict.resourceKind,\n resourceId: result.conflict.resourceId,\n tenantId: result.conflict.tenantId,\n organizationId: result.conflict.organizationId,\n conflictActorUserId: result.conflict.conflictActorUserId,\n incomingActorUserId: result.conflict.incomingActorUserId,\n baseActionLogId: result.conflict.baseActionLogId,\n incomingActionLogId: result.conflict.incomingActionLogId,\n })\n }\n\n return result.conflict\n }\n\n private findPendingConflictByFingerprint(\n em: EntityManager,\n input: {\n scope: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource\n baseActionLogId: string | null\n incomingActionLogId: string | null\n conflictActorUserId: string\n },\n ): Promise<RecordLockConflict | null> {\n return em.findOne(RecordLockConflict, {\n tenantId: input.scope.tenantId,\n organizationId: normalizeScopeOrganization(input.scope.organizationId),\n resourceKind: input.scope.resourceKind,\n resourceId: input.scope.resourceId,\n conflictActorUserId: input.conflictActorUserId,\n status: 'pending',\n baseActionLogId: input.baseActionLogId,\n incomingActionLogId: input.incomingActionLogId,\n deletedAt: null,\n }, { orderBy: { createdAt: 'desc' } })\n }\n\n private async resolveConflict(\n conflict: RecordLockConflict,\n resolution: 'accept_incoming' | Extract<RecordLockMutationHeaders['resolution'], 'accept_mine' | 'merged'>,\n resolvedByUserId: string,\n ): Promise<void> {\n const now = new Date()\n\n const resolutionMap: Record<'accept_incoming' | Extract<RecordLockMutationHeaders['resolution'], 'accept_mine' | 'merged'>, {\n status: RecordLockConflictStatus\n resolution: RecordLockConflictResolution\n }> = {\n accept_incoming: { status: 'resolved_accept_incoming', resolution: 'accept_incoming' },\n accept_mine: { status: 'resolved_accept_mine', resolution: 'accept_mine' },\n merged: { status: 'resolved_merged', resolution: 'merged' },\n }\n\n const target = resolutionMap[resolution]\n conflict.status = target.status\n conflict.resolution = target.resolution\n conflict.resolvedByUserId = resolvedByUserId\n conflict.resolvedAt = now\n conflict.updatedAt = now\n await this.em.flush()\n\n await emitRecordLocksEvent('record_locks.conflict.resolved', {\n conflictId: conflict.id,\n resourceKind: conflict.resourceKind,\n resourceId: conflict.resourceId,\n tenantId: conflict.tenantId,\n organizationId: conflict.organizationId,\n conflictActorUserId: conflict.conflictActorUserId,\n incomingActorUserId: conflict.incomingActorUserId,\n resolution: conflict.resolution,\n resolvedByUserId,\n })\n }\n\n private async findConflictById(\n conflictId: string,\n scope: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n ): Promise<RecordLockConflict | null> {\n const where: FilterQuery<RecordLockConflict> = {\n id: conflictId,\n tenantId: scope.tenantId,\n resourceKind: scope.resourceKind,\n resourceId: scope.resourceId,\n deletedAt: null,\n }\n\n if (scope.organizationId !== undefined) {\n where.organizationId = normalizeScopeOrganization(scope.organizationId)\n }\n\n const scoped = await this.em.findOne(RecordLockConflict, where)\n if (scoped || scope.organizationId === undefined) return scoped\n\n return this.em.findOne(RecordLockConflict, {\n id: conflictId,\n tenantId: scope.tenantId,\n resourceKind: scope.resourceKind,\n resourceId: scope.resourceId,\n deletedAt: null,\n })\n }\n\n private async findActionLogById(\n logId: string | null,\n scope: Pick<RecordLockScope, 'tenantId' | 'organizationId'> & RecordLockResource,\n ): Promise<ActionLog | null> {\n if (!logId) return null\n\n let resolved = this.actionLogService\n ? await this.actionLogService.findById(logId)\n : null\n if (!resolved) {\n resolved = await this.em.findOne(ActionLog, { id: logId, deletedAt: null })\n }\n if (!resolved || resolved.deletedAt) return null\n\n if (resolved.tenantId !== scope.tenantId) return null\n\n if (scope.organizationId !== undefined) {\n const expectedOrganizationId = normalizeScopeOrganization(scope.organizationId)\n if (normalizeScopeOrganization(resolved.organizationId) !== expectedOrganizationId) return null\n }\n\n if (resolved.resourceKind !== scope.resourceKind || resolved.resourceId !== scope.resourceId) {\n return null\n }\n\n return resolved\n }\n\n private collectSnapshotDiffPaths(\n before: unknown,\n after: unknown,\n pathPrefix: string | null,\n output: Set<string>,\n seen: Set<unknown>,\n ): void {\n if (valuesEqual(before, after)) return\n\n const beforeRecord = isRecordValue(before) ? before : null\n const afterRecord = isRecordValue(after) ? after : null\n\n if (!beforeRecord || !afterRecord) {\n if (pathPrefix) output.add(pathPrefix)\n return\n }\n\n if (seen.has(beforeRecord) || seen.has(afterRecord)) {\n if (pathPrefix) output.add(pathPrefix)\n return\n }\n\n seen.add(beforeRecord)\n seen.add(afterRecord)\n\n const keys = new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)])\n for (const key of keys) {\n if (SKIPPED_CONFLICT_FIELDS.has(key)) continue\n const nextPath = pathPrefix ? `${pathPrefix}.${key}` : key\n this.collectSnapshotDiffPaths(beforeRecord[key], afterRecord[key], nextPath, output, seen)\n }\n }\n\n private async buildConflictChanges(\n conflict: RecordLockConflict,\n mutationPayload: Record<string, unknown> | null,\n ): Promise<RecordLockConflictChange[]> {\n const scope = {\n tenantId: conflict.tenantId,\n organizationId: conflict.organizationId,\n resourceKind: conflict.resourceKind,\n resourceId: conflict.resourceId,\n }\n\n const baseLog = await this.findActionLogById(conflict.baseActionLogId, scope)\n const incomingLog = await this.findActionLogById(conflict.incomingActionLogId, scope)\n\n const baseSnapshot = isRecordValue(baseLog?.snapshotAfter) ? baseLog.snapshotAfter : null\n const incomingBeforeSnapshot = isRecordValue(incomingLog?.snapshotBefore) ? incomingLog.snapshotBefore : null\n const incomingAfterSnapshot = isRecordValue(incomingLog?.snapshotAfter) ? incomingLog.snapshotAfter : null\n const fallbackBaseSnapshot = baseSnapshot ?? incomingBeforeSnapshot\n\n const changeMap = new Map<string, { baseValue: unknown; incomingValue: unknown }>()\n\n const incomingChanges = isRecordValue(incomingLog?.changesJson) ? incomingLog.changesJson : null\n if (incomingChanges) {\n for (const [fieldPathRaw, rawChange] of Object.entries(incomingChanges)) {\n const fieldPath = fieldPathRaw.trim()\n if (shouldSkipConflictField(fieldPath)) continue\n\n const changeRecord = isRecordValue(rawChange) ? rawChange : null\n const fromValue = changeRecord && Object.prototype.hasOwnProperty.call(changeRecord, 'from')\n ? changeRecord.from\n : readPathValueLoose(fallbackBaseSnapshot, fieldPath)\n const toValue = changeRecord && Object.prototype.hasOwnProperty.call(changeRecord, 'to')\n ? changeRecord.to\n : readPathValueLoose(incomingAfterSnapshot, fieldPath)\n\n changeMap.set(fieldPath, {\n baseValue: fromValue === MISSING_CONFLICT_VALUE ? null : normalizeConflictValue(fromValue),\n incomingValue: toValue === MISSING_CONFLICT_VALUE ? null : normalizeConflictValue(toValue),\n })\n }\n }\n\n if (!changeMap.size && fallbackBaseSnapshot && incomingAfterSnapshot) {\n const diffPaths = new Set<string>()\n this.collectSnapshotDiffPaths(\n fallbackBaseSnapshot,\n incomingAfterSnapshot,\n null,\n diffPaths,\n new Set<unknown>(),\n )\n\n for (const fieldPath of diffPaths) {\n if (shouldSkipConflictField(fieldPath)) continue\n const fromValue = readPathValueLoose(fallbackBaseSnapshot, fieldPath)\n const toValue = readPathValueLoose(incomingAfterSnapshot, fieldPath)\n changeMap.set(fieldPath, {\n baseValue: fromValue === MISSING_CONFLICT_VALUE ? null : normalizeConflictValue(fromValue),\n incomingValue: toValue === MISSING_CONFLICT_VALUE ? null : normalizeConflictValue(toValue),\n })\n }\n }\n\n if (!changeMap.size && mutationPayload && incomingAfterSnapshot) {\n for (const fieldPath of Object.keys(mutationPayload)) {\n if (shouldSkipConflictField(fieldPath)) continue\n const mineValue = readPathValueLoose(mutationPayload, fieldPath)\n const incomingValue = readPathValueLoose(incomingAfterSnapshot, fieldPath)\n if (mineValue === MISSING_CONFLICT_VALUE || incomingValue === MISSING_CONFLICT_VALUE) continue\n if (valuesEqual(mineValue, incomingValue)) continue\n const baseValue = readPathValueLoose(fallbackBaseSnapshot, fieldPath)\n changeMap.set(fieldPath, {\n baseValue: baseValue === MISSING_CONFLICT_VALUE ? null : normalizeConflictValue(baseValue),\n incomingValue: normalizeConflictValue(incomingValue),\n })\n }\n }\n\n if (!changeMap.size) return []\n\n const allFields = Array.from(changeMap.keys())\n const preferredFields = mutationPayload\n ? allFields.filter((fieldPath) => {\n const mineValue = readPathValueLoose(mutationPayload, fieldPath)\n if (mineValue === MISSING_CONFLICT_VALUE) return false\n const incomingValue = changeMap.get(fieldPath)?.incomingValue\n return !valuesEqual(mineValue, incomingValue)\n })\n : []\n const selectedFields = (preferredFields.length ? preferredFields : allFields)\n .filter((fieldPath) => !shouldSkipConflictField(fieldPath))\n .sort((left, right) => left.localeCompare(right))\n .slice(0, 25)\n\n return selectedFields.map((fieldPath) => {\n const entry = changeMap.get(fieldPath) ?? { baseValue: null, incomingValue: null }\n const mineValueRaw = mutationPayload ? readPathValueLoose(mutationPayload, fieldPath) : MISSING_CONFLICT_VALUE\n const mineValue = mineValueRaw === MISSING_CONFLICT_VALUE\n ? entry.baseValue\n : normalizeConflictValue(mineValueRaw)\n\n return {\n field: fieldPath,\n displayValue: normalizeConflictValue(entry.baseValue),\n baseValue: normalizeConflictValue(entry.baseValue),\n incomingValue: normalizeConflictValue(entry.incomingValue),\n mineValue: normalizeConflictValue(mineValue),\n }\n })\n }\n\n private async toConflictPayload(\n conflict: RecordLockConflict,\n mutationPayload: Record<string, unknown> | null,\n allowIncomingOverride: boolean,\n canOverrideIncoming: boolean,\n ): Promise<RecordLockConflictPayload> {\n const changes = await this.buildConflictChanges(conflict, mutationPayload)\n return {\n id: conflict.id,\n resourceKind: conflict.resourceKind,\n resourceId: conflict.resourceId,\n baseActionLogId: conflict.baseActionLogId,\n incomingActionLogId: conflict.incomingActionLogId,\n allowIncomingOverride,\n canOverrideIncoming,\n resolutionOptions: canOverrideIncoming ? ['accept_mine'] : [],\n changes,\n }\n }\n}\n\nexport function createRecordLockService(deps: RecordLockServiceDeps): RecordLockService {\n return new RecordLockService(deps)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["lock"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { securityApiError } from "../i18n.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
GET: { requireAuth: true },
|
|
4
|
+
POST: { requireAuth: true }
|
|
5
|
+
};
|
|
2
6
|
async function GET() {
|
|
3
7
|
return securityApiError(501, "Not implemented");
|
|
4
8
|
}
|
|
@@ -16,6 +20,7 @@ const openApi = {
|
|
|
16
20
|
export {
|
|
17
21
|
GET,
|
|
18
22
|
POST,
|
|
23
|
+
metadata,
|
|
19
24
|
openApi
|
|
20
25
|
};
|
|
21
26
|
//# sourceMappingURL=route.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/security/api/admin/route.ts"],
|
|
4
|
-
"sourcesContent": ["import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { securityApiError } from '../i18n'\n\nexport async function GET() {\n return securityApiError(501, 'Not implemented')\n}\n\nexport async function POST() {\n return securityApiError(501, 'Not implemented')\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Security',\n summary: 'Admin security routes',\n methods: {\n GET: { summary: 'Get admin security data' },\n POST: { summary: 'Manage admin security actions' },\n },\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,wBAAwB;
|
|
4
|
+
"sourcesContent": ["import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { securityApiError } from '../i18n'\n\nexport const metadata = {\n GET: { requireAuth: true },\n POST: { requireAuth: true },\n}\n\nexport async function GET() {\n return securityApiError(501, 'Not implemented')\n}\n\nexport async function POST() {\n return securityApiError(501, 'Not implemented')\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Security',\n summary: 'Admin security routes',\n methods: {\n GET: { summary: 'Get admin security data' },\n POST: { summary: 'Manage admin security actions' },\n },\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,wBAAwB;AAE1B,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,KAAK;AAAA,EACzB,MAAM,EAAE,aAAa,KAAK;AAC5B;AAEA,eAAsB,MAAM;AAC1B,SAAO,iBAAiB,KAAK,iBAAiB;AAChD;AAEA,eAAsB,OAAO;AAC3B,SAAO,iBAAiB,KAAK,iBAAiB;AAChD;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK,EAAE,SAAS,0BAA0B;AAAA,IAC1C,MAAM,EAAE,SAAS,gCAAgC;AAAA,EACnD;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -264,7 +264,7 @@ class PasskeyProvider {
|
|
|
264
264
|
return Buffer.from(value).toString("base64url");
|
|
265
265
|
}
|
|
266
266
|
base64UrlToBytes(value) {
|
|
267
|
-
return new Uint8Array(Buffer.from(value, "base64url"));
|
|
267
|
+
return new Uint8Array(Buffer.from(value, "base64url")).slice();
|
|
268
268
|
}
|
|
269
269
|
createSetupToken(setup) {
|
|
270
270
|
const encodedPayload = Buffer.from(JSON.stringify(setup), "utf8").toString("base64url");
|
|
@@ -310,7 +310,7 @@ class PasskeyProvider {
|
|
|
310
310
|
return resolveSecurityModuleConfigForRequest(this.securityConfig, context?.request);
|
|
311
311
|
}
|
|
312
312
|
toWebAuthnUserId(userId) {
|
|
313
|
-
return new TextEncoder().encode(userId);
|
|
313
|
+
return new TextEncoder().encode(userId).slice();
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
var PasskeyProvider_default = PasskeyProvider;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/security/lib/providers/PasskeyProvider.ts"],
|
|
4
|
-
"sourcesContent": ["import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'\nimport {\n generateAuthenticationOptions,\n generateRegistrationOptions,\n verifyAuthenticationResponse,\n verifyRegistrationResponse,\n} from '@simplewebauthn/server'\nimport type { AuthenticatorTransportFuture } from '@simplewebauthn/types'\nimport { z } from 'zod'\nimport type {\n MfaMethodRecord,\n MfaProviderConfirmResult,\n MfaProviderInterface,\n MfaProviderRuntimeContext,\n MfaProviderUser,\n MfaVerifyContext,\n} from '../mfa-provider-interface'\nimport type { SecurityModuleConfig } from '../security-config'\nimport {\n readSecurityModuleConfig,\n readSecuritySetupTokenSecret,\n resolveSecurityModuleConfigForRequest,\n} from '../security-config'\n\nconst SETUP_TOKEN_VERSION = 'v1'\n\nconst setupPayloadSchema = z.object({\n label: z.string().min(1).max(100).optional(),\n userName: z.string().min(1).max(255).optional(),\n authenticatorAttachment: z.enum(['platform', 'cross-platform']).optional(),\n})\n\nconst setupConfirmationPayloadSchema = z.union([\n z.object({\n response: z.record(z.string(), z.unknown()),\n label: z.string().min(1).max(100).optional(),\n }),\n z.object({\n credentialId: z.string().min(1),\n publicKey: z.string().min(1),\n challenge: z.string().min(1),\n transports: z.array(z.string().min(1)).optional(),\n label: z.string().min(1).max(100).optional(),\n }),\n])\n\nconst verifyPayloadSchema = z.union([\n z.object({\n response: z.record(z.string(), z.unknown()),\n }),\n z.object({\n credentialId: z.string().min(1),\n challenge: z.string().min(1),\n }),\n])\n\nconst setupTokenSchema = z.object({\n version: z.string().min(1),\n userId: z.string().min(1),\n challenge: z.string().min(1),\n label: z.string().min(1).max(100).optional(),\n createdAt: z.number().int().nonnegative(),\n nonce: z.string().min(1),\n})\n\ntype PendingSetup = {\n version: string\n userId: string\n challenge: string\n label?: string\n createdAt: number\n nonce: string\n}\n\nconst verifyContextSchema = z.object({\n challenge: z.object({\n challenge: z.string().min(1),\n createdAt: z.number().int().nonnegative(),\n }),\n})\n\nconst AUTHENTICATOR_TRANSPORTS: AuthenticatorTransportFuture[] = [\n 'ble',\n 'cable',\n 'hybrid',\n 'internal',\n 'nfc',\n 'smart-card',\n 'usb',\n]\n\nexport class PasskeyProvider implements MfaProviderInterface {\n readonly type = 'passkey'\n readonly label = 'Passkey'\n readonly icon = 'Key'\n readonly allowMultiple = true\n readonly setupSchema = setupPayloadSchema\n readonly verifySchema = verifyPayloadSchema\n\n constructor(\n private readonly securityConfig: SecurityModuleConfig = readSecurityModuleConfig(),\n private readonly setupTokenSecret: string = readSecuritySetupTokenSecret(),\n ) {}\n\n resolveSetupPayload(user: MfaProviderUser, payload: unknown): unknown {\n const parsed = setupPayloadSchema.parse(payload ?? {})\n const email = typeof user.email === 'string' ? user.email.trim() : ''\n\n return {\n ...parsed,\n ...(parsed.label || email.length === 0 ? {} : { label: email }),\n ...(parsed.userName || email.length === 0 ? {} : { userName: email }),\n }\n }\n\n async setup(\n userId: string,\n payload: unknown,\n context?: MfaProviderRuntimeContext,\n ): Promise<{ setupId: string; clientData: Record<string, unknown> }> {\n const parsed = setupPayloadSchema.parse(payload ?? {})\n const userName = parsed.userName ?? parsed.label ?? userId\n const userDisplayName = parsed.label ?? parsed.userName ?? userId\n const securityConfig = this.resolveSecurityConfig(context)\n const options = await generateRegistrationOptions({\n rpName: this.getRpName(securityConfig),\n rpID: this.getRpId(securityConfig),\n userID: this.toWebAuthnUserId(userId),\n userName,\n userDisplayName,\n timeout: securityConfig.webauthn.setupTtlMs,\n attestationType: 'none',\n authenticatorSelection: {\n residentKey: 'required',\n userVerification: 'preferred',\n ...(parsed.authenticatorAttachment ? { authenticatorAttachment: parsed.authenticatorAttachment } : {}),\n },\n })\n\n const now = Date.now()\n const setupId = this.createSetupToken({\n version: SETUP_TOKEN_VERSION,\n userId,\n challenge: options.challenge,\n label: parsed.label,\n createdAt: now,\n nonce: randomBytes(16).toString('hex'),\n })\n\n return {\n setupId,\n clientData: options as unknown as Record<string, unknown>,\n }\n }\n\n async confirmSetup(\n userId: string,\n setupId: string,\n payload: unknown,\n context?: MfaProviderRuntimeContext,\n ): Promise<MfaProviderConfirmResult> {\n const parsed = setupConfirmationPayloadSchema.parse(payload)\n const pending = this.readSetupToken(setupId)\n const securityConfig = this.resolveSecurityConfig(context)\n if (!pending || pending.version !== SETUP_TOKEN_VERSION || pending.userId !== userId) {\n throw new Error('Passkey setup session not found')\n }\n if (Date.now() - pending.createdAt > securityConfig.webauthn.setupTtlMs) {\n throw new Error('Passkey setup session expired')\n }\n\n if ('response' in parsed) {\n const verification = await verifyRegistrationResponse({\n response: parsed.response as never,\n expectedChallenge: pending.challenge,\n expectedOrigin: this.getExpectedOrigins(securityConfig),\n expectedRPID: this.getRpId(securityConfig),\n requireUserVerification: false,\n })\n\n if (!verification.verified || !verification.registrationInfo) {\n throw new Error('Passkey registration verification failed')\n }\n\n const registrationInfo = verification.registrationInfo as {\n credential?: {\n id: string\n publicKey: Uint8Array\n counter: number\n transports?: string[]\n }\n credentialID?: string\n credentialPublicKey?: Uint8Array\n counter?: number\n }\n\n const credentialId = registrationInfo.credential?.id ?? registrationInfo.credentialID\n const publicKeyBytes = registrationInfo.credential?.publicKey ?? registrationInfo.credentialPublicKey\n const counter = registrationInfo.credential?.counter ?? registrationInfo.counter ?? 0\n const transports = this.normalizeTransports(registrationInfo.credential?.transports)\n\n if (!credentialId || !publicKeyBytes) {\n throw new Error('Passkey registration did not return credential data')\n }\n\n return {\n metadata: {\n credentialId,\n credentialPublicKey: this.bytesToBase64Url(publicKeyBytes),\n counter,\n transports,\n label: parsed.label ?? pending.label ?? 'Passkey',\n },\n }\n }\n\n if (parsed.challenge !== pending.challenge) {\n throw new Error('Invalid passkey setup challenge')\n }\n\n return {\n metadata: {\n credentialId: parsed.credentialId,\n credentialPublicKey: parsed.publicKey,\n counter: 0,\n transports: parsed.transports ?? [],\n label: parsed.label ?? pending.label ?? 'Passkey',\n },\n }\n }\n\n async prepareChallenge(\n userId: string,\n method: MfaMethodRecord,\n context?: MfaProviderRuntimeContext,\n ): Promise<{ clientData?: Record<string, unknown>; verifyContext?: MfaVerifyContext }> {\n if (method.userId !== userId) {\n throw new Error('MFA method does not belong to user')\n }\n\n const metadata = method.providerMetadata ?? {}\n const credentialId = typeof metadata.credentialId === 'string' ? metadata.credentialId : null\n if (!credentialId) {\n throw new Error('Passkey credential is not configured')\n }\n\n const securityConfig = this.resolveSecurityConfig(context)\n const options = await generateAuthenticationOptions({\n rpID: this.getRpId(securityConfig),\n userVerification: 'preferred',\n timeout: securityConfig.webauthn.challengeTtlMs,\n allowCredentials: [{\n id: credentialId,\n transports: this.normalizeTransports(metadata.transports),\n }],\n })\n\n const now = Date.now()\n\n return {\n clientData: options as unknown as Record<string, unknown>,\n verifyContext: {\n challenge: {\n challenge: options.challenge,\n createdAt: now,\n },\n },\n }\n }\n\n async verify(\n userId: string,\n method: MfaMethodRecord,\n payload: unknown,\n context?: MfaVerifyContext,\n runtimeContext?: MfaProviderRuntimeContext,\n ): Promise<boolean> {\n const parsed = verifyPayloadSchema.parse(payload)\n if (method.userId !== userId) return false\n\n const parsedContext = verifyContextSchema.safeParse(context)\n const securityConfig = this.resolveSecurityConfig(runtimeContext)\n if (!parsedContext.success) {\n if ('credentialId' in parsed) {\n const metadataCredentialId = method.providerMetadata?.credentialId\n return typeof metadataCredentialId === 'string' && metadataCredentialId === parsed.credentialId\n }\n return false\n }\n const pending = parsedContext.data.challenge\n if (Date.now() - pending.createdAt > securityConfig.webauthn.challengeTtlMs) {\n return false\n }\n\n if ('response' in parsed) {\n const metadata = method.providerMetadata ?? {}\n const credentialId = typeof metadata.credentialId === 'string' ? metadata.credentialId : null\n const credentialPublicKey = typeof metadata.credentialPublicKey === 'string'\n ? metadata.credentialPublicKey\n : typeof metadata.publicKey === 'string'\n ? metadata.publicKey\n : null\n const counter = typeof metadata.counter === 'number' && Number.isFinite(metadata.counter)\n ? metadata.counter\n : 0\n\n if (!credentialId || !credentialPublicKey) {\n return false\n }\n\n const verification = await verifyAuthenticationResponse({\n response: parsed.response as never,\n expectedChallenge: pending.challenge,\n expectedOrigin: this.getExpectedOrigins(securityConfig),\n expectedRPID: this.getRpId(securityConfig),\n requireUserVerification: false,\n credential: {\n id: credentialId,\n publicKey: this.base64UrlToBytes(credentialPublicKey),\n counter,\n transports: this.normalizeTransports(metadata.transports),\n },\n })\n\n if (!verification.verified) {\n return false\n }\n\n const nextCounter = verification.authenticationInfo?.newCounter\n if (typeof nextCounter === 'number' && Number.isFinite(nextCounter)) {\n const providerMetadata = method.providerMetadata ?? {}\n providerMetadata.counter = nextCounter\n method.providerMetadata = providerMetadata\n }\n\n return true\n }\n\n const metadataCredentialId = method.providerMetadata?.credentialId\n if (typeof metadataCredentialId !== 'string' || metadataCredentialId !== parsed.credentialId) {\n return false\n }\n if (pending.challenge !== parsed.challenge) {\n return false\n }\n\n return true\n }\n\n private normalizeTransports(raw: unknown): AuthenticatorTransportFuture[] {\n if (!Array.isArray(raw)) return []\n return raw.filter((value: unknown): value is AuthenticatorTransportFuture =>\n typeof value === 'string' && AUTHENTICATOR_TRANSPORTS.includes(value as AuthenticatorTransportFuture),\n )\n }\n\n private bytesToBase64Url(value: Uint8Array): string {\n return Buffer.from(value).toString('base64url')\n }\n\n private base64UrlToBytes(value: string): Uint8Array {\n return new Uint8Array(Buffer.from(value, 'base64url'))\n }\n\n private createSetupToken(setup: PendingSetup): string {\n const encodedPayload = Buffer.from(JSON.stringify(setup), 'utf8').toString('base64url')\n const signature = this.signSetupPayload(encodedPayload)\n return `${encodedPayload}.${signature}`\n }\n\n private readSetupToken(token: string): PendingSetup | null {\n const [encodedPayload, signature, ...extra] = token.split('.')\n if (!encodedPayload || !signature || extra.length > 0) {\n return null\n }\n\n const expectedSignature = this.signSetupPayload(encodedPayload)\n const providedBuffer = Buffer.from(signature, 'base64url')\n const expectedBuffer = Buffer.from(expectedSignature, 'base64url')\n if (providedBuffer.length !== expectedBuffer.length || !timingSafeEqual(providedBuffer, expectedBuffer)) {\n return null\n }\n\n try {\n const raw = Buffer.from(encodedPayload, 'base64url').toString('utf8')\n const parsed = JSON.parse(raw)\n const result = setupTokenSchema.safeParse(parsed)\n return result.success ? result.data : null\n } catch {\n return null\n }\n }\n\n private signSetupPayload(encodedPayload: string): string {\n return createHmac('sha256', this.getSetupTokenSecret()).update(encodedPayload).digest('base64url')\n }\n\n private getSetupTokenSecret(): string {\n return this.setupTokenSecret\n }\n\n private getRpName(securityConfig: SecurityModuleConfig): string {\n return securityConfig.webauthn.rpName\n }\n\n private getRpId(securityConfig: SecurityModuleConfig): string {\n return securityConfig.webauthn.rpId\n }\n\n private getExpectedOrigins(securityConfig: SecurityModuleConfig): string[] {\n return [...securityConfig.webauthn.expectedOrigins]\n }\n\n private resolveSecurityConfig(context?: MfaProviderRuntimeContext): SecurityModuleConfig {\n return resolveSecurityModuleConfigForRequest(this.securityConfig, context?.request)\n }\n\n private toWebAuthnUserId(userId: string): Uint8Array {\n return new TextEncoder().encode(userId)\n }\n}\n\nexport default PasskeyProvider\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'\nimport {\n generateAuthenticationOptions,\n generateRegistrationOptions,\n verifyAuthenticationResponse,\n verifyRegistrationResponse,\n} from '@simplewebauthn/server'\nimport type { AuthenticatorTransportFuture } from '@simplewebauthn/types'\nimport { z } from 'zod'\nimport type {\n MfaMethodRecord,\n MfaProviderConfirmResult,\n MfaProviderInterface,\n MfaProviderRuntimeContext,\n MfaProviderUser,\n MfaVerifyContext,\n} from '../mfa-provider-interface'\nimport type { SecurityModuleConfig } from '../security-config'\nimport {\n readSecurityModuleConfig,\n readSecuritySetupTokenSecret,\n resolveSecurityModuleConfigForRequest,\n} from '../security-config'\n\nconst SETUP_TOKEN_VERSION = 'v1'\n\nconst setupPayloadSchema = z.object({\n label: z.string().min(1).max(100).optional(),\n userName: z.string().min(1).max(255).optional(),\n authenticatorAttachment: z.enum(['platform', 'cross-platform']).optional(),\n})\n\nconst setupConfirmationPayloadSchema = z.union([\n z.object({\n response: z.record(z.string(), z.unknown()),\n label: z.string().min(1).max(100).optional(),\n }),\n z.object({\n credentialId: z.string().min(1),\n publicKey: z.string().min(1),\n challenge: z.string().min(1),\n transports: z.array(z.string().min(1)).optional(),\n label: z.string().min(1).max(100).optional(),\n }),\n])\n\nconst verifyPayloadSchema = z.union([\n z.object({\n response: z.record(z.string(), z.unknown()),\n }),\n z.object({\n credentialId: z.string().min(1),\n challenge: z.string().min(1),\n }),\n])\n\nconst setupTokenSchema = z.object({\n version: z.string().min(1),\n userId: z.string().min(1),\n challenge: z.string().min(1),\n label: z.string().min(1).max(100).optional(),\n createdAt: z.number().int().nonnegative(),\n nonce: z.string().min(1),\n})\n\ntype PendingSetup = {\n version: string\n userId: string\n challenge: string\n label?: string\n createdAt: number\n nonce: string\n}\n\nconst verifyContextSchema = z.object({\n challenge: z.object({\n challenge: z.string().min(1),\n createdAt: z.number().int().nonnegative(),\n }),\n})\n\nconst AUTHENTICATOR_TRANSPORTS: AuthenticatorTransportFuture[] = [\n 'ble',\n 'cable',\n 'hybrid',\n 'internal',\n 'nfc',\n 'smart-card',\n 'usb',\n]\n\nexport class PasskeyProvider implements MfaProviderInterface {\n readonly type = 'passkey'\n readonly label = 'Passkey'\n readonly icon = 'Key'\n readonly allowMultiple = true\n readonly setupSchema = setupPayloadSchema\n readonly verifySchema = verifyPayloadSchema\n\n constructor(\n private readonly securityConfig: SecurityModuleConfig = readSecurityModuleConfig(),\n private readonly setupTokenSecret: string = readSecuritySetupTokenSecret(),\n ) {}\n\n resolveSetupPayload(user: MfaProviderUser, payload: unknown): unknown {\n const parsed = setupPayloadSchema.parse(payload ?? {})\n const email = typeof user.email === 'string' ? user.email.trim() : ''\n\n return {\n ...parsed,\n ...(parsed.label || email.length === 0 ? {} : { label: email }),\n ...(parsed.userName || email.length === 0 ? {} : { userName: email }),\n }\n }\n\n async setup(\n userId: string,\n payload: unknown,\n context?: MfaProviderRuntimeContext,\n ): Promise<{ setupId: string; clientData: Record<string, unknown> }> {\n const parsed = setupPayloadSchema.parse(payload ?? {})\n const userName = parsed.userName ?? parsed.label ?? userId\n const userDisplayName = parsed.label ?? parsed.userName ?? userId\n const securityConfig = this.resolveSecurityConfig(context)\n const options = await generateRegistrationOptions({\n rpName: this.getRpName(securityConfig),\n rpID: this.getRpId(securityConfig),\n userID: this.toWebAuthnUserId(userId),\n userName,\n userDisplayName,\n timeout: securityConfig.webauthn.setupTtlMs,\n attestationType: 'none',\n authenticatorSelection: {\n residentKey: 'required',\n userVerification: 'preferred',\n ...(parsed.authenticatorAttachment ? { authenticatorAttachment: parsed.authenticatorAttachment } : {}),\n },\n })\n\n const now = Date.now()\n const setupId = this.createSetupToken({\n version: SETUP_TOKEN_VERSION,\n userId,\n challenge: options.challenge,\n label: parsed.label,\n createdAt: now,\n nonce: randomBytes(16).toString('hex'),\n })\n\n return {\n setupId,\n clientData: options as unknown as Record<string, unknown>,\n }\n }\n\n async confirmSetup(\n userId: string,\n setupId: string,\n payload: unknown,\n context?: MfaProviderRuntimeContext,\n ): Promise<MfaProviderConfirmResult> {\n const parsed = setupConfirmationPayloadSchema.parse(payload)\n const pending = this.readSetupToken(setupId)\n const securityConfig = this.resolveSecurityConfig(context)\n if (!pending || pending.version !== SETUP_TOKEN_VERSION || pending.userId !== userId) {\n throw new Error('Passkey setup session not found')\n }\n if (Date.now() - pending.createdAt > securityConfig.webauthn.setupTtlMs) {\n throw new Error('Passkey setup session expired')\n }\n\n if ('response' in parsed) {\n const verification = await verifyRegistrationResponse({\n response: parsed.response as never,\n expectedChallenge: pending.challenge,\n expectedOrigin: this.getExpectedOrigins(securityConfig),\n expectedRPID: this.getRpId(securityConfig),\n requireUserVerification: false,\n })\n\n if (!verification.verified || !verification.registrationInfo) {\n throw new Error('Passkey registration verification failed')\n }\n\n const registrationInfo = verification.registrationInfo as {\n credential?: {\n id: string\n publicKey: Uint8Array\n counter: number\n transports?: string[]\n }\n credentialID?: string\n credentialPublicKey?: Uint8Array\n counter?: number\n }\n\n const credentialId = registrationInfo.credential?.id ?? registrationInfo.credentialID\n const publicKeyBytes = registrationInfo.credential?.publicKey ?? registrationInfo.credentialPublicKey\n const counter = registrationInfo.credential?.counter ?? registrationInfo.counter ?? 0\n const transports = this.normalizeTransports(registrationInfo.credential?.transports)\n\n if (!credentialId || !publicKeyBytes) {\n throw new Error('Passkey registration did not return credential data')\n }\n\n return {\n metadata: {\n credentialId,\n credentialPublicKey: this.bytesToBase64Url(publicKeyBytes),\n counter,\n transports,\n label: parsed.label ?? pending.label ?? 'Passkey',\n },\n }\n }\n\n if (parsed.challenge !== pending.challenge) {\n throw new Error('Invalid passkey setup challenge')\n }\n\n return {\n metadata: {\n credentialId: parsed.credentialId,\n credentialPublicKey: parsed.publicKey,\n counter: 0,\n transports: parsed.transports ?? [],\n label: parsed.label ?? pending.label ?? 'Passkey',\n },\n }\n }\n\n async prepareChallenge(\n userId: string,\n method: MfaMethodRecord,\n context?: MfaProviderRuntimeContext,\n ): Promise<{ clientData?: Record<string, unknown>; verifyContext?: MfaVerifyContext }> {\n if (method.userId !== userId) {\n throw new Error('MFA method does not belong to user')\n }\n\n const metadata = method.providerMetadata ?? {}\n const credentialId = typeof metadata.credentialId === 'string' ? metadata.credentialId : null\n if (!credentialId) {\n throw new Error('Passkey credential is not configured')\n }\n\n const securityConfig = this.resolveSecurityConfig(context)\n const options = await generateAuthenticationOptions({\n rpID: this.getRpId(securityConfig),\n userVerification: 'preferred',\n timeout: securityConfig.webauthn.challengeTtlMs,\n allowCredentials: [{\n id: credentialId,\n transports: this.normalizeTransports(metadata.transports),\n }],\n })\n\n const now = Date.now()\n\n return {\n clientData: options as unknown as Record<string, unknown>,\n verifyContext: {\n challenge: {\n challenge: options.challenge,\n createdAt: now,\n },\n },\n }\n }\n\n async verify(\n userId: string,\n method: MfaMethodRecord,\n payload: unknown,\n context?: MfaVerifyContext,\n runtimeContext?: MfaProviderRuntimeContext,\n ): Promise<boolean> {\n const parsed = verifyPayloadSchema.parse(payload)\n if (method.userId !== userId) return false\n\n const parsedContext = verifyContextSchema.safeParse(context)\n const securityConfig = this.resolveSecurityConfig(runtimeContext)\n if (!parsedContext.success) {\n if ('credentialId' in parsed) {\n const metadataCredentialId = method.providerMetadata?.credentialId\n return typeof metadataCredentialId === 'string' && metadataCredentialId === parsed.credentialId\n }\n return false\n }\n const pending = parsedContext.data.challenge\n if (Date.now() - pending.createdAt > securityConfig.webauthn.challengeTtlMs) {\n return false\n }\n\n if ('response' in parsed) {\n const metadata = method.providerMetadata ?? {}\n const credentialId = typeof metadata.credentialId === 'string' ? metadata.credentialId : null\n const credentialPublicKey = typeof metadata.credentialPublicKey === 'string'\n ? metadata.credentialPublicKey\n : typeof metadata.publicKey === 'string'\n ? metadata.publicKey\n : null\n const counter = typeof metadata.counter === 'number' && Number.isFinite(metadata.counter)\n ? metadata.counter\n : 0\n\n if (!credentialId || !credentialPublicKey) {\n return false\n }\n\n const verification = await verifyAuthenticationResponse({\n response: parsed.response as never,\n expectedChallenge: pending.challenge,\n expectedOrigin: this.getExpectedOrigins(securityConfig),\n expectedRPID: this.getRpId(securityConfig),\n requireUserVerification: false,\n credential: {\n id: credentialId,\n publicKey: this.base64UrlToBytes(credentialPublicKey),\n counter,\n transports: this.normalizeTransports(metadata.transports),\n },\n })\n\n if (!verification.verified) {\n return false\n }\n\n const nextCounter = verification.authenticationInfo?.newCounter\n if (typeof nextCounter === 'number' && Number.isFinite(nextCounter)) {\n const providerMetadata = method.providerMetadata ?? {}\n providerMetadata.counter = nextCounter\n method.providerMetadata = providerMetadata\n }\n\n return true\n }\n\n const metadataCredentialId = method.providerMetadata?.credentialId\n if (typeof metadataCredentialId !== 'string' || metadataCredentialId !== parsed.credentialId) {\n return false\n }\n if (pending.challenge !== parsed.challenge) {\n return false\n }\n\n return true\n }\n\n private normalizeTransports(raw: unknown): AuthenticatorTransportFuture[] {\n if (!Array.isArray(raw)) return []\n return raw.filter((value: unknown): value is AuthenticatorTransportFuture =>\n typeof value === 'string' && AUTHENTICATOR_TRANSPORTS.includes(value as AuthenticatorTransportFuture),\n )\n }\n\n private bytesToBase64Url(value: Uint8Array): string {\n return Buffer.from(value).toString('base64url')\n }\n\n private base64UrlToBytes(value: string) {\n return new Uint8Array(Buffer.from(value, 'base64url')).slice()\n }\n\n private createSetupToken(setup: PendingSetup): string {\n const encodedPayload = Buffer.from(JSON.stringify(setup), 'utf8').toString('base64url')\n const signature = this.signSetupPayload(encodedPayload)\n return `${encodedPayload}.${signature}`\n }\n\n private readSetupToken(token: string): PendingSetup | null {\n const [encodedPayload, signature, ...extra] = token.split('.')\n if (!encodedPayload || !signature || extra.length > 0) {\n return null\n }\n\n const expectedSignature = this.signSetupPayload(encodedPayload)\n const providedBuffer = Buffer.from(signature, 'base64url')\n const expectedBuffer = Buffer.from(expectedSignature, 'base64url')\n if (providedBuffer.length !== expectedBuffer.length || !timingSafeEqual(providedBuffer, expectedBuffer)) {\n return null\n }\n\n try {\n const raw = Buffer.from(encodedPayload, 'base64url').toString('utf8')\n const parsed = JSON.parse(raw)\n const result = setupTokenSchema.safeParse(parsed)\n return result.success ? result.data : null\n } catch {\n return null\n }\n }\n\n private signSetupPayload(encodedPayload: string): string {\n return createHmac('sha256', this.getSetupTokenSecret()).update(encodedPayload).digest('base64url')\n }\n\n private getSetupTokenSecret(): string {\n return this.setupTokenSecret\n }\n\n private getRpName(securityConfig: SecurityModuleConfig): string {\n return securityConfig.webauthn.rpName\n }\n\n private getRpId(securityConfig: SecurityModuleConfig): string {\n return securityConfig.webauthn.rpId\n }\n\n private getExpectedOrigins(securityConfig: SecurityModuleConfig): string[] {\n return [...securityConfig.webauthn.expectedOrigins]\n }\n\n private resolveSecurityConfig(context?: MfaProviderRuntimeContext): SecurityModuleConfig {\n return resolveSecurityModuleConfigForRequest(this.securityConfig, context?.request)\n }\n\n private toWebAuthnUserId(userId: string) {\n return new TextEncoder().encode(userId).slice()\n }\n}\n\nexport default PasskeyProvider\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["metadataCredentialId"]
|
|
7
7
|
}
|
|
@@ -2,6 +2,10 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import { toAbsoluteUrl } from "@open-mercato/shared/lib/url";
|
|
3
3
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
4
|
import { emitSsoEvent } from "../../../events.js";
|
|
5
|
+
const metadata = {
|
|
6
|
+
GET: { requireAuth: false },
|
|
7
|
+
POST: { requireAuth: false }
|
|
8
|
+
};
|
|
5
9
|
function parseCookie(req, name) {
|
|
6
10
|
const cookie = req.headers.get("cookie") || "";
|
|
7
11
|
const m = cookie.match(new RegExp("(?:^|;\\s*)" + name + "=([^;]+)"));
|
|
@@ -98,6 +102,7 @@ const openApi = {
|
|
|
98
102
|
export {
|
|
99
103
|
GET,
|
|
100
104
|
POST,
|
|
105
|
+
metadata,
|
|
101
106
|
openApi
|
|
102
107
|
};
|
|
103
108
|
//# sourceMappingURL=route.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/sso/api/callback/oidc/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { toAbsoluteUrl } from '@open-mercato/shared/lib/url'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoService } from '../../../services/ssoService'\nimport { emitSsoEvent } from '../../../events'\n\nfunction parseCookie(req: Request, name: string): string | null {\n const cookie = req.headers.get('cookie') || ''\n const m = cookie.match(new RegExp('(?:^|;\\\\s*)' + name + '=([^;]+)'))\n return m ? decodeURIComponent(m[1]) : null\n}\n\nasync function handleCallback(req: Request): Promise<NextResponse> {\n try {\n const url = new URL(req.url)\n const callbackParams: Record<string, string> = {}\n url.searchParams.forEach((value, key) => {\n callbackParams[key] = value\n })\n\n if (req.method === 'POST') {\n const contentType = req.headers.get('content-type') || ''\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const form = await req.formData()\n form.forEach((value, key) => {\n callbackParams[key] = String(value)\n })\n }\n }\n\n const stateCookie = parseCookie(req, 'sso_state')\n if (!stateCookie) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_state_missing'))\n }\n\n if (callbackParams.error) {\n void emitSsoEvent('sso.login.failed', {\n reason: callbackParams.error,\n }).catch((e) => console.error('[SSO Event]', e))\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_idp_error'))\n }\n\n if (!callbackParams.code || !callbackParams.state) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_missing_params'))\n }\n\n const redirectUri = toAbsoluteUrl(req, '/api/sso/callback/oidc')\n const container = await createRequestContainer()\n const ssoService = container.resolve<SsoService>('ssoService')\n\n const result = await ssoService.handleOidcCallback(callbackParams, stateCookie, redirectUri)\n\n const res = NextResponse.redirect(toAbsoluteUrl(req, result.redirectUrl))\n\n res.cookies.set('auth_token', result.token, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n maxAge: 60 * 60 * 8,\n })\n\n res.cookies.set('session_token', result.sessionToken, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n expires: result.sessionExpiresAt,\n })\n\n res.cookies.set('sso_state', '', { path: '/', maxAge: 0 })\n\n return res\n } catch (err) {\n console.error('[SSO Callback] Error:', err)\n void emitSsoEvent('sso.login.failed', {\n reason: err instanceof Error ? err.message : 'callback_failed',\n }).catch((e) => console.error('[SSO Event]', e))\n const message = err instanceof Error ? err.message : ''\n const errorCode = message.includes('email is not verified') ? 'sso_email_not_verified' : 'sso_failed'\n return NextResponse.redirect(toAbsoluteUrl(req, `/login?error=${errorCode}`))\n }\n}\n\nexport async function GET(req: Request) {\n return handleCallback(req)\n}\n\nexport async function POST(req: Request) {\n return handleCallback(req)\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'OIDC callback',\n methods: {\n GET: {\n summary: 'Handle OIDC callback (GET)',\n description: 'Receives the authorization code from the IdP, exchanges it for tokens, resolves the user, and issues auth cookies.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n POST: {\n summary: 'Handle OIDC callback (POST)',\n description: 'Some IdPs send the callback as a POST (form_post response mode). Handles the same flow as the GET variant.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAEvC,SAAS,oBAAoB;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { toAbsoluteUrl } from '@open-mercato/shared/lib/url'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoService } from '../../../services/ssoService'\nimport { emitSsoEvent } from '../../../events'\n\nexport const metadata = {\n GET: { requireAuth: false },\n POST: { requireAuth: false },\n}\n\nfunction parseCookie(req: Request, name: string): string | null {\n const cookie = req.headers.get('cookie') || ''\n const m = cookie.match(new RegExp('(?:^|;\\\\s*)' + name + '=([^;]+)'))\n return m ? decodeURIComponent(m[1]) : null\n}\n\nasync function handleCallback(req: Request): Promise<NextResponse> {\n try {\n const url = new URL(req.url)\n const callbackParams: Record<string, string> = {}\n url.searchParams.forEach((value, key) => {\n callbackParams[key] = value\n })\n\n if (req.method === 'POST') {\n const contentType = req.headers.get('content-type') || ''\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const form = await req.formData()\n form.forEach((value, key) => {\n callbackParams[key] = String(value)\n })\n }\n }\n\n const stateCookie = parseCookie(req, 'sso_state')\n if (!stateCookie) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_state_missing'))\n }\n\n if (callbackParams.error) {\n void emitSsoEvent('sso.login.failed', {\n reason: callbackParams.error,\n }).catch((e) => console.error('[SSO Event]', e))\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_idp_error'))\n }\n\n if (!callbackParams.code || !callbackParams.state) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_missing_params'))\n }\n\n const redirectUri = toAbsoluteUrl(req, '/api/sso/callback/oidc')\n const container = await createRequestContainer()\n const ssoService = container.resolve<SsoService>('ssoService')\n\n const result = await ssoService.handleOidcCallback(callbackParams, stateCookie, redirectUri)\n\n const res = NextResponse.redirect(toAbsoluteUrl(req, result.redirectUrl))\n\n res.cookies.set('auth_token', result.token, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n maxAge: 60 * 60 * 8,\n })\n\n res.cookies.set('session_token', result.sessionToken, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n expires: result.sessionExpiresAt,\n })\n\n res.cookies.set('sso_state', '', { path: '/', maxAge: 0 })\n\n return res\n } catch (err) {\n console.error('[SSO Callback] Error:', err)\n void emitSsoEvent('sso.login.failed', {\n reason: err instanceof Error ? err.message : 'callback_failed',\n }).catch((e) => console.error('[SSO Event]', e))\n const message = err instanceof Error ? err.message : ''\n const errorCode = message.includes('email is not verified') ? 'sso_email_not_verified' : 'sso_failed'\n return NextResponse.redirect(toAbsoluteUrl(req, `/login?error=${errorCode}`))\n }\n}\n\nexport async function GET(req: Request) {\n return handleCallback(req)\n}\n\nexport async function POST(req: Request) {\n return handleCallback(req)\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'OIDC callback',\n methods: {\n GET: {\n summary: 'Handle OIDC callback (GET)',\n description: 'Receives the authorization code from the IdP, exchanges it for tokens, resolves the user, and issues auth cookies.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n POST: {\n summary: 'Handle OIDC callback (POST)',\n description: 'Some IdPs send the callback as a POST (form_post response mode). Handles the same flow as the GET variant.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
3
|
import { hrdRequestSchema } from "../../data/validators.js";
|
|
4
|
+
const metadata = {
|
|
5
|
+
POST: { requireAuth: false }
|
|
6
|
+
};
|
|
4
7
|
async function POST(req) {
|
|
5
8
|
try {
|
|
6
9
|
const body = await req.json();
|
|
@@ -47,6 +50,7 @@ const openApi = {
|
|
|
47
50
|
};
|
|
48
51
|
export {
|
|
49
52
|
POST,
|
|
53
|
+
metadata,
|
|
50
54
|
openApi
|
|
51
55
|
};
|
|
52
56
|
//# sourceMappingURL=route.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sso/api/hrd/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { HrdService } from '../../services/hrdService'\nimport { hrdRequestSchema } from '../../data/validators'\n\nexport async function POST(req: Request) {\n try {\n const body = await req.json()\n const parsed = hrdRequestSchema.safeParse(body)\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const hrdService = container.resolve<HrdService>('hrdService')\n const config = await hrdService.findActiveConfigByEmailDomain(parsed.data.email)\n\n if (!config) {\n return NextResponse.json({ hasSso: false })\n }\n\n return NextResponse.json({\n hasSso: true,\n configId: config.id,\n protocol: config.protocol,\n })\n } catch (err) {\n console.error('[SSO HRD] Error:', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Home Realm Discovery',\n methods: {\n POST: {\n summary: 'Check if email domain has SSO configured',\n description: 'Given an email address, determines if the associated organization has an active SSO configuration. Called from the login page before authentication.',\n tags: ['SSO'],\n requestBody: {\n contentType: 'application/json',\n schema: hrdRequestSchema,\n },\n responses: [\n { status: 200, description: 'HRD result' },\n ],\n errors: [\n { status: 400, description: 'Invalid request' },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAEvC,SAAS,wBAAwB;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { HrdService } from '../../services/hrdService'\nimport { hrdRequestSchema } from '../../data/validators'\n\nexport const metadata = {\n POST: { requireAuth: false },\n}\n\nexport async function POST(req: Request) {\n try {\n const body = await req.json()\n const parsed = hrdRequestSchema.safeParse(body)\n\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const hrdService = container.resolve<HrdService>('hrdService')\n const config = await hrdService.findActiveConfigByEmailDomain(parsed.data.email)\n\n if (!config) {\n return NextResponse.json({ hasSso: false })\n }\n\n return NextResponse.json({\n hasSso: true,\n configId: config.id,\n protocol: config.protocol,\n })\n } catch (err) {\n console.error('[SSO HRD] Error:', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Home Realm Discovery',\n methods: {\n POST: {\n summary: 'Check if email domain has SSO configured',\n description: 'Given an email address, determines if the associated organization has an active SSO configuration. Called from the login page before authentication.',\n tags: ['SSO'],\n requestBody: {\n contentType: 'application/json',\n schema: hrdRequestSchema,\n },\n responses: [\n { status: 200, description: 'HRD result' },\n ],\n errors: [\n { status: 400, description: 'Invalid request' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAEvC,SAAS,wBAAwB;AAE1B,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM;AAC7B;AAEA,eAAsB,KAAK,KAAc;AACvC,MAAI;AACF,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,SAAS,iBAAiB,UAAU,IAAI;AAE9C,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,aAAa,KAAK,EAAE,OAAO,kBAAkB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACxE;AAEA,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,aAAa,UAAU,QAAoB,YAAY;AAC7D,UAAM,SAAS,MAAM,WAAW,8BAA8B,OAAO,KAAK,KAAK;AAE/E,QAAI,CAAC,QAAQ;AACX,aAAO,aAAa,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,IAC5C;AAEA,WAAO,aAAa,KAAK;AAAA,MACvB,QAAQ;AAAA,MACR,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,IACnB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,oBAAoB,GAAG;AACrC,WAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,KAAK;AAAA,MACZ,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,aAAa;AAAA,MAC3C;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,kBAAkB;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,9 @@ import { toAbsoluteUrl } from "@open-mercato/shared/lib/url";
|
|
|
3
3
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
4
|
import { ssoInitiateSchema } from "../../data/validators.js";
|
|
5
5
|
import { emitSsoEvent } from "../../events.js";
|
|
6
|
+
const metadata = {
|
|
7
|
+
GET: { requireAuth: false }
|
|
8
|
+
};
|
|
6
9
|
function sanitizeReturnUrl(raw) {
|
|
7
10
|
const value = raw || "/backend";
|
|
8
11
|
if (!value.startsWith("/") || value.startsWith("//")) return "/backend";
|
|
@@ -61,6 +64,7 @@ const openApi = {
|
|
|
61
64
|
};
|
|
62
65
|
export {
|
|
63
66
|
GET,
|
|
67
|
+
metadata,
|
|
64
68
|
openApi
|
|
65
69
|
};
|
|
66
70
|
//# sourceMappingURL=route.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sso/api/initiate/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { toAbsoluteUrl } from '@open-mercato/shared/lib/url'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoService } from '../../services/ssoService'\nimport { ssoInitiateSchema } from '../../data/validators'\nimport { emitSsoEvent } from '../../events'\n\nfunction sanitizeReturnUrl(raw: string | null): string {\n const value = raw || '/backend'\n if (!value.startsWith('/') || value.startsWith('//')) return '/backend'\n try {\n const parsed = new URL(value, 'http://localhost')\n if (parsed.origin !== 'http://localhost') return '/backend'\n return parsed.pathname + parsed.search + parsed.hash\n } catch {\n return '/backend'\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const url = new URL(req.url)\n const configId = url.searchParams.get('configId')\n const rawReturnUrl = url.searchParams.get('returnUrl')\n\n const parsed = ssoInitiateSchema.safeParse({ configId, returnUrl: rawReturnUrl ?? undefined })\n if (!parsed.success || !parsed.data.configId) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_missing_config'))\n }\n\n const returnUrl = sanitizeReturnUrl(rawReturnUrl)\n const redirectUri = toAbsoluteUrl(req, '/api/sso/callback/oidc')\n const container = await createRequestContainer()\n const ssoService = container.resolve<SsoService>('ssoService')\n\n const { redirectUrl, stateCookie } = await ssoService.initiateLogin(parsed.data.configId, returnUrl, redirectUri)\n\n const res = NextResponse.redirect(redirectUrl)\n res.cookies.set('sso_state', stateCookie, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n maxAge: 300,\n })\n return res\n } catch (err) {\n console.error('[SSO Initiate] Error:', err)\n void emitSsoEvent('sso.login.failed', {\n reason: err instanceof Error ? err.message : 'initiate_failed',\n }).catch((e) => console.error('[SSO Event]', e))\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_failed'))\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Initiate SSO login',\n methods: {\n GET: {\n summary: 'Start SSO login flow',\n description: 'Redirects the browser to the configured IdP authorization endpoint. Sets an encrypted sso_state cookie for CSRF protection.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to IdP authorization endpoint', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAEvC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { toAbsoluteUrl } from '@open-mercato/shared/lib/url'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoService } from '../../services/ssoService'\nimport { ssoInitiateSchema } from '../../data/validators'\nimport { emitSsoEvent } from '../../events'\n\nexport const metadata = {\n GET: { requireAuth: false },\n}\n\nfunction sanitizeReturnUrl(raw: string | null): string {\n const value = raw || '/backend'\n if (!value.startsWith('/') || value.startsWith('//')) return '/backend'\n try {\n const parsed = new URL(value, 'http://localhost')\n if (parsed.origin !== 'http://localhost') return '/backend'\n return parsed.pathname + parsed.search + parsed.hash\n } catch {\n return '/backend'\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const url = new URL(req.url)\n const configId = url.searchParams.get('configId')\n const rawReturnUrl = url.searchParams.get('returnUrl')\n\n const parsed = ssoInitiateSchema.safeParse({ configId, returnUrl: rawReturnUrl ?? undefined })\n if (!parsed.success || !parsed.data.configId) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_missing_config'))\n }\n\n const returnUrl = sanitizeReturnUrl(rawReturnUrl)\n const redirectUri = toAbsoluteUrl(req, '/api/sso/callback/oidc')\n const container = await createRequestContainer()\n const ssoService = container.resolve<SsoService>('ssoService')\n\n const { redirectUrl, stateCookie } = await ssoService.initiateLogin(parsed.data.configId, returnUrl, redirectUri)\n\n const res = NextResponse.redirect(redirectUrl)\n res.cookies.set('sso_state', stateCookie, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n maxAge: 300,\n })\n return res\n } catch (err) {\n console.error('[SSO Initiate] Error:', err)\n void emitSsoEvent('sso.login.failed', {\n reason: err instanceof Error ? err.message : 'initiate_failed',\n }).catch((e) => console.error('[SSO Event]', e))\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_failed'))\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Initiate SSO login',\n methods: {\n GET: {\n summary: 'Start SSO login flow',\n description: 'Redirects the browser to the configured IdP authorization endpoint. Sets an encrypted sso_state cookie for CSRF protection.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to IdP authorization endpoint', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAEvC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAEtB,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM;AAC5B;AAEA,SAAS,kBAAkB,KAA4B;AACrD,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,MAAM,WAAW,GAAG,KAAK,MAAM,WAAW,IAAI,EAAG,QAAO;AAC7D,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,OAAO,kBAAkB;AAChD,QAAI,OAAO,WAAW,mBAAoB,QAAO;AACjD,WAAO,OAAO,WAAW,OAAO,SAAS,OAAO;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,IAAI,KAAc;AACtC,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,UAAM,WAAW,IAAI,aAAa,IAAI,UAAU;AAChD,UAAM,eAAe,IAAI,aAAa,IAAI,WAAW;AAErD,UAAM,SAAS,kBAAkB,UAAU,EAAE,UAAU,WAAW,gBAAgB,OAAU,CAAC;AAC7F,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,KAAK,UAAU;AAC5C,aAAO,aAAa,SAAS,cAAc,KAAK,iCAAiC,CAAC;AAAA,IACpF;AAEA,UAAM,YAAY,kBAAkB,YAAY;AAChD,UAAM,cAAc,cAAc,KAAK,wBAAwB;AAC/D,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,aAAa,UAAU,QAAoB,YAAY;AAE7D,UAAM,EAAE,aAAa,YAAY,IAAI,MAAM,WAAW,cAAc,OAAO,KAAK,UAAU,WAAW,WAAW;AAEhH,UAAM,MAAM,aAAa,SAAS,WAAW;AAC7C,QAAI,QAAQ,IAAI,aAAa,aAAa;AAAA,MACxC,UAAU;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,MACjC,QAAQ;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,MAAM,yBAAyB,GAAG;AAC1C,SAAK,aAAa,oBAAoB;AAAA,MACpC,QAAQ,eAAe,QAAQ,IAAI,UAAU;AAAA,IAC/C,CAAC,EAAE,MAAM,CAAC,MAAM,QAAQ,MAAM,eAAe,CAAC,CAAC;AAC/C,WAAO,aAAa,SAAS,cAAc,KAAK,yBAAyB,CAAC;AAAA,EAC5E;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,KAAK;AAAA,MACZ,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,0CAA0C,WAAW,YAAY;AAAA,MAC/F;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/enterprise",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -64,27 +64,31 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@open-mercato/core": "0.
|
|
68
|
-
"@open-mercato/ui": "0.
|
|
69
|
-
"@simplewebauthn/browser": "^
|
|
70
|
-
"@simplewebauthn/server": "^
|
|
71
|
-
"@simplewebauthn/types": "^
|
|
67
|
+
"@open-mercato/core": "0.5.0",
|
|
68
|
+
"@open-mercato/ui": "0.5.0",
|
|
69
|
+
"@simplewebauthn/browser": "^13.3.0",
|
|
70
|
+
"@simplewebauthn/server": "^13.3.0",
|
|
71
|
+
"@simplewebauthn/types": "^12.0.0",
|
|
72
72
|
"@types/qrcode": "^1.5.5",
|
|
73
|
-
"openid-client": "^6.
|
|
74
|
-
"otpauth": "9.
|
|
73
|
+
"openid-client": "^6.8.3",
|
|
74
|
+
"otpauth": "9.5.0",
|
|
75
75
|
"qrcode": "^1.5.4"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@open-mercato/shared": "0.
|
|
78
|
+
"@open-mercato/shared": "0.5.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@open-mercato/shared": "0.
|
|
81
|
+
"@open-mercato/shared": "0.5.0",
|
|
82
82
|
"@types/jest": "^30.0.0",
|
|
83
|
-
"jest": "^30.
|
|
84
|
-
"ts-jest": "^29.4.
|
|
83
|
+
"jest": "^30.3.0",
|
|
84
|
+
"ts-jest": "^29.4.9"
|
|
85
85
|
},
|
|
86
86
|
"publishConfig": {
|
|
87
87
|
"access": "restricted"
|
|
88
88
|
},
|
|
89
|
-
"
|
|
89
|
+
"repository": {
|
|
90
|
+
"type": "git",
|
|
91
|
+
"url": "https://github.com/open-mercato/open-mercato",
|
|
92
|
+
"directory": "packages/enterprise"
|
|
93
|
+
}
|
|
90
94
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
2
2
|
import { securityApiError } from '../i18n'
|
|
3
3
|
|
|
4
|
+
export const metadata = {
|
|
5
|
+
GET: { requireAuth: true },
|
|
6
|
+
POST: { requireAuth: true },
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
export async function GET() {
|
|
5
10
|
return securityApiError(501, 'Not implemented')
|
|
6
11
|
}
|
|
@@ -358,8 +358,8 @@ export class PasskeyProvider implements MfaProviderInterface {
|
|
|
358
358
|
return Buffer.from(value).toString('base64url')
|
|
359
359
|
}
|
|
360
360
|
|
|
361
|
-
private base64UrlToBytes(value: string)
|
|
362
|
-
return new Uint8Array(Buffer.from(value, 'base64url'))
|
|
361
|
+
private base64UrlToBytes(value: string) {
|
|
362
|
+
return new Uint8Array(Buffer.from(value, 'base64url')).slice()
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
private createSetupToken(setup: PendingSetup): string {
|
|
@@ -415,8 +415,8 @@ export class PasskeyProvider implements MfaProviderInterface {
|
|
|
415
415
|
return resolveSecurityModuleConfigForRequest(this.securityConfig, context?.request)
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
private toWebAuthnUserId(userId: string)
|
|
419
|
-
return new TextEncoder().encode(userId)
|
|
418
|
+
private toWebAuthnUserId(userId: string) {
|
|
419
|
+
return new TextEncoder().encode(userId).slice()
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
|
|
@@ -5,6 +5,11 @@ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
|
5
5
|
import { SsoService } from '../../../services/ssoService'
|
|
6
6
|
import { emitSsoEvent } from '../../../events'
|
|
7
7
|
|
|
8
|
+
export const metadata = {
|
|
9
|
+
GET: { requireAuth: false },
|
|
10
|
+
POST: { requireAuth: false },
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
function parseCookie(req: Request, name: string): string | null {
|
|
9
14
|
const cookie = req.headers.get('cookie') || ''
|
|
10
15
|
const m = cookie.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]+)'))
|
|
@@ -4,6 +4,10 @@ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
|
4
4
|
import { HrdService } from '../../services/hrdService'
|
|
5
5
|
import { hrdRequestSchema } from '../../data/validators'
|
|
6
6
|
|
|
7
|
+
export const metadata = {
|
|
8
|
+
POST: { requireAuth: false },
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
export async function POST(req: Request) {
|
|
8
12
|
try {
|
|
9
13
|
const body = await req.json()
|
|
@@ -6,6 +6,10 @@ import { SsoService } from '../../services/ssoService'
|
|
|
6
6
|
import { ssoInitiateSchema } from '../../data/validators'
|
|
7
7
|
import { emitSsoEvent } from '../../events'
|
|
8
8
|
|
|
9
|
+
export const metadata = {
|
|
10
|
+
GET: { requireAuth: false },
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
function sanitizeReturnUrl(raw: string | null): string {
|
|
10
14
|
const value = raw || '/backend'
|
|
11
15
|
if (!value.startsWith('/') || value.startsWith('//')) return '/backend'
|