update electron to v43
All checks were successful
Android Build / publish (push) Successful in 55s
Linux Build / publish (push) Successful in 1m6s

This commit is contained in:
olcxja 2026-07-09 22:38:33 +02:00
commit fb6c8b6ee9
5385 changed files with 513060 additions and 123058 deletions

View file

@ -0,0 +1,101 @@
const ARRAY_BUFFER_TAG = "[object ArrayBuffer]";
const SHARED_ARRAY_BUFFER_TAG = "[object SharedArrayBuffer]";
function tagOf(value) {
return Object.prototype.toString.call(value);
}
function isDataViewConstructor(type) {
return type === DataView || type.prototype instanceof DataView;
}
function bytesPerElement(type) {
if (isDataViewConstructor(type)) {
return 1;
}
const value = type.BYTES_PER_ELEMENT;
return value ?? 1;
}
function isArrayBufferViewLike(value) {
if (ArrayBuffer.isView(value)) {
return true;
}
if (!value || typeof value !== "object") {
return false;
}
const view = value;
return typeof view.byteOffset === "number"
&& typeof view.byteLength === "number"
&& isArrayBufferLike(view.buffer);
}
function copyBytes(data) {
const view = toUint8Array(data);
const copy = new Uint8Array(view.byteLength);
copy.set(view);
return copy;
}
export function isArrayBuffer(value) {
return tagOf(value) === ARRAY_BUFFER_TAG;
}
export function isSharedArrayBuffer(value) {
return typeof SharedArrayBuffer !== "undefined" && tagOf(value) === SHARED_ARRAY_BUFFER_TAG;
}
export function isArrayBufferLike(value) {
return isArrayBuffer(value) || isSharedArrayBuffer(value);
}
export function isArrayBufferView(value) {
return isArrayBufferViewLike(value);
}
export function isBufferSource(value) {
return isArrayBufferLike(value) || isArrayBufferView(value);
}
export function assertBufferSource(value) {
if (!isBufferSource(value)) {
throw new TypeError("Expected ArrayBuffer, SharedArrayBuffer, or ArrayBufferView");
}
}
export function toUint8Array(data) {
assertBufferSource(data);
if (isArrayBufferLike(data)) {
return new Uint8Array(data);
}
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
}
export function toUint8ArrayCopy(data) {
return copyBytes(data);
}
export function toArrayBuffer(data) {
assertBufferSource(data);
if (isArrayBuffer(data)) {
return data;
}
const buffer = new ArrayBuffer(data.byteLength);
new Uint8Array(buffer).set(toUint8Array(data));
return buffer;
}
export function toArrayBufferLike(data) {
assertBufferSource(data);
if (isArrayBufferLike(data)) {
return data;
}
if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) {
return data.buffer;
}
return copyBytes(data).buffer;
}
export function toView(data, type) {
assertBufferSource(data);
if (ArrayBuffer.isView(data) && data.constructor === type) {
return data;
}
const view = toUint8Array(data);
const elementSize = bytesPerElement(type);
if (view.byteOffset % elementSize !== 0 || view.byteLength % elementSize !== 0) {
throw new RangeError(`Cannot create ${type.name} over unaligned byte range`);
}
if (isDataViewConstructor(type)) {
return new type(view.buffer, view.byteOffset, view.byteLength);
}
return new type(view.buffer, view.byteOffset, view.byteLength / elementSize);
}
export function toViewCopy(data, type) {
const copy = toUint8ArrayCopy(data);
return toView(copy, type);
}

View file

@ -0,0 +1,37 @@
import { isBufferSource, toUint8Array, toView } from "./buffer-source.js";
export function concatToUint8Array(buffers) {
const views = [];
let length = 0;
for (const buffer of buffers) {
const view = toUint8Array(buffer);
views.push(view);
length += view.byteLength;
}
const result = new Uint8Array(length);
let offset = 0;
for (const view of views) {
result.set(view, offset);
offset += view.byteLength;
}
return result;
}
export function concat(first, second, ...rest) {
let buffers;
let type;
if (typeof second === "function") {
buffers = Array.from(first);
type = second;
}
else if (isBufferSource(first)) {
buffers = [first, second, ...rest].filter(isBufferSource);
}
else {
buffers = Array.from(first);
if (second) {
buffers.push(second);
}
buffers.push(...rest);
}
const bytes = concatToUint8Array(buffers);
return type ? toView(bytes, type) : bytes.buffer;
}

View file

@ -0,0 +1,14 @@
import { toUint8Array } from "./buffer-source.js";
export function equal(a, b, options = {}) {
const left = toUint8Array(a);
const right = toUint8Array(b);
if (!options.constantTime && left.byteLength !== right.byteLength) {
return false;
}
const length = Math.max(left.byteLength, right.byteLength);
let diff = left.byteLength ^ right.byteLength;
for (let i = 0; i < length; i++) {
diff |= (left[i] ?? 0) ^ (right[i] ?? 0);
}
return diff === 0;
}

View file

@ -0,0 +1,4 @@
export { assertBufferSource, isArrayBuffer, isArrayBufferLike, isArrayBufferView, isBufferSource, isSharedArrayBuffer, toArrayBuffer, toArrayBufferLike, toUint8Array, toUint8ArrayCopy, toView, toViewCopy, } from "./buffer-source.js";
export { concat, concatToUint8Array } from "./concat.js";
export { equal } from "./equal.js";
export { compare, copy, endsWith, includes, indexOf, lastIndexOf, slice, startsWith, tail, } from "./sequence.js";

View file

@ -0,0 +1,150 @@
import { toUint8Array, toUint8ArrayCopy } from "./buffer-source.js";
function clampIndex(value, fallback, length) {
const normalized = Number.isFinite(value) ? Math.trunc(value) : fallback;
if (normalized <= 0) {
return 0;
}
if (normalized >= length) {
return length;
}
return normalized;
}
function normalizeForwardRange(length, options) {
const start = clampIndex(options?.start, 0, length);
const end = clampIndex(options?.end, length, length);
return end >= start ? [start, end] : [start, start];
}
function normalizeReverseRange(length, options) {
const start = clampIndex(options?.start, length, length);
const end = clampIndex(options?.end, 0, length);
return start >= end ? [end, start] : [start, start];
}
function normalizeSliceIndex(value, fallback, length) {
const normalized = Number.isFinite(value) ? Math.trunc(value) : fallback;
if (normalized < 0) {
return Math.max(length + normalized, 0);
}
if (normalized > length) {
return length;
}
return normalized;
}
function encodeAscii(text) {
const bytes = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
bytes[i] = text.charCodeAt(i) & 0xff;
}
return bytes;
}
function encodeUtf8(text) {
return new TextEncoder().encode(text);
}
function toPatternBytes(pattern, options) {
if (typeof pattern === "string") {
return options?.encoding === "utf8" ? encodeUtf8(pattern) : encodeAscii(pattern);
}
return toUint8Array(pattern);
}
function bytesEqualAt(data, pattern, offset) {
for (let index = 0; index < pattern.byteLength; index++) {
if (data[offset + index] !== pattern[index]) {
return false;
}
}
return true;
}
export function indexOf(data, pattern, options) {
const bytes = toUint8Array(data);
const needle = toPatternBytes(pattern, options);
const [start, end] = normalizeForwardRange(bytes.byteLength, options);
if (needle.byteLength === 0) {
return start;
}
const lastOffset = end - needle.byteLength;
if (lastOffset < start) {
return -1;
}
for (let offset = start; offset <= lastOffset; offset++) {
if (bytesEqualAt(bytes, needle, offset)) {
return offset;
}
}
return -1;
}
export function lastIndexOf(data, pattern, options) {
const bytes = toUint8Array(data);
const needle = toPatternBytes(pattern, options);
const [end, start] = normalizeReverseRange(bytes.byteLength, options);
if (needle.byteLength === 0) {
return start;
}
const firstOffset = start - needle.byteLength;
if (firstOffset < end) {
return -1;
}
for (let offset = firstOffset; offset >= end; offset--) {
if (bytesEqualAt(bytes, needle, offset)) {
return offset;
}
}
return -1;
}
export function includes(data, pattern, options) {
return indexOf(data, pattern, options) !== -1;
}
export function startsWith(data, pattern, options) {
const bytes = toUint8Array(data);
const needle = toPatternBytes(pattern, options);
if (needle.byteLength > bytes.byteLength) {
return false;
}
return bytesEqualAt(bytes, needle, 0);
}
export function endsWith(data, pattern, options) {
const bytes = toUint8Array(data);
const needle = toPatternBytes(pattern, options);
if (needle.byteLength > bytes.byteLength) {
return false;
}
return bytesEqualAt(bytes, needle, bytes.byteLength - needle.byteLength);
}
export function slice(data, start, end) {
const bytes = toUint8Array(data);
const normalizedStart = normalizeSliceIndex(start, 0, bytes.byteLength);
const normalizedEnd = normalizeSliceIndex(end, bytes.byteLength, bytes.byteLength);
if (normalizedEnd <= normalizedStart) {
return bytes.subarray(normalizedStart, normalizedStart);
}
return bytes.subarray(normalizedStart, normalizedEnd);
}
export function tail(data, length) {
const bytes = toUint8Array(data);
const normalizedLength = Number.isFinite(length) ? Math.max(0, Math.trunc(length)) : 0;
if (normalizedLength >= bytes.byteLength) {
return bytes;
}
return bytes.subarray(bytes.byteLength - normalizedLength);
}
export function copy(data) {
return toUint8ArrayCopy(data);
}
export function compare(a, b) {
const left = toUint8Array(a);
const right = toUint8Array(b);
const limit = Math.min(left.byteLength, right.byteLength);
for (let index = 0; index < limit; index++) {
if (left[index] < right[index]) {
return -1;
}
if (left[index] > right[index]) {
return 1;
}
}
if (left.byteLength < right.byteLength) {
return -1;
}
if (left.byteLength > right.byteLength) {
return 1;
}
return 0;
}

View file

@ -0,0 +1 @@
export {};

View file

@ -0,0 +1,71 @@
import { toArrayBuffer } from "../bytes/index.js";
import { base64, base64url, binary, hex, utf8, utf16 } from "../encoding/index.js";
import { defaultConverterRegistry } from "./defaults.js";
function encode(name, data, ...args) {
return defaultConverterRegistry.encode(name, data, ...args);
}
function decode(name, text, ...args) {
return defaultConverterRegistry.decode(name, text, ...args);
}
function tryDecode(name, text, ...args) {
return defaultConverterRegistry.tryDecode(name, text, ...args);
}
function normalize(name, text, ...args) {
return defaultConverterRegistry.normalize(name, text, ...args);
}
function parse(name, text, ...args) {
return defaultConverterRegistry.parse(name, text, ...args);
}
function format(name, data, value) {
return defaultConverterRegistry.format(name, data, value);
}
function transcode(text, options) {
return defaultConverterRegistry.transcode(text, options);
}
function detect(text, options) {
return defaultConverterRegistry.detect(text, options);
}
function normalizeEncodingName(encoding) {
return encoding.toLowerCase();
}
export const convert = {
encode,
decode,
tryDecode,
normalize,
parse,
format,
transcode,
detect,
to(format, data, ...args) {
return encode(format, data, ...args);
},
from(format, text, ...args) {
return decode(format, text, ...args);
},
toString(data, encoding = "utf8") {
return encode(encoding, data);
},
fromString(text, encoding = "utf8") {
if (normalizeEncodingName(encoding) === "hex") {
return toArrayBuffer(hex.decode(text, { allowOddLength: true }));
}
return toArrayBuffer(decode(encoding, text));
},
toBase64: base64.encode,
fromBase64: (text) => toArrayBuffer(base64.decode(text)),
toBase64Url: base64url.encode,
fromBase64Url: (text) => toArrayBuffer(base64url.decode(text)),
toHex: hex.encode,
fromHex: (text) => toArrayBuffer(hex.decode(text, { allowOddLength: true })),
toBinary: binary.encode,
fromBinary: (text) => toArrayBuffer(binary.decode(text)),
toUtf8String: utf8.decode,
fromUtf8String: (text) => toArrayBuffer(utf8.encode(text)),
toUtf16String: (data, littleEndian = false) => utf16.decode(data, { littleEndian }),
fromUtf16String: (text, littleEndian = false) => toArrayBuffer(utf16.encode(text, { littleEndian })),
isHex: hex.is,
isBase64: base64.is,
isBase64Url: base64url.is,
formatString: base64.normalize,
};

View file

@ -0,0 +1,68 @@
import { base64, base64url, binary, hex, utf8, utf16 } from "../encoding/index.js";
import { pemConverter } from "../pem/index.js";
export { pemConverter } from "../pem/index.js";
import { createConverterRegistry } from "./registry.js";
export const binaryConverter = {
name: "binary",
aliases: ["latin1"],
encode: binary.encode,
decode: binary.decode,
is: binary.is,
};
export const hexConverter = {
name: "hex",
encode: hex.encode,
decode: hex.decode,
format: hex.format,
is: hex.is,
normalize: hex.normalize,
parse: hex.parse,
};
export const base64Converter = {
name: "base64",
aliases: ["b64"],
encode: base64.encode,
decode: base64.decode,
is: base64.is,
normalize: base64.normalize,
};
export const base64urlConverter = {
name: "base64url",
aliases: ["base64-url", "b64url"],
encode: base64url.encode,
decode: base64url.decode,
is: base64url.is,
normalize: base64url.normalize,
};
export const utf8Converter = {
name: "utf8",
aliases: ["utf-8"],
encode: (data) => utf8.decode(data),
decode: (text) => utf8.encode(text),
is: (text) => typeof text === "string",
};
export const utf16beConverter = {
name: "utf16be",
aliases: ["utf16", "utf-16", "utf-16be"],
encode: (data) => utf16.decode(data),
decode: (text) => utf16.encode(text),
is: (text) => typeof text === "string",
};
export const utf16leConverter = {
name: "utf16le",
aliases: ["utf-16le", "ucs2", "usc2"],
encode: (data) => utf16.decode(data, { littleEndian: true }),
decode: (text) => utf16.encode(text, { littleEndian: true }),
is: (text) => typeof text === "string",
};
export const defaultConverters = [
binaryConverter,
hexConverter,
base64Converter,
base64urlConverter,
utf8Converter,
utf16beConverter,
utf16leConverter,
pemConverter,
];
export const defaultConverterRegistry = createConverterRegistry(defaultConverters);

View file

@ -0,0 +1,3 @@
export { createConverterRegistry } from "./registry.js";
export { base64Converter, base64urlConverter, binaryConverter, defaultConverterRegistry, defaultConverters, hexConverter, pemConverter, utf16beConverter, utf16leConverter, utf8Converter, } from "./defaults.js";
export { convert } from "./convert.js";

View file

@ -0,0 +1,185 @@
function keyOf(name) {
return name.trim().toLowerCase();
}
function toError(error) {
return error instanceof Error ? error : new Error(String(error));
}
function removeConverter(converters, primaryNames, converter) {
for (const alias of [converter.name, ...(converter.aliases ?? [])]) {
converters.delete(keyOf(alias));
}
primaryNames.delete(keyOf(converter.name));
}
function requireCapability(converter, name, capability) {
const method = converter[capability];
if (typeof method !== "function") {
throw new Error(`Converter '${name}' does not support ${capability}()`);
}
return method;
}
function detectConfidence(name, text, converter) {
const normalizedName = keyOf(converter.name || name);
const trimmed = text.trim();
if (!trimmed) {
return 0;
}
let accepted = false;
if (converter.is) {
accepted = converter.is(text);
}
let decodable = false;
try {
converter.decode(text);
decodable = true;
}
catch {
decodable = false;
}
if (!accepted && !decodable) {
return 0;
}
switch (normalizedName) {
case "pem":
return /-----BEGIN [^-]+-----/.test(text) ? 1 : 0;
case "hex": {
const compact = trimmed.replace(/^0x/i, "").replace(/[\s:.-]/g, "");
if (!compact || /[^0-9a-f]/i.test(compact) || compact.length % 2 !== 0) {
return 0;
}
if (/^0x/i.test(trimmed) || /[:\s.-]/.test(trimmed)) {
return 0.95;
}
if (/[a-f]/.test(trimmed) || /[A-F]/.test(trimmed)) {
return 0.8;
}
return 0.45;
}
case "base64url":
if (/[-_]/.test(trimmed)) {
return 0.95;
}
if (/=/.test(trimmed)) {
return 0.1;
}
return 0.6;
case "base64":
if (/[+/=]/.test(trimmed)) {
return 0.9;
}
return 0.55;
case "binary":
case "utf8":
case "utf16be":
case "utf16le":
return 0;
default:
return accepted && decodable ? 0.75 : 0.5;
}
}
export function createConverterRegistry(initialConverters = []) {
const converters = new Map();
const primaryNames = new Set();
const api = {
register(converter, options = {}) {
if (!converter.name || !keyOf(converter.name)) {
throw new TypeError("Converter name is required");
}
const names = [...new Set([converter.name, ...(converter.aliases ?? [])].map(keyOf))];
const conflicts = new Set();
for (const name of names) {
const existing = converters.get(name);
if (!existing) {
continue;
}
if (!options.override) {
throw new Error(`Converter '${name}' is already registered`);
}
conflicts.add(existing);
}
for (const conflicting of conflicts) {
removeConverter(converters, primaryNames, conflicting);
}
for (const name of names) {
converters.set(name, converter);
}
primaryNames.add(keyOf(converter.name));
return this;
},
unregister(name) {
const converter = converters.get(keyOf(name));
if (!converter) {
return false;
}
removeConverter(converters, primaryNames, converter);
return true;
},
has(name) {
return converters.has(keyOf(name));
},
get(name) {
const converter = converters.get(keyOf(name));
if (!converter) {
throw new Error(`Converter '${name}' is not registered`);
}
return converter;
},
list() {
return [...primaryNames].map((name) => this.get(name));
},
encode(name, data, options) {
return this.get(name).encode(data, options);
},
decode(name, text, options) {
return this.get(name).decode(text, options);
},
tryDecode(name, text, options) {
try {
return { ok: true, bytes: this.decode(name, text, options) };
}
catch (error) {
return { ok: false, error: toError(error) };
}
},
normalize(name, text, options) {
const converter = this.get(name);
return requireCapability(converter, name, "normalize").call(converter, text, options);
},
parse(name, text, options) {
const converter = this.get(name);
return requireCapability(converter, name, "parse").call(converter, text, options);
},
format(name, data, format) {
const converter = this.get(name);
return requireCapability(converter, name, "format").call(converter, data, format);
},
transcode(text, options) {
const bytes = this.decode(options.from, text, options.fromOptions);
return this.encode(options.to, bytes, options.toOptions);
},
detect(text, options = {}) {
const formatNames = options.formats?.length
? options.formats.map((name) => String(name))
: this.list()
.map((converter) => converter.name)
.filter((name) => !["binary", "utf8", "utf16be", "utf16le"].includes(keyOf(name)));
const detections = new Map();
for (const requestedName of formatNames) {
const converter = this.get(requestedName);
const confidence = detectConfidence(requestedName, text, converter);
if (confidence <= 0) {
continue;
}
const format = converter.name;
const current = detections.get(format);
if (!current || confidence > current.confidence) {
detections.set(format, { format, confidence });
}
}
return [...detections.values()].sort((left, right) => right.confidence - left.confidence);
},
};
for (const converter of initialConverters) {
api.register(converter);
}
return api;
}

View file

@ -0,0 +1 @@
export {};

View file

@ -0,0 +1,40 @@
import { toUint8Array } from "../bytes/index.js";
import { encode as encodeBinary, decode as decodeBinary } from "./binary.js";
const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
function nodeBuffer() {
return globalThis.Buffer;
}
export function normalize(text) {
return text.replace(/[\n\r\t ]/g, "");
}
export function pad(text) {
const remainder = text.length % 4;
return remainder ? text + "=".repeat(4 - remainder) : text;
}
export function is(text) {
if (typeof text !== "string") {
return false;
}
const normalized = normalize(text);
return normalized === "" || BASE64_REGEX.test(normalized);
}
export function encode(data, _options) {
const bytes = toUint8Array(data);
const buffer = nodeBuffer();
if (buffer) {
return buffer.from(bytes).toString("base64");
}
return btoa(encodeBinary(bytes));
}
export function decode(text, _options) {
const normalized = normalize(text);
if (!is(normalized)) {
throw new TypeError("Input is not valid Base64 text");
}
const buffer = nodeBuffer();
if (buffer) {
return new Uint8Array(buffer.from(normalized, "base64"));
}
return decodeBinary(atob(normalized));
}
export const base64 = { encode, decode, is, normalize, pad };

View file

@ -0,0 +1,19 @@
import { base64 } from "./base64.js";
const BASE64URL_REGEX = /^[A-Za-z0-9_-]*$/;
export function normalize(text) {
return text.replace(/[\n\r\t ]/g, "");
}
export function is(text) {
return typeof text === "string" && BASE64URL_REGEX.test(normalize(text));
}
export function encode(data, _options) {
return base64.encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
export function decode(text, _options) {
const normalized = normalize(text);
if (!is(normalized)) {
throw new TypeError("Input is not valid Base64Url text");
}
return base64.decode(base64.pad(normalized.replace(/-/g, "+").replace(/_/g, "/")));
}
export const base64url = { encode, decode, is, normalize };

View file

@ -0,0 +1,20 @@
import { toUint8Array } from "../bytes/index.js";
export function encode(data) {
const bytes = toUint8Array(data);
let result = "";
for (const byte of bytes) {
result += String.fromCharCode(byte);
}
return result;
}
export function decode(text) {
const result = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
result[i] = text.charCodeAt(i) & 0xff;
}
return result;
}
export function is(text) {
return typeof text === "string";
}
export const binary = { encode, decode, is };

View file

@ -0,0 +1,220 @@
import { toUint8Array } from "../bytes/index.js";
const HEX_CHARACTER_REGEX = /^[0-9a-f]$/i;
const COMMON_SEPARATORS = [" ", "\t", "\n", "\r", ":", "-", "."];
function resolveSeparators(options) {
if (options.separators === "none") {
return [];
}
if (!options.separators || options.separators === "common") {
return COMMON_SEPARATORS;
}
return options.separators;
}
function validateSeparator(separator) {
if (!separator) {
throw new TypeError("Hex separators must be non-empty strings");
}
}
function matchSeparator(text, index, separators) {
for (const separator of separators) {
if (text.startsWith(separator, index)) {
return separator;
}
}
return undefined;
}
function detectCase(text) {
const hasUpper = /[A-F]/.test(text);
const hasLower = /[a-f]/.test(text);
return hasUpper && !hasLower ? "upper" : "lower";
}
function detectLineSeparator(text) {
const match = /\r\n|\n/.exec(text);
if (!match) {
return undefined;
}
return match[0] === "\r\n" ? "\r\n" : "\n";
}
function compactForDetection(text) {
return text.replace(/[^0-9a-f]/gi, "");
}
function detectGroup(text) {
const segments = text.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
if (segments.length < 3) {
return undefined;
}
const hexSegments = segments.filter((_, index) => index % 2 === 0);
const separators = segments.filter((_, index) => index % 2 === 1);
const separator = separators[0];
if (!separator || separators.some((item) => item !== separator)) {
return undefined;
}
if (hexSegments.some((segment) => segment.length === 0 || segment.length % 2 !== 0)) {
return undefined;
}
const firstLength = hexSegments[0]?.length ?? 0;
if (!firstLength) {
return undefined;
}
if (hexSegments.slice(0, -1).some((segment) => segment.length !== firstLength)) {
return undefined;
}
if ((hexSegments[hexSegments.length - 1]?.length ?? 0) > firstLength) {
return undefined;
}
return {
size: firstLength / 2,
separator,
};
}
function detectFormat(text) {
const trimmed = text.trim();
const prefix = /^0x/i.test(trimmed) ? "0x" : "";
const body = prefix ? trimmed.slice(2) : trimmed;
const lineSeparator = detectLineSeparator(body);
const lines = body.split(/\r\n|\n/).filter((line) => line.length > 0);
const sampleLine = lines[0]?.trim() ?? "";
const group = detectGroup(sampleLine);
const format = {
case: detectCase(trimmed),
prefix,
};
if (group) {
format.group = group;
}
if (lineSeparator && lines.length > 1) {
const firstLineBytes = compactForDetection(lines[0] ?? "").length / 2;
if (firstLineBytes > 0 && lines.slice(0, -1).every((line) => compactForDetection(line).length / 2 === firstLineBytes)) {
format.line = {
bytesPerLine: firstLineBytes,
separator: lineSeparator,
};
}
}
return format;
}
function normalizeText(text, options) {
const allowPrefix = options.allowPrefix ?? true;
const separators = [...resolveSeparators(options)].sort((left, right) => right.length - left.length);
for (const separator of separators) {
validateSeparator(separator);
}
let working = text.trim();
if (/^0x/i.test(working)) {
if (!allowPrefix) {
throw new TypeError("Hexadecimal text must not include a 0x prefix");
}
working = working.slice(2);
}
let normalized = "";
let lastTokenWasSeparator = false;
for (let index = 0; index < working.length;) {
const character = working[index] ?? "";
if (HEX_CHARACTER_REGEX.test(character)) {
normalized += character;
lastTokenWasSeparator = false;
index += 1;
continue;
}
const separator = matchSeparator(working, index, separators);
if (!separator) {
throw new TypeError("Input is not valid hexadecimal text");
}
if (options.strict && (lastTokenWasSeparator || normalized.length === 0)) {
throw new TypeError("Hexadecimal text contains misplaced separators");
}
lastTokenWasSeparator = true;
index += separator.length;
}
if (options.strict && lastTokenWasSeparator && normalized.length > 0) {
throw new TypeError("Hexadecimal text must not end with a separator");
}
if (normalized.length % 2 !== 0) {
if (!options.allowOddLength) {
throw new TypeError("Hexadecimal text must contain an even number of characters");
}
normalized = `0${normalized}`;
}
return normalized.toLowerCase();
}
function groupPairs(pairs, group) {
if (!group) {
return pairs.join("");
}
if (!Number.isInteger(group.size) || group.size < 1) {
throw new RangeError("Hex group size must be a positive integer");
}
const chunks = [];
for (let index = 0; index < pairs.length; index += group.size) {
chunks.push(pairs.slice(index, index + group.size).join(""));
}
return chunks.join(group.separator);
}
export function normalize(text, options = {}) {
return normalizeText(text, options);
}
export function is(text, options = {}) {
if (typeof text !== "string") {
return false;
}
try {
normalize(text, options);
return true;
}
catch {
return false;
}
}
export function encode(data, options = {}) {
const bytes = toUint8Array(data);
const casing = options.case ?? "lower";
const pairs = Array.from(bytes, (byte) => {
const text = byte.toString(16).padStart(2, "0");
return casing === "upper" ? text.toUpperCase() : text;
});
let body = "";
if (options.line) {
const bytesPerLine = options.line.bytesPerLine;
if (!Number.isInteger(bytesPerLine) || bytesPerLine < 1) {
throw new RangeError("Hex bytesPerLine must be a positive integer");
}
const separator = options.line.separator ?? "\n";
const lines = [];
for (let index = 0; index < pairs.length; index += bytesPerLine) {
lines.push(groupPairs(pairs.slice(index, index + bytesPerLine), options.group));
}
body = lines.join(separator);
}
else {
body = groupPairs(pairs, options.group);
}
return `${options.prefix ?? ""}${body}`;
}
export function decode(text, options = {}) {
const normalized = normalize(text, options);
const result = new Uint8Array(normalized.length / 2);
for (let i = 0; i < normalized.length; i += 2) {
result[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
}
return result;
}
export function parse(text, options = {}) {
const normalized = normalize(text, options);
return {
bytes: decode(normalized),
format: detectFormat(text),
normalized,
};
}
export function format(data, value) {
return encode(data, value);
}
export const formats = {
compact: Object.freeze({}),
upper: Object.freeze({ case: "upper" }),
colon: Object.freeze({ group: { size: 1, separator: ":" } }),
colonUpper: Object.freeze({ case: "upper", group: { size: 1, separator: ":" } }),
groupsOf4: Object.freeze({ group: { size: 4, separator: " " } }),
prefixed: Object.freeze({ prefix: "0x" }),
};
export const hex = { encode, decode, format, formats, is, normalize, parse };

View file

@ -0,0 +1,6 @@
export * as binary from "./binary.js";
export * as hex from "./hex.js";
export * as utf8 from "./utf8.js";
export * as utf16 from "./utf16.js";
export * as base64 from "./base64.js";
export * as base64url from "./base64url.js";

View file

@ -0,0 +1,19 @@
import { toArrayBuffer } from "../bytes/index.js";
export function encode(text, options = {}) {
const result = new ArrayBuffer(text.length * 2);
const view = new DataView(result);
for (let i = 0; i < text.length; i++) {
view.setUint16(i * 2, text.charCodeAt(i), options.littleEndian ?? false);
}
return new Uint8Array(result);
}
export function decode(data, options = {}) {
const buffer = toArrayBuffer(data);
const view = new DataView(buffer);
let result = "";
for (let i = 0; i < buffer.byteLength; i += 2) {
result += String.fromCharCode(view.getUint16(i, options.littleEndian ?? false));
}
return result;
}
export const utf16 = { encode, decode };

View file

@ -0,0 +1,8 @@
import { toUint8Array } from "../bytes/index.js";
export function encode(text) {
return new TextEncoder().encode(text);
}
export function decode(data) {
return new TextDecoder("utf-8", { fatal: false }).decode(toUint8Array(data));
}
export const utf8 = { encode, decode };

View file

@ -0,0 +1,6 @@
export * from "./bytes/index.js";
export * as bytes from "./bytes/index.js";
export * from "./encoding/index.js";
export * from "./pem/index.js";
export * from "./converters/index.js";
export * from "./legacy/index.js";

View file

@ -0,0 +1,33 @@
import { concat, equal, isArrayBuffer, isArrayBufferView, isBufferSource, toArrayBuffer, toUint8Array, toView, } from "../bytes/index.js";
export class BufferSourceConverter {
static isArrayBuffer(data) {
return isArrayBuffer(data);
}
static toArrayBuffer(data) {
return toArrayBuffer(data);
}
static toUint8Array(data) {
return toUint8Array(data);
}
static toView(data, type) {
return toView(data, type);
}
static isBufferSource(data) {
return isBufferSource(data);
}
static isArrayBufferView(data) {
return isArrayBufferView(data);
}
static isEqual(a, b) {
return equal(a, b);
}
static concat(first, second, ...rest) {
if (Array.isArray(first)) {
return typeof second === "function"
? concat(first, second)
: concat(first);
}
const buffers = [first, second, ...rest].filter(Boolean);
return concat(buffers);
}
}

View file

@ -0,0 +1,68 @@
import { convert } from "../converters/index.js";
function normalizeTextEncoding(encoding) {
return encoding === "ascii" ? "binary" : encoding;
}
export class Convert {
static DEFAULT_UTF8_ENCODING = "utf8";
static isHex(data) {
return convert.isHex(data);
}
static isBase64(data) {
return convert.isBase64(data);
}
static isBase64Url(data) {
return convert.isBase64Url(data);
}
static ToString(buffer, enc = "utf8") {
return convert.toString(buffer, enc);
}
static FromString(str, enc = "utf8") {
if (!str) {
return new ArrayBuffer(0);
}
return convert.fromString(str, enc);
}
static ToBase64(buffer) {
return convert.toBase64(buffer);
}
static FromBase64(base64) {
return convert.fromBase64(base64);
}
static FromBase64Url(base64url) {
return convert.fromBase64Url(base64url);
}
static ToBase64Url(data) {
return convert.toBase64Url(data);
}
static FromUtf8String(text, encoding = Convert.DEFAULT_UTF8_ENCODING) {
return convert.fromString(text, normalizeTextEncoding(encoding));
}
static ToUtf8String(buffer, encoding = Convert.DEFAULT_UTF8_ENCODING) {
return convert.toString(buffer, normalizeTextEncoding(encoding));
}
static FromBinary(text) {
return convert.fromBinary(text);
}
static ToBinary(buffer) {
return convert.toBinary(buffer);
}
static ToHex(buffer) {
return convert.toHex(buffer);
}
static FromHex(hexString) {
return convert.fromHex(hexString);
}
static ToUtf16String(buffer, littleEndian = false) {
return convert.toUtf16String(buffer, littleEndian);
}
static FromUtf16String(text, littleEndian = false) {
return convert.fromUtf16String(text, littleEndian);
}
static Base64Padding(base64) {
const padCount = 4 - (base64.length % 4);
return padCount < 4 ? base64 + "=".repeat(padCount) : base64;
}
static formatString(data) {
return convert.formatString(data);
}
}

View file

@ -0,0 +1,18 @@
import { concat, equal } from "../bytes/index.js";
export function assign(target, ...sources) {
for (const source of sources) {
if (!source) {
continue;
}
for (const prop in source) {
target[prop] = source[prop];
}
}
return target;
}
export function combine(...buf) {
return concat(buf);
}
export function isEqual(bytes1, bytes2) {
return equal(bytes1, bytes2);
}

View file

@ -0,0 +1,3 @@
export { BufferSourceConverter } from "./buffer-source-converter.js";
export { Convert } from "./convert.js";
export { assign, combine, isEqual } from "./functions.js";

View file

@ -0,0 +1 @@
export { decode, decodeFirst, encode, encodeMany, find, findAll, format, parse, pem, pemConverter } from "./pem.js";

View file

@ -0,0 +1,129 @@
import { base64 } from "../encoding/base64.js";
const LABEL_REGEX = /^[A-Z0-9][A-Z0-9 ._-]*[A-Z0-9]$/i;
const PEM_BLOCK_REGEX = /-----BEGIN ([^-]+)-----([\s\S]*?)-----END \1-----/g;
function assertLabel(label) {
if (!LABEL_REGEX.test(label)) {
throw new TypeError(`Invalid PEM label '${label}'`);
}
}
function wrap(text, lineLength) {
const result = [];
for (let i = 0; i < text.length; i += lineLength) {
result.push(text.slice(i, i + lineLength));
}
return result;
}
function parseBody(body) {
const normalized = body.trim().replace(/\r\n/g, "\n");
const lines = normalized.split("\n").map((line) => line.trim()).filter(Boolean);
const headers = {};
let index = 0;
for (; index < lines.length; index++) {
const line = lines[index];
const separator = line.indexOf(":");
if (separator <= 0) {
break;
}
headers[line.slice(0, separator).trim()] = line.slice(separator + 1).trim();
}
return {
headers: Object.keys(headers).length ? headers : undefined,
base64Lines: lines.slice(index),
base64Text: lines.slice(index).join(""),
};
}
function detectNewline(text) {
return /\r\n/.test(text) ? "\r\n" : "\n";
}
function collectBlocks(text, options = {}) {
const blocks = [];
const requestedLabel = options.label;
let match;
PEM_BLOCK_REGEX.lastIndex = 0;
while ((match = PEM_BLOCK_REGEX.exec(text))) {
const label = match[1].trim();
if (requestedLabel && label !== requestedLabel) {
continue;
}
assertLabel(label);
const parsed = parseBody(match[2]);
blocks.push({
label,
data: base64.decode(parsed.base64Text),
headers: parsed.headers,
lineLength: parsed.base64Lines[0]?.length ?? 64,
newline: detectNewline(match[0]),
});
}
if (options.strict && blocks.length === 0) {
throw new TypeError(requestedLabel
? `No PEM block with label '${requestedLabel}' was found`
: "No PEM blocks were found");
}
return blocks;
}
export function encode(label, data, options = {}) {
assertLabel(label);
const lineLength = options.lineLength ?? 64;
if (!Number.isInteger(lineLength) || lineLength < 1) {
throw new RangeError("PEM lineLength must be a positive integer");
}
const newline = options.newline ?? "\n";
const lines = [`-----BEGIN ${label}-----`];
if (options.headers) {
for (const [name, value] of Object.entries(options.headers)) {
lines.push(`${name}: ${value}`);
}
lines.push("");
}
lines.push(...wrap(base64.encode(data), lineLength));
lines.push(`-----END ${label}-----`);
return `${lines.join(newline)}${newline}`;
}
export function encodeMany(blocks, options = {}) {
return blocks.map((block) => encode(block.label, block.data, { ...options, headers: block.headers ?? options.headers })).join("");
}
export function decode(text, options = {}) {
return collectBlocks(text, options).map(({ lineLength: _lineLength, newline: _newline, ...block }) => block);
}
export function find(text, label) {
return decode(text, { label })[0];
}
export function findAll(text, label) {
return decode(text, { label });
}
export function decodeFirst(text, label) {
const [block] = decode(text, { label, strict: true });
return block.data;
}
export function parse(text, options = {}) {
const [block] = collectBlocks(text, { ...options, strict: true });
const format = {
label: block.label,
headers: block.headers,
lineLength: block.lineLength,
newline: block.newline,
};
return {
bytes: block.data,
format,
normalized: encode(block.label, block.data, format),
};
}
export function format(data, value) {
return encode(value.label, data, value);
}
export const pem = { decode, decodeFirst, encode, encodeMany, find, findAll, format, parse };
export const pemConverter = {
name: "pem",
encode: (data, options) => {
if (!options?.label) {
throw new TypeError("PEM label is required");
}
return encode(options.label, data, options);
},
decode: (text, options) => decodeFirst(text, options?.label),
format,
is: (text) => typeof text === "string" && /-----BEGIN [^-]+-----/.test(text),
parse,
};

View file

@ -0,0 +1 @@
export {};