import CID from 'cids' ; import multibase from 'multibase' ; import { StreamType } from './stream-type' ; import varint from 'varint' ; import uint8ArrayConcat from 'uint8arrays/concat' ; import uint8ArrayToString from 'uint8arrays/to-string' ; import { Memoize } from 'typescript-memoize' ; import { DEFAULT_BASE , STREAMID_CODEC } from './constants' ; import { readCid , readVarint } from './reading-bytes' ; import { StreamID } from './stream-id' ; import { StreamRef } from './stream-ref' ; param bytes throws see function fromBytes ( bytes ) { const result = fromBytesNoThrow ( bytes ) ; if ( result instanceof Error ) { throw result ; } return result ; } param bytes function fromBytesNoThrow ( bytes ) { const [ streamCodec , streamCodecRemainder ] = readVarint ( bytes ) ; if ( streamCodec !== STREAMID_CODEC ) return new Error ( 'fromBytes: invalid streamid, does not include streamid codec' ) ; const [ type , streamtypeRemainder ] = readVarint ( streamCodecRemainder ) ; const cidResult = readCid ( streamtypeRemainder ) ; if ( cidResult instanceof Error ) { return cidResult ; } const [ base , baseRemainder ] = cidResult ; if ( baseRemainder . length === 0 ) { return new Error ( `No commit information provided` ) ; } else if ( baseRemainder . length === 1 ) { return new CommitID ( type , base , baseRemainder [ 0 ] ) ; } else { const [ commit ] = readCid ( baseRemainder ) ; return new CommitID ( type , base , commit ) ; } } param input function parseCID ( input ) { try { return new CID ( input ) ; } catch { return undefined ; } } param genesis param commit function parseCommit ( genesis , commit = null ) { if ( ! commit ) return null ; const commitCID = parseCID ( commit ) ; if ( commitCID ) { if ( genesis . equals ( commitCID ) ) { return null ; } else { return commitCID ; } } else if ( String ( commit ) === '0' ) { return null ; } else { throw new Error ( 'Cannot specify commit as a number except to request commit 0 (the genesis commit)' ) ; } } param input see see function fromString ( input ) { const result = fromStringNoThrow ( input ) ; if ( result instanceof Error ) { throw result ; } return result ; } param input function fromStringNoThrow ( input ) { const protocolFree = input . replace ( 'ceramic://' , '' ) . replace ( '/ceramic/' , '' ) ; if ( protocolFree . includes ( 'commit' ) ) { const commit = protocolFree . split ( '?' ) [ 1 ] . split ( '=' ) [ 1 ] ; const base = protocolFree . split ( '?' ) [ 0 ] ; return StreamID . fromString ( base ) . atCommit ( commit ) ; } else { return fromBytesNoThrow ( multibase . decode ( protocolFree ) ) ; } } const TAG = Symbol . for ( '@ceramicnetwork/streamid/CommitID' ) ; /**
 * Commit identifier, includes type, genesis CID, commit CID.
 *
 * Encoded as `<multibase-prefix><multicodec-streamid><type><genesis-cid-bytes><commit-cid-bytes>`.
 *
 * String representation is base36-encoding of the bytes above.
 */ export class CommitID implements StreamRef { protected readonly _tag = TAG ; readonly #type : number ; readonly #cid : CID ; readonly #commit : CID | null ; static fromBytes = fromBytes ; static fromBytesNoThrow = fromBytesNoThrow ; static fromString = fromString ; static fromStringNoThrow = fromStringNoThrow ; static isInstance ( instance ) { return typeof instance === 'object' && '_tag' in instance && instance . _tag === TAG ; } param type param { CID | string } cid param { CID | string } commit example constructor ( type , cid , commit = null ) { if ( ! type && type !== 0 ) throw new Error ( 'constructor: type required' ) ; if ( ! cid ) throw new Error ( 'constructor: cid required' ) ; this . #type = typeof type === 'string' ? StreamType . codeByName ( type ) : type ; this . #cid = typeof cid === 'string' ? new CID ( cid ) : cid ; this . #commit = parseCommit ( this . #cid , commit ) ; } /**
     * Construct StreamID, no commit information included
     */ @ Memoize ( ) get baseID ( ) : StreamID { return new StreamID ( this . #type , this . #cid ) ; } /**
     * Stream type code
     */ get type ( ) : number { return this . #type ; } /**
     * Stream type name
     */ @ Memoize ( ) get typeName ( ) : string { return StreamType . nameByCode ( this . #type ) ; } /**
     * Genesis CID
     */ get cid ( ) : CID { return this . #cid ; } /**
     * Commit CID
     */ @ Memoize ( ) get commit ( ) : CID { return this . #commit || this . #cid ; } /**
     * Bytes representation
     */ @ Memoize ( ) get bytes ( ) : Uint8Array { const codec = varint . encode ( STREAMID_CODEC ) ; const type = varint . encode ( this . type ) ; const commitBytes = this . #commit ?. bytes || new Uint8Array ( [ 0 ] ) ; return uint8ArrayConcat ( [ codec , type , this . cid . bytes , commitBytes ] ) ; } /**
     * Construct new CommitID for the same stream, but a new `commit` CID.
     */ atCommit ( commit ) { return new CommitID ( this . #type , this . #cid , commit ) ; } /**
     * Compare equality with another CommitID.
     */ equals ( other ) { return ( this . type === other . type && this . cid . equals ( other . cid ) && this . commit . equals ( other . commit ) ) ; } /**
     * Encode the CommitID into a string.
     */ @ Memoize ( ) toString ( ) { return uint8ArrayToString ( multibase . encode ( DEFAULT_BASE , this . bytes ) ) ; } /**
     * Encode the StreamID into a base36 url
     */ @ Memoize ( ) toUrl ( ) { return `ceramic://${ this . toString ( ) }` ; } returns { String } [ Symbol . for ( 'nodejs.util.inspect.custom' ) ] ( ) { return `CommitID(${ this . toString ( ) })` ; } /**
     * String representation of CommitID.
     */ [ Symbol . toPrimitive ] ( ) { return this . toString ( ) ; } }