Comprehensive decoding functions with support for multiple items, asynchronous operations, extended result information, and fine-grained control over the decoding process.
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 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);
}
}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;
}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');
}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));
}
}
}