CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-cbor

Encode and parse data in the Concise Binary Object Representation (CBOR) data format (RFC8949).

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

advanced-decoding.mddocs/

Advanced Decoding

Comprehensive decoding functions with support for multiple items, asynchronous operations, extended result information, and fine-grained control over the decoding process.

Capabilities

Decode Multiple Items

Decode all CBOR items from input data that may contain multiple encoded values.

/**
 * Decode all CBOR items from input
 * @param {BufferLike} input - CBOR data containing multiple items
 * @param {DecoderOptions|decodeCallback} [options] - Options or callback
 * @param {decodeCallback} [cb] - Callback function
 * @returns {Promise<any[]>|void} Array of decoded items or void if callback provided
 */
function decodeAll(input, options, cb);

/**
 * Synchronously decode all CBOR items
 * @param {BufferLike} input - CBOR data containing multiple items
 * @param {DecoderOptions} [options] - Decoding options
 * @returns {any[]} Array of decoded items
 */
function decodeAllSync(input, options);

Usage Examples:

const cbor = require("cbor");

// Encode multiple items
const item1 = { name: "Alice", type: "user" };
const item2 = { name: "Bob", type: "admin" };  
const item3 = [1, 2, 3, 4, 5];

const encoded = Buffer.concat([
  cbor.encode(item1),
  cbor.encode(item2),
  cbor.encode(item3)
]);

// Decode all items synchronously
const allItems = cbor.decodeAllSync(encoded);
console.log(allItems); // [{ name: "Alice", type: "user" }, { name: "Bob", type: "admin" }, [1, 2, 3, 4, 5]]

// Decode all items with options
const allItemsWithOptions = cbor.decodeAllSync(encoded, {
  preferMap: true,
  max_depth: 10
});

// Async decoding with callback
cbor.decodeAll(encoded, (err, items) => {
  if (err) {
    console.error('Decoding failed:', err);
  } else {
    console.log('Decoded items:', items);
  }
});

// Async decoding with Promise
async function decodeMultiple() {
  try {
    const items = await cbor.decodeAll(encoded, {
      extendedResults: false,
      preferWeb: true
    });
    return items;
  } catch (error) {
    console.error('Async decode failed:', error);
    throw error;
  }
}

Decode First Item

Decode only the first CBOR item from input, leaving remaining data unused.

/**
 * Decode first CBOR item from input (async)
 * @param {BufferLike} input - CBOR data
 * @param {DecoderOptions|decodeCallback} [options] - Options or callback
 * @param {decodeCallback} [cb] - Callback function
 * @returns {Promise<any>|void} Decoded item or void if callback provided
 */
function decodeFirst(input, options, cb);

/**
 * Synchronously decode first CBOR item
 * @param {BufferLike} input - CBOR data
 * @param {DecoderOptions} [options] - Decoding options
 * @returns {any} Decoded item
 */
function decodeFirstSync(input, options);

Usage Examples:

const cbor = require("cbor");

// Multiple encoded items
const multipleItems = Buffer.concat([
  cbor.encode("first"),
  cbor.encode("second"),  
  cbor.encode("third")
]);

// Decode only first item synchronously
const firstItem = cbor.decodeFirstSync(multipleItems);
console.log(firstItem); // "first"

// Decode first with extended results
const firstWithExtended = cbor.decodeFirstSync(multipleItems, {
  extendedResults: true
});
console.log(firstWithExtended.value); // "first"
console.log(firstWithExtended.length); // Number of bytes consumed
console.log(firstWithExtended.bytes); // Actual bytes used
console.log(firstWithExtended.unused); // Remaining bytes

// Async decoding with callback
cbor.decodeFirst(multipleItems, { preferMap: true }, (err, item) => {
  if (err) {
    console.error('Decode error:', err);
  } else {
    console.log('First item:', item);
  }
});

// Async decoding with Promise
async function decodeFirstAsync() {
  const result = await cbor.decodeFirst(multipleItems, {
    max_depth: 64,
    extendedResults: true
  });
  
  console.log('Value:', result.value);
  console.log('Bytes used:', result.length);
  
  // Process remaining data if needed  
  if (result.unused && result.unused.length > 0) {
    return await cbor.decodeFirst(result.unused);
  }
}

Extended Results

Get detailed information about the decoding process including byte usage and remaining data.

/**
 * Extended result object with additional metadata
 * @typedef {Object} ExtendedResults
 * @property {any} value - The decoded value
 * @property {number} length - Number of bytes read from original input
 * @property {Buffer} bytes - Bytes of original input used to produce value
 * @property {Buffer} [unused] - Leftover bytes (only for decodeFirst/decodeFirstSync)
 */

Usage Examples:

const cbor = require("cbor");

const data = { name: "Charlie", items: [1, 2, 3] };
const encoded = cbor.encode(data);

// Get extended results
const result = cbor.decodeFirstSync(encoded, { extendedResults: true });

console.log('Decoded value:', result.value);
console.log('Bytes consumed:', result.length);
console.log('Input bytes used:', result.bytes);
console.log('Unused bytes:', result.unused); // Should be empty Buffer

// Useful for processing streams of CBOR data
function processStream(buffer) {
  let offset = 0;
  const results = [];
  
  while (offset < buffer.length) {
    try {
      const remaining = buffer.slice(offset);
      const result = cbor.decodeFirstSync(remaining, { extendedResults: true });
      
      results.push(result.value);
      offset += result.length;
      
    } catch (error) {
      console.error('Failed to decode at offset', offset, ':', error);
      break;
    }
  }
  
  return results;
}

Advanced Decoding Options

Fine-tune the decoding process with comprehensive configuration options.

/**
 * Decoder configuration options
 * @typedef {Object} DecoderOptions
 * @property {number} [max_depth=-1] - Maximum depth to parse (-1 for unlimited)
 * @property {TagMap} [tags] - Mapping from tag numbers to conversion functions
 * @property {boolean} [preferMap=false] - Prefer Map instances over plain objects
 * @property {boolean} [preferWeb=false] - Prefer Uint8Arrays over Buffers
 * @property {BufferEncoding} [encoding='hex'] - Input encoding if input is string
 * @property {boolean} [required=false] - Error when no data in input
 * @property {boolean} [extendedResults=false] - Emit extended result objects
 * @property {boolean} [preventDuplicateKeys=false] - Error on duplicate map keys
 */

Usage Examples:

const cbor = require("cbor");

// Maximum depth protection
const deepObject = { level1: { level2: { level3: { level4: "deep" } } } };
const encodedDeep = cbor.encode(deepObject);

try {
  const decoded = cbor.decodeFirstSync(encodedDeep, { max_depth: 2 });
} catch (error) {
  console.log('Depth limit exceeded'); // Will throw error
}

// Custom tag handlers
const decodedWithTags = cbor.decodeFirstSync(encodedData, {
  tags: {
    0: (dateString) => new Date(dateString),
    1: (epochTime) => new Date(epochTime * 1000),
    100: (value) => new MyCustomClass(value)
  }
});

// Prefer Map objects for better key type support
const mapData = new Map([
  [1, "number key"],
  ["str", "string key"],
  [true, "boolean key"]
]);
const encodedMap = cbor.encode(mapData);
const decodedAsMap = cbor.decodeFirstSync(encodedMap, { preferMap: true });

// Web platform compatibility
const decodedWeb = cbor.decodeFirstSync(encodedData, {
  preferWeb: true  // Use Uint8Arrays instead of Buffers
});

// Strict duplicate key checking
const duplicateKeyData = '{"a": 1, "a": 2}'; // Invalid CBOR with duplicate keys
try {
  const decoded = cbor.decodeFirstSync(duplicateKeyData, {
    preventDuplicateKeys: true
  });
} catch (error) {
  console.log('Duplicate keys detected');
}

// Require data to be present
try {
  const decoded = cbor.decodeFirstSync(Buffer.alloc(0), { required: true });
} catch (error) {
  console.log('No data found but required');
}

Error Handling and Recovery

Handle various decoding errors and implement recovery strategies.

Usage Examples:

const cbor = require("cbor");

// Comprehensive error handling
function safeDecode(input, options = {}) {
  try {
    return {
      success: true,
      data: cbor.decodeFirstSync(input, options),
      error: null
    };
  } catch (error) {
    let errorType = 'unknown';
    
    if (error.message.includes('depth')) {
      errorType = 'max_depth_exceeded';
    } else if (error.message.includes('truncated')) {
      errorType = 'incomplete_data';
    } else if (error.message.includes('duplicate')) {
      errorType = 'duplicate_keys';
    } else if (error.message.includes('Unexpected')) {
      errorType = 'invalid_cbor';
    }
    
    return {
      success: false,
      data: null,
      error: { type: errorType, message: error.message }
    };
  }
}

// Decode with fallback options
function decodeWithFallback(input) {
  // Try strict decoding first
  let result = safeDecode(input, {
    max_depth: 32,
    preventDuplicateKeys: true,
    required: true
  });
  
  if (result.success) {
    return result.data;
  }
  
  // Try relaxed decoding
  result = safeDecode(input, {
    max_depth: -1,
    preventDuplicateKeys: false,
    required: false
  });
  
  if (result.success) {
    console.warn('Decoded with relaxed options');
    return result.data;
  }
  
  throw new Error(`Unable to decode: ${result.error.message}`);
}

// Async error handling
async function asyncDecodeWithRetry(input, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await cbor.decodeFirst(input, {
        max_depth: 64,
        extendedResults: true
      });
    } catch (error) {
      console.warn(`Decode attempt ${attempt} failed:`, error.message);
      
      if (attempt === maxRetries) {
        throw new Error(`Failed to decode after ${maxRetries} attempts: ${error.message}`);
      }
      
      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, 100 * attempt));
    }
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-cbor

docs

advanced-decoding.md

cbor-types.md

diagnostic-tools.md

encoding-decoding.md

index.md

integration-utilities.md

stream-processing.md

tile.json