@andrew_l/toolkit 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1583,8 +1583,12 @@ class Base64Encoding {
1583
1583
  }
1584
1584
  this.alphabet = alphabet;
1585
1585
  this.padding = options?.padding ?? "=";
1586
- if (this.alphabet.includes(this.padding) || this.padding.length !== 1) {
1587
- throw new Error("Invalid padding");
1586
+ if (this.padding) {
1587
+ ok(
1588
+ !this.alphabet.includes(this.padding),
1589
+ "Padding cannot be a part of alphabet"
1590
+ );
1591
+ ok(this.padding.length === 1, "Padding length must be a 1");
1588
1592
  }
1589
1593
  for (let i = 0; i < alphabet.length; i++) {
1590
1594
  this.decodeMap.set(alphabet[i], i);
@@ -1603,26 +1607,24 @@ class Base64Encoding {
1603
1607
  * ```
1604
1608
  */
1605
1609
  encode(data, options) {
1610
+ const includePadding = options?.includePadding ?? true;
1606
1611
  let result = "";
1607
1612
  let buffer = 0;
1608
1613
  let shift = 0;
1609
- for (let i = 0; i < data.length; i++) {
1610
- buffer = buffer << 8 | data[i];
1614
+ for (const byte of data) {
1615
+ buffer = buffer << 8 | byte;
1611
1616
  shift += 8;
1612
1617
  while (shift >= 6) {
1613
- shift += -6;
1618
+ shift -= 6;
1614
1619
  result += this.alphabet[buffer >> shift & 63];
1615
1620
  }
1616
1621
  }
1617
1622
  if (shift > 0) {
1618
1623
  result += this.alphabet[buffer << 6 - shift & 63];
1619
1624
  }
1620
- const includePadding = options?.includePadding ?? true;
1621
- if (includePadding) {
1625
+ if (includePadding && this.padding) {
1622
1626
  const padCount = (4 - result.length % 4) % 4;
1623
- for (let i = 0; i < padCount; i++) {
1624
- result += "=";
1625
- }
1627
+ result += "=".repeat(padCount);
1626
1628
  }
1627
1629
  return result;
1628
1630
  }
@@ -1641,39 +1643,23 @@ class Base64Encoding {
1641
1643
  */
1642
1644
  decode(data, options) {
1643
1645
  const strict = options?.strict ?? true;
1644
- const chunkCount = Math.ceil(data.length / 4);
1645
1646
  const result = [];
1646
- for (let i = 0; i < chunkCount; i++) {
1647
- let padCount = 0;
1648
- let buffer = 0;
1649
- for (let j = 0; j < 4; j++) {
1650
- const encoded = data[i * 4 + j];
1651
- if (encoded === "=") {
1652
- if (i + 1 !== chunkCount) {
1653
- throw new Error(`Invalid character: ${encoded}`);
1654
- }
1655
- padCount += 1;
1656
- continue;
1657
- }
1658
- if (encoded === void 0) {
1659
- if (strict) {
1660
- throw new Error("Invalid data");
1661
- }
1662
- padCount += 1;
1663
- continue;
1664
- }
1665
- const value = this.decodeMap.get(encoded) ?? null;
1666
- if (value === null) {
1667
- throw new Error(`Invalid character: ${encoded}`);
1668
- }
1669
- buffer += value << 6 * (3 - j);
1670
- }
1671
- result.push(buffer >> 16 & 255);
1672
- if (padCount < 2) {
1673
- result.push(buffer >> 8 & 255);
1647
+ let buffer = 0;
1648
+ let bitsCollected = 0;
1649
+ if (this.padding && strict) {
1650
+ ok(data.length % 4 === 0, "Invalid Base64 data");
1651
+ }
1652
+ for (const char of data) {
1653
+ if (char === this.padding) break;
1654
+ const value = this.decodeMap.get(char);
1655
+ if (value === void 0) {
1656
+ throw new Error(`Invalid Base64 character: ${char}`);
1674
1657
  }
1675
- if (padCount < 1) {
1676
- result.push(buffer & 255);
1658
+ buffer = buffer << 6 | value;
1659
+ bitsCollected += 6;
1660
+ if (bitsCollected >= 8) {
1661
+ bitsCollected -= 8;
1662
+ result.push(buffer >> bitsCollected & 255);
1677
1663
  }
1678
1664
  }
1679
1665
  return Uint8Array.from(result);
@@ -1687,10 +1673,22 @@ const base64url = new Base64Encoding(
1687
1673
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
1688
1674
  );
1689
1675
 
1690
- function base64ToBytes(data, { encoding = "base64", strict } = {}) {
1676
+ function base64ToBytes(data, { encoding = "base64", strict, native = true } = {}) {
1691
1677
  if (encoding === "base64") {
1678
+ if (native && isFunction(Uint8Array.fromBase64)) {
1679
+ return Uint8Array.fromBase64(data, {
1680
+ alphabet: "base64",
1681
+ lastChunkHandling: strict ?? true ? "strict" : "loose"
1682
+ });
1683
+ }
1692
1684
  return base64.decode(data, { strict: strict ?? true });
1693
1685
  } else if (encoding === "base64url") {
1686
+ if (native && isFunction(Uint8Array.fromBase64)) {
1687
+ return Uint8Array.fromBase64(data, {
1688
+ alphabet: "base64url",
1689
+ lastChunkHandling: strict ?? false ? "strict" : "loose"
1690
+ });
1691
+ }
1694
1692
  return base64url.decode(data, { strict: strict ?? false });
1695
1693
  }
1696
1694
  ok(false, "Invalid encoding options: " + encoding);
@@ -2154,10 +2152,22 @@ function buildFieldsInfo(fields, totalBits) {
2154
2152
  return result;
2155
2153
  }
2156
2154
 
2157
- function bytesToBase64(data, { encoding = "base64", padding } = {}) {
2155
+ function bytesToBase64(data, { encoding = "base64", padding, native = true } = {}) {
2158
2156
  if (encoding === "base64") {
2157
+ if (native && isFunction(data.toBase64)) {
2158
+ return data.toBase64({
2159
+ alphabet: "base64",
2160
+ omitPadding: !(padding ?? true)
2161
+ });
2162
+ }
2159
2163
  return base64.encode(data, { includePadding: padding ?? true });
2160
2164
  } else if (encoding === "base64url") {
2165
+ if (native && isFunction(data.toBase64)) {
2166
+ return data.toBase64({
2167
+ alphabet: "base64url",
2168
+ omitPadding: !(padding ?? false)
2169
+ });
2170
+ }
2161
2171
  return base64url.encode(data, { includePadding: padding ?? false });
2162
2172
  }
2163
2173
  ok(false, "Invalid encoding options: " + encoding);
@@ -5208,17 +5218,28 @@ function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] }
5208
5218
  return throttled;
5209
5219
  }
5210
5220
 
5211
- const LEVEL_NUM = {
5221
+ const LEVEL_NAME_TO_NUM = {
5212
5222
  debug: 0,
5213
5223
  log: 1,
5214
5224
  info: 2,
5215
5225
  warn: 3,
5216
5226
  error: 4
5217
5227
  };
5218
- let currentLogLevel = LEVEL_NUM.log;
5219
- const loggerSetLevel = (level) => {
5220
- number$1(LEVEL_NUM[level], `Invalid log level: ${level}`);
5221
- currentLogLevel = LEVEL_NUM[level];
5228
+ const LEVEL_NUM_TO_NAME = {
5229
+ 0: "debug",
5230
+ 1: "log",
5231
+ 2: "info",
5232
+ 3: "warn",
5233
+ 4: "error"
5234
+ };
5235
+ const LOG_LEVEL = env.string("LOG_LEVEL", "info");
5236
+ let currentLogLevel = LOG_LEVEL in LEVEL_NAME_TO_NUM ? LEVEL_NAME_TO_NUM[LOG_LEVEL] : LEVEL_NAME_TO_NUM.log;
5237
+ const setLoggerLevel = (level) => {
5238
+ number$1(LEVEL_NAME_TO_NUM[level], `Invalid log level: ${level}`);
5239
+ currentLogLevel = LEVEL_NAME_TO_NUM[level];
5240
+ };
5241
+ const getLoggerLevel = () => {
5242
+ return LEVEL_NUM_TO_NAME[currentLogLevel];
5222
5243
  };
5223
5244
  const logger = (...baseArgs) => {
5224
5245
  if (isString(baseArgs[0]?.url)) {
@@ -5228,7 +5249,7 @@ const logger = (...baseArgs) => {
5228
5249
  baseArgs[0] = `[${baseArgs[0].split("/").at(-1).split("?", 1)[0]}]`;
5229
5250
  }
5230
5251
  const writeLog = (level, ...[pattern, ...args]) => {
5231
- const levelNum = LEVEL_NUM[level];
5252
+ const levelNum = LEVEL_NAME_TO_NUM[level];
5232
5253
  if (levelNum < currentLogLevel) {
5233
5254
  return;
5234
5255
  }
@@ -5956,6 +5977,135 @@ class ResourcePool extends SimpleEventEmitter {
5956
5977
  }
5957
5978
  }
5958
5979
 
5980
+ const SCHEDULER_JOB_FLAGS = {
5981
+ QUEUED: 1 << 0,
5982
+ ALLOW_RECURSE: 1 << 2,
5983
+ DISPOSED: 1 << 3
5984
+ };
5985
+ function createScheduler() {
5986
+ return new Scheduler();
5987
+ }
5988
+ class Scheduler {
5989
+ queue = [];
5990
+ flushIndex = -1;
5991
+ resolvedPromise = Promise.resolve();
5992
+ currentFlushPromise = null;
5993
+ onJobCbs = [];
5994
+ onJobStartCbs = [];
5995
+ onJobCompleteCbs = [];
5996
+ constructor() {
5997
+ for (const methodName of Object.getOwnPropertyNames(
5998
+ Object.getPrototypeOf(this)
5999
+ )) {
6000
+ this[methodName] = this[methodName].bind(this);
6001
+ }
6002
+ }
6003
+ onJob(fn) {
6004
+ this.onJobCbs.push(fn);
6005
+ }
6006
+ onJobStart(fn) {
6007
+ this.onJobStartCbs.push(fn);
6008
+ }
6009
+ onJobComplete(fn) {
6010
+ this.onJobCompleteCbs.push(fn);
6011
+ }
6012
+ nextTick(fn) {
6013
+ const p = this.currentFlushPromise || this.resolvedPromise;
6014
+ return fn ? p.then(this ? fn.bind(this) : fn) : p;
6015
+ }
6016
+ queueJob(job, opts) {
6017
+ if (opts) {
6018
+ Object.assign(job, opts);
6019
+ }
6020
+ if (!(job.flags & SCHEDULER_JOB_FLAGS.QUEUED)) {
6021
+ const jobId = getId(job);
6022
+ const lastJob = this.queue[this.queue.length - 1];
6023
+ if (!lastJob || jobId >= getId(lastJob)) {
6024
+ this.queue.push(job);
6025
+ } else {
6026
+ this.queue.splice(this.findInsertionIndex(jobId), 0, job);
6027
+ }
6028
+ job.flags |= SCHEDULER_JOB_FLAGS.QUEUED;
6029
+ this.queueFlush();
6030
+ for (const hookFn of this.onJobCbs) {
6031
+ hookFn(job);
6032
+ }
6033
+ }
6034
+ }
6035
+ queueJobWait(job, opts) {
6036
+ return new CancellablePromise((resolve, reject, onCancel) => {
6037
+ onCancel(() => {
6038
+ job.flags |= SCHEDULER_JOB_FLAGS.DISPOSED;
6039
+ reject(new Error("Canceled"));
6040
+ });
6041
+ const fn = () => {
6042
+ return Promise.resolve().then(() => job()).then(resolve).catch(reject);
6043
+ };
6044
+ fn.id = job.id;
6045
+ fn.flags = job.flags;
6046
+ this.queueJob(fn, opts);
6047
+ });
6048
+ }
6049
+ findInsertionIndex(id) {
6050
+ let start = this.flushIndex + 1;
6051
+ let end = this.queue.length;
6052
+ while (start < end) {
6053
+ const middle = start + end >>> 1;
6054
+ const middleJob = this.queue[middle];
6055
+ const middleJobId = getId(middleJob);
6056
+ if (middleJobId < id) {
6057
+ start = middle + 1;
6058
+ } else {
6059
+ end = middle;
6060
+ }
6061
+ }
6062
+ return start;
6063
+ }
6064
+ async flushJobs() {
6065
+ try {
6066
+ for (this.flushIndex = 0; this.flushIndex < this.queue.length; this.flushIndex++) {
6067
+ const job = this.queue[this.flushIndex];
6068
+ if (job && !(job.flags & SCHEDULER_JOB_FLAGS.DISPOSED)) {
6069
+ if (job.flags & SCHEDULER_JOB_FLAGS.ALLOW_RECURSE) {
6070
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6071
+ }
6072
+ for (const hookFn of this.onJobStartCbs) {
6073
+ hookFn(job);
6074
+ }
6075
+ await job();
6076
+ for (const hookFn of this.onJobCompleteCbs) {
6077
+ hookFn(job);
6078
+ }
6079
+ if (!(job.flags & SCHEDULER_JOB_FLAGS.ALLOW_RECURSE)) {
6080
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6081
+ }
6082
+ }
6083
+ }
6084
+ } finally {
6085
+ for (; this.flushIndex < this.queue.length; this.flushIndex++) {
6086
+ const job = this.queue[this.flushIndex];
6087
+ if (job) {
6088
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6089
+ }
6090
+ }
6091
+ this.flushIndex = -1;
6092
+ this.queue.length = 0;
6093
+ this.currentFlushPromise = null;
6094
+ if (this.queue.length) {
6095
+ return this.flushJobs();
6096
+ }
6097
+ }
6098
+ }
6099
+ queueFlush() {
6100
+ if (!this.currentFlushPromise) {
6101
+ this.currentFlushPromise = this.resolvedPromise.then(this.flushJobs);
6102
+ }
6103
+ }
6104
+ }
6105
+ function getId(job) {
6106
+ return job.id == null ? Infinity : job.id;
6107
+ }
6108
+
5959
6109
  function timeout(ms, promiseOrCallback, timeoutError = new AppError(408)) {
5960
6110
  const abortController = new AbortController();
5961
6111
  let taskResult;
@@ -6054,6 +6204,8 @@ exports.FixedWeakMap = FixedWeakMap;
6054
6204
  exports.LruCache = LruCache;
6055
6205
  exports.Queue = Queue;
6056
6206
  exports.ResourcePool = ResourcePool;
6207
+ exports.SCHEDULER_JOB_FLAGS = SCHEDULER_JOB_FLAGS;
6208
+ exports.Scheduler = Scheduler;
6057
6209
  exports.SimpleEventEmitter = SimpleEventEmitter;
6058
6210
  exports.SortedArray = SortedArray;
6059
6211
  exports.TWEMOJI_REGEX = TWEMOJI_REGEX;
@@ -6113,6 +6265,7 @@ exports.createEJSONStream = createEJSONStream;
6113
6265
  exports.createEnvParser = createEnvParser;
6114
6266
  exports.createFunction = createFunction;
6115
6267
  exports.createRandomizer = createRandomizer;
6268
+ exports.createScheduler = createScheduler;
6116
6269
  exports.createSecureCustomizer = createSecureCustomizer;
6117
6270
  exports.createTimeObject = createTimeObject;
6118
6271
  exports.createTimeSpan = createTimeSpan;
@@ -6147,6 +6300,7 @@ exports.get = get;
6147
6300
  exports.getFileExtension = getFileExtension;
6148
6301
  exports.getFileName = getFileName;
6149
6302
  exports.getInitials = getInitials;
6303
+ exports.getLoggerLevel = getLoggerLevel;
6150
6304
  exports.getMostSpecificPaths = getMostSpecificPaths;
6151
6305
  exports.getRandomInt = getRandomInt;
6152
6306
  exports.getRandomTime = getRandomTime;
@@ -6204,7 +6358,6 @@ exports.isoToFlagEmoji = isoToFlagEmoji;
6204
6358
  exports.kebabCase = kebabCase;
6205
6359
  exports.keyBy = keyBy;
6206
6360
  exports.logger = logger;
6207
- exports.loggerSetLevel = loggerSetLevel;
6208
6361
  exports.lowerCase = lowerCase;
6209
6362
  exports.luminance = luminance;
6210
6363
  exports.maskingEmail = maskingEmail;
@@ -6233,6 +6386,7 @@ exports.rleEncode = rleEncode;
6233
6386
  exports.round2digits = round2digits;
6234
6387
  exports.secondsToHm = secondsToHm;
6235
6388
  exports.set = set;
6389
+ exports.setLoggerLevel = setLoggerLevel;
6236
6390
  exports.shuffle = shuffle;
6237
6391
  exports.snakeCase = snakeCase;
6238
6392
  exports.sprintf = sprintf;