node/lib/sea.js
Joyee Cheung c307ad7686
sea: support sea.getRawAsset()
This patch adds support for `sea.getRawAsset()` which is
similar to `sea.getAsset()` but returns the raw asset
in an array buffer without copying. Users should avoid
writing to the returned array buffer. If the injected
section is not marked as writable or not aligned,
writing to the raw asset is likely to result in a crash.

PR-URL: https://github.com/nodejs/node/pull/50960
Refs: https://github.com/nodejs/single-executable/issues/68
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
2024-02-02 15:25:34 +01:00

77 lines
2.1 KiB
JavaScript

'use strict';
const {
ArrayBufferPrototypeSlice,
} = primordials;
const { isSea, getAsset: getAssetInternal } = internalBinding('sea');
const { TextDecoder } = require('internal/encoding');
const { validateString } = require('internal/validators');
const {
ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION,
ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND,
} = require('internal/errors').codes;
const { Blob } = require('internal/blob');
/**
* Look for the asset in the injected SEA blob using the key. If
* no matching asset is found an error is thrown. The returned
* ArrayBuffer should not be mutated or otherwise the process
* can crash due to access violation.
* @param {string} key
* @returns {ArrayBuffer}
*/
function getRawAsset(key) {
validateString(key, 'key');
if (!isSea()) {
throw new ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION();
}
const asset = getAssetInternal(key);
if (asset === undefined) {
throw new ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND(key);
}
return asset;
}
/**
* Look for the asset in the injected SEA blob using the key. If the
* encoding is specified, return a string decoded from it by TextDecoder,
* otherwise return *a copy* of the original data in an ArrayBuffer. If
* no matching asset is found an error is thrown.
* @param {string} key
* @param {string|undefined} encoding
* @returns {string|ArrayBuffer}
*/
function getAsset(key, encoding) {
if (encoding !== undefined) {
validateString(encoding, 'encoding');
}
const asset = getRawAsset(key);
if (encoding === undefined) {
return ArrayBufferPrototypeSlice(asset);
}
const decoder = new TextDecoder(encoding);
return decoder.decode(asset);
}
/**
* Look for the asset in the injected SEA blob using the key. If
* no matching asset is found an error is thrown. The data is returned
* in a Blob. If no matching asset is found an error is thrown.
* @param {string} key
* @param {ConstructorParameters<Blob>[1]} [options]
* @returns {Blob}
*/
function getAssetAsBlob(key, options) {
const asset = getRawAsset(key);
return new Blob([asset], options);
}
module.exports = {
isSea,
getAsset,
getRawAsset,
getAssetAsBlob,
};