import typeDetect from 'type-detect' ; import { LEGACY_URL_ALIAS_TYPE } from '../object_types' ; import { decodeVersion , encodeVersion } from '../version' ; import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry' ; import { SavedObjectsRawDoc , SavedObjectSanitizedDoc , SavedObjectsRawDocParseOptions , } from './types' ; /**
 * A serializer that can be used to manually convert  SavedObjectsRawDoc or
 *  SavedObjectSanitizedDoc documents to the other kind.
 *
 *  remarks Serializer instances should only be created and accessed by calling  SavedObjectsServiceStart . createSerializer public export class SavedObjectsSerializer { private readonly registry : ISavedObjectTypeRegistry ; internal constructor ( registry ) { this . registry = registry ; } param { SavedObjectsRawDoc } doc param { SavedObjectsRawDocParseOptions } options public isRawSavedObject ( doc , options = { } ) { try { this . checkIsRawSavedObject ( doc , options ) ; return true ; } catch ( error ) { } return false ; } private checkIsRawSavedObject ( doc , options = { } ) { const { namespaceTreatment = 'strict' } = options ; const { _id , _source } = doc ; const { type , namespace } = _source ; if ( ! type ) { throw new Error ( `Raw document '${ _id }' is missing _source.type field` ) ; } const { idMatchesPrefix , prefix } = this . parseIdPrefix ( namespace , type , _id , namespaceTreatment ) ; if ( ! idMatchesPrefix ) { throw new Error ( `Raw document '${ _id }' does not start with expected prefix '${ prefix }'` ) ; } return idMatchesPrefix ; } param { SavedObjectsRawDoc } doc param { SavedObjectsRawDocParseOptions } options public rawToSavedObject < T = unknown > ( doc , options = { } ) { this . checkIsRawSavedObject ( doc , options ) ; const { namespaceTreatment = 'strict' } = options ; const { _id , _source , _seq_no , _primary_term } = doc ; const { type , namespaces , originId , migrationVersion , references , coreMigrationVersion } = _source ; const version = _seq_no != null || _primary_term != null ? encodeVersion ( _seq_no ! , _primary_term ! ) : undefined ; const { id , namespace } = this . trimIdPrefix ( _source . namespace , type , _id , namespaceTreatment ) ; const includeNamespace = namespace && ( namespaceTreatment === 'lax' || this . registry . isSingleNamespace ( type ) ) ; const includeNamespaces = this . registry . isMultiNamespace ( type ) ; return { type , id , ... ( includeNamespace && { namespace } ) , ... ( includeNamespaces && { namespaces } ) , ... ( originId && { originId } ) , attributes : _source [ type ] , references : references || [ ] , ... ( migrationVersion && { migrationVersion } ) , ... ( coreMigrationVersion && { coreMigrationVersion } ) , ... ( _source . updated_at && { updated_at : _source . updated_at } ) , ... ( version && { version } ) , } ; } param { SavedObjectSanitizedDoc } savedObj public savedObjectToRaw ( savedObj ) { const { id , type , namespace , namespaces , originId , attributes , migrationVersion , updated_at , version , references , coreMigrationVersion , } = savedObj ; const source = { [ type ] : attributes , type , references , ... ( namespace && this . registry . isSingleNamespace ( type ) && { namespace } ) , ... ( namespaces && this . registry . isMultiNamespace ( type ) && { namespaces } ) , ... ( originId && { originId } ) , ... ( migrationVersion && { migrationVersion } ) , ... ( coreMigrationVersion && { coreMigrationVersion } ) , ... ( updated_at && { updated_at } ) , } ; return { _id : this . generateRawId ( namespace , type , id ) , _source : source , ... ( version != null && decodeVersion ( version ) ) , } ; } param { string } namespace param { string } type param { string } id public generateRawId ( namespace , type , id ) { const namespacePrefix = namespace && this . registry . isSingleNamespace ( type ) ? `${ namespace }:` : '' ; return `${ namespacePrefix }${ type }:${ id }` ; } param { string } namespace param { string } type param { string } id public generateRawLegacyUrlAliasId ( namespace , type , id ) { return `${ LEGACY_URL_ALIAS_TYPE }:${ namespace }:${ type }:${ id }` ; } /**
     * Given a document's source namespace, type, and raw ID, trim the ID prefix (based on the namespaceType), returning the object ID and the
     * detected namespace. A single-namespace object is only considered to exist in a namespace if its raw ID is prefixed by that *and* it has
     * the namespace field in its source.
     */ private trimIdPrefix ( sourceNamespace , type , id , namespaceTreatment ) { assertNonEmptyString ( id , 'document id' ) ; assertNonEmptyString ( type , 'saved object type' ) ; const { prefix , idMatchesPrefix , namespace } = this . parseIdPrefix ( sourceNamespace , type , id , namespaceTreatment ) ; return { id : idMatchesPrefix ? id . slice ( prefix . length ) : id , namespace , } ; } private parseIdPrefix ( sourceNamespace , type , id , namespaceTreatment ) { let prefix ; let namespace ; const parseFlexibly = namespaceTreatment === 'lax' && this . registry . isMultiNamespace ( type ) ; if ( sourceNamespace && ( this . registry . isSingleNamespace ( type ) || parseFlexibly ) ) { prefix = `${ sourceNamespace }:${ type }:` ; if ( parseFlexibly && ! checkIdMatchesPrefix ( id , prefix ) ) { prefix = `${ type }:` ; } else { namespace = sourceNamespace ; } } else { prefix = `${ type }:` ; } return { prefix , idMatchesPrefix : checkIdMatchesPrefix ( id , prefix ) , namespace , } ; } } function checkIdMatchesPrefix ( id , prefix ) { return id . startsWith ( prefix ) && id . length > prefix . length ; } function assertNonEmptyString ( value , name ) { if ( ! value || typeof value !== 'string' ) { throw new TypeError ( `Expected ${ name } to be a string but given [${ typeDetect ( value ) }] with [${ value }] value.` ) ; } }