11import type { ScimUserAttributes , ScimUserEmail } from '@sim/db/schema'
2+ import { isRecordLike } from '@sim/utils/object'
23import type { ScimPatchOperation } from '@/lib/api/contracts/scim'
34import { invalidPath , invalidValue , mutability , noTarget } from '@/ee/scim/lib/protocol/errors'
45import {
5- isRecord ,
66 isScimPasswordAttribute ,
77 normalizeAttributePath ,
88 normalizeScimBoolean ,
@@ -89,7 +89,7 @@ function normalizeEmailList(
8989 const entries = Array . isArray ( value ) ? value : [ value ]
9090 const normalized : ScimUserEmail [ ] = [ ]
9191 for ( const entry of entries ) {
92- if ( ! isRecord ( entry ) ) throw invalidValue ( `${ attribute } entries must be objects` )
92+ if ( ! isRecordLike ( entry ) ) throw invalidValue ( `${ attribute } entries must be objects` )
9393 const address = requireString ( entry . value , `${ attribute } .value` )
9494 normalized . push ( {
9595 value : address . toLowerCase ( ) ,
@@ -146,7 +146,7 @@ function applyOperation(
146146 else user . enterprise = undefined
147147 return
148148 }
149- if ( ! isRecord ( value ) ) throw invalidValue ( `${ path } requires an object value` )
149+ if ( ! isRecordLike ( value ) ) throw invalidValue ( `${ path } requires an object value` )
150150 for ( const [ sub , nested ] of sortFormattedLast ( Object . entries ( value ) ) ) {
151151 applyOperation ( user , op , `${ path } .${ sub } ` , nested )
152152 }
@@ -253,7 +253,7 @@ function applyOperation(
253253 user . enterprise . manager = { value : unwrapped }
254254 return
255255 }
256- if ( isRecord ( unwrapped ) ) {
256+ if ( isRecordLike ( unwrapped ) ) {
257257 user . enterprise . manager = {
258258 ...( typeof unwrapped . value === 'string' ? { value : unwrapped . value } : { } ) ,
259259 ...( typeof unwrapped . displayName === 'string'
@@ -301,7 +301,7 @@ function extensionTarget(
301301 ...( path . length > existing . length ? { attribute : path . slice ( existing . length + 1 ) } : { } ) ,
302302 }
303303 }
304- if ( resourceAttribute && isRecord ( value ) ) return { schema : path }
304+ if ( resourceAttribute && isRecordLike ( value ) ) return { schema : path }
305305 const separator = path . lastIndexOf ( ':' )
306306 if ( separator <= 'urn:' . length ) throw invalidPath ( `User PATCH path ${ path } is not supported` )
307307 return { schema : path . slice ( 0 , separator ) , attribute : path . slice ( separator + 1 ) }
@@ -329,14 +329,14 @@ function applyExtraOperation(
329329 if ( ! extension . attribute ) {
330330 if ( op === 'remove' ) delete user . extra [ extension . schema ]
331331 else {
332- if ( ! isRecord ( value ) ) throw invalidValue ( `${ path } requires an object value` )
332+ if ( ! isRecordLike ( value ) ) throw invalidValue ( `${ path } requires an object value` )
333333 const current = user . extra [ extension . schema ]
334- user . extra [ extension . schema ] = { ...( isRecord ( current ) ? current : { } ) , ...value }
334+ user . extra [ extension . schema ] = { ...( isRecordLike ( current ) ? current : { } ) , ...value }
335335 }
336336 return
337337 }
338338 const current = user . extra [ extension . schema ]
339- const attributes = isRecord ( current ) ? { ...current } : { }
339+ const attributes = isRecordLike ( current ) ? { ...current } : { }
340340 applyExtraAttribute ( attributes , op , extension . attribute , value )
341341 user . extra [ extension . schema ] = attributes
342342 return
@@ -368,18 +368,18 @@ function applyExtraAttribute(
368368 if ( type ) {
369369 const list = Array . isArray ( attributes [ attribute ] ) ? [ ...attributes [ attribute ] ] : [ ]
370370 const index = list . findIndex (
371- ( entry ) => isRecord ( entry ) && String ( entry . type ) . toLowerCase ( ) === type . toLowerCase ( )
371+ ( entry ) => isRecordLike ( entry ) && String ( entry . type ) . toLowerCase ( ) === type . toLowerCase ( )
372372 )
373373 if ( op === 'remove' && ! sub ) {
374374 if ( index !== - 1 ) list . splice ( index , 1 )
375375 } else if ( sub ) {
376376 if ( op === 'remove' && index === - 1 ) return
377- const current = index !== - 1 && isRecord ( list [ index ] ) ? list [ index ] : { type }
377+ const current = index !== - 1 && isRecordLike ( list [ index ] ) ? list [ index ] : { type }
378378 const key = Object . keys ( current ) . find ( ( key ) => key . toLowerCase ( ) === sub . toLowerCase ( ) ) ?? sub
379379 const next = { ...current , [ key ] : op === 'remove' ? undefined : value }
380380 if ( index === - 1 ) list . push ( next )
381381 else list [ index ] = next
382- } else if ( isRecord ( value ) ) {
382+ } else if ( isRecordLike ( value ) ) {
383383 if ( index === - 1 ) list . push ( { type, ...value } )
384384 else list [ index ] = { ...( list [ index ] as Record < string , unknown > ) , ...value }
385385 } else {
@@ -389,7 +389,7 @@ function applyExtraAttribute(
389389 return
390390 }
391391
392- const current = isRecord ( attributes [ attribute ] ) ? { ...attributes [ attribute ] } : { }
392+ const current = isRecordLike ( attributes [ attribute ] ) ? { ...attributes [ attribute ] } : { }
393393 const key = Object . keys ( current ) . find ( ( key ) => key . toLowerCase ( ) === sub . toLowerCase ( ) ) ?? sub
394394 current [ key ] = op === 'remove' ? undefined : value
395395 attributes [ attribute ] = current
@@ -404,7 +404,7 @@ function applyExtraAttribute(
404404 */
405405function sortDeep ( value : unknown ) : unknown {
406406 if ( Array . isArray ( value ) ) return value . map ( sortDeep )
407- if ( ! isRecord ( value ) ) return value
407+ if ( ! isRecordLike ( value ) ) return value
408408 const sorted : Record < string , unknown > = { }
409409 for ( const key of Object . keys ( value ) . sort ( ) ) sorted [ key ] = sortDeep ( value [ key ] )
410410 return sorted
@@ -454,7 +454,7 @@ export function applyUserPatch(
454454
455455 if ( ! operation . path ) {
456456 const value = operation . value
457- if ( ! isRecord ( value ) ) {
457+ if ( ! isRecordLike ( value ) ) {
458458 throw invalidValue ( 'A PATCH operation without a path requires an object value' )
459459 }
460460 /**
0 commit comments