@andrew_l/toolkit 0.3.6 → 0.3.8

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);
@@ -4598,10 +4608,18 @@ const env = (() => {
4598
4608
  })();
4599
4609
  function createEnvParser(targetObject) {
4600
4610
  return Object.freeze({
4601
- isDevelopment: targetObject.NODE_ENV === "development",
4602
- isProduction: targetObject.NODE_ENV === "production",
4603
- isStage: targetObject.NODE_ENV === "state",
4604
- isTest: targetObject.NODE_ENV === "test",
4611
+ get isDevelopment() {
4612
+ return targetObject.NODE_ENV === "development";
4613
+ },
4614
+ get isProduction() {
4615
+ return targetObject.NODE_ENV === "production";
4616
+ },
4617
+ get isStage() {
4618
+ return targetObject.NODE_ENV === "state";
4619
+ },
4620
+ get isTest() {
4621
+ return targetObject.NODE_ENV === "test";
4622
+ },
4605
4623
  bool(key, defaultValue = false) {
4606
4624
  if (!(key in targetObject)) {
4607
4625
  return defaultValue;
@@ -5208,17 +5226,28 @@ function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] }
5208
5226
  return throttled;
5209
5227
  }
5210
5228
 
5211
- const LEVEL_NUM = {
5229
+ const LEVEL_NAME_TO_NUM = {
5212
5230
  debug: 0,
5213
5231
  log: 1,
5214
5232
  info: 2,
5215
5233
  warn: 3,
5216
5234
  error: 4
5217
5235
  };
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];
5236
+ const LEVEL_NUM_TO_NAME = {
5237
+ 0: "debug",
5238
+ 1: "log",
5239
+ 2: "info",
5240
+ 3: "warn",
5241
+ 4: "error"
5242
+ };
5243
+ const LOG_LEVEL = env.string("LOG_LEVEL", "info");
5244
+ let currentLogLevel = LOG_LEVEL in LEVEL_NAME_TO_NUM ? LEVEL_NAME_TO_NUM[LOG_LEVEL] : LEVEL_NAME_TO_NUM.log;
5245
+ const setLoggerLevel = (level) => {
5246
+ number$1(LEVEL_NAME_TO_NUM[level], `Invalid log level: ${level}`);
5247
+ currentLogLevel = LEVEL_NAME_TO_NUM[level];
5248
+ };
5249
+ const getLoggerLevel = () => {
5250
+ return LEVEL_NUM_TO_NAME[currentLogLevel];
5222
5251
  };
5223
5252
  const logger = (...baseArgs) => {
5224
5253
  if (isString(baseArgs[0]?.url)) {
@@ -5228,7 +5257,7 @@ const logger = (...baseArgs) => {
5228
5257
  baseArgs[0] = `[${baseArgs[0].split("/").at(-1).split("?", 1)[0]}]`;
5229
5258
  }
5230
5259
  const writeLog = (level, ...[pattern, ...args]) => {
5231
- const levelNum = LEVEL_NUM[level];
5260
+ const levelNum = LEVEL_NAME_TO_NUM[level];
5232
5261
  if (levelNum < currentLogLevel) {
5233
5262
  return;
5234
5263
  }
@@ -5956,6 +5985,135 @@ class ResourcePool extends SimpleEventEmitter {
5956
5985
  }
5957
5986
  }
5958
5987
 
5988
+ const SCHEDULER_JOB_FLAGS = {
5989
+ QUEUED: 1 << 0,
5990
+ ALLOW_RECURSE: 1 << 2,
5991
+ DISPOSED: 1 << 3
5992
+ };
5993
+ function createScheduler() {
5994
+ return new Scheduler();
5995
+ }
5996
+ class Scheduler {
5997
+ queue = [];
5998
+ flushIndex = -1;
5999
+ resolvedPromise = Promise.resolve();
6000
+ currentFlushPromise = null;
6001
+ onJobCbs = [];
6002
+ onJobStartCbs = [];
6003
+ onJobCompleteCbs = [];
6004
+ constructor() {
6005
+ for (const methodName of Object.getOwnPropertyNames(
6006
+ Object.getPrototypeOf(this)
6007
+ )) {
6008
+ this[methodName] = this[methodName].bind(this);
6009
+ }
6010
+ }
6011
+ onJob(fn) {
6012
+ this.onJobCbs.push(fn);
6013
+ }
6014
+ onJobStart(fn) {
6015
+ this.onJobStartCbs.push(fn);
6016
+ }
6017
+ onJobComplete(fn) {
6018
+ this.onJobCompleteCbs.push(fn);
6019
+ }
6020
+ nextTick(fn) {
6021
+ const p = this.currentFlushPromise || this.resolvedPromise;
6022
+ return fn ? p.then(this ? fn.bind(this) : fn) : p;
6023
+ }
6024
+ queueJob(job, opts) {
6025
+ if (opts) {
6026
+ Object.assign(job, opts);
6027
+ }
6028
+ if (!(job.flags & SCHEDULER_JOB_FLAGS.QUEUED)) {
6029
+ const jobId = getId(job);
6030
+ const lastJob = this.queue[this.queue.length - 1];
6031
+ if (!lastJob || jobId >= getId(lastJob)) {
6032
+ this.queue.push(job);
6033
+ } else {
6034
+ this.queue.splice(this.findInsertionIndex(jobId), 0, job);
6035
+ }
6036
+ job.flags |= SCHEDULER_JOB_FLAGS.QUEUED;
6037
+ this.queueFlush();
6038
+ for (const hookFn of this.onJobCbs) {
6039
+ hookFn(job);
6040
+ }
6041
+ }
6042
+ }
6043
+ queueJobWait(job, opts) {
6044
+ return new CancellablePromise((resolve, reject, onCancel) => {
6045
+ onCancel(() => {
6046
+ job.flags |= SCHEDULER_JOB_FLAGS.DISPOSED;
6047
+ reject(new Error("Canceled"));
6048
+ });
6049
+ const fn = () => {
6050
+ return Promise.resolve().then(() => job()).then(resolve).catch(reject);
6051
+ };
6052
+ fn.id = job.id;
6053
+ fn.flags = job.flags;
6054
+ this.queueJob(fn, opts);
6055
+ });
6056
+ }
6057
+ findInsertionIndex(id) {
6058
+ let start = this.flushIndex + 1;
6059
+ let end = this.queue.length;
6060
+ while (start < end) {
6061
+ const middle = start + end >>> 1;
6062
+ const middleJob = this.queue[middle];
6063
+ const middleJobId = getId(middleJob);
6064
+ if (middleJobId < id) {
6065
+ start = middle + 1;
6066
+ } else {
6067
+ end = middle;
6068
+ }
6069
+ }
6070
+ return start;
6071
+ }
6072
+ async flushJobs() {
6073
+ try {
6074
+ for (this.flushIndex = 0; this.flushIndex < this.queue.length; this.flushIndex++) {
6075
+ const job = this.queue[this.flushIndex];
6076
+ if (job && !(job.flags & SCHEDULER_JOB_FLAGS.DISPOSED)) {
6077
+ if (job.flags & SCHEDULER_JOB_FLAGS.ALLOW_RECURSE) {
6078
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6079
+ }
6080
+ for (const hookFn of this.onJobStartCbs) {
6081
+ hookFn(job);
6082
+ }
6083
+ await job();
6084
+ for (const hookFn of this.onJobCompleteCbs) {
6085
+ hookFn(job);
6086
+ }
6087
+ if (!(job.flags & SCHEDULER_JOB_FLAGS.ALLOW_RECURSE)) {
6088
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6089
+ }
6090
+ }
6091
+ }
6092
+ } finally {
6093
+ for (; this.flushIndex < this.queue.length; this.flushIndex++) {
6094
+ const job = this.queue[this.flushIndex];
6095
+ if (job) {
6096
+ job.flags &= ~SCHEDULER_JOB_FLAGS.QUEUED;
6097
+ }
6098
+ }
6099
+ this.flushIndex = -1;
6100
+ this.queue.length = 0;
6101
+ this.currentFlushPromise = null;
6102
+ if (this.queue.length) {
6103
+ return this.flushJobs();
6104
+ }
6105
+ }
6106
+ }
6107
+ queueFlush() {
6108
+ if (!this.currentFlushPromise) {
6109
+ this.currentFlushPromise = this.resolvedPromise.then(this.flushJobs);
6110
+ }
6111
+ }
6112
+ }
6113
+ function getId(job) {
6114
+ return job.id == null ? Infinity : job.id;
6115
+ }
6116
+
5959
6117
  function timeout(ms, promiseOrCallback, timeoutError = new AppError(408)) {
5960
6118
  const abortController = new AbortController();
5961
6119
  let taskResult;
@@ -6054,6 +6212,8 @@ exports.FixedWeakMap = FixedWeakMap;
6054
6212
  exports.LruCache = LruCache;
6055
6213
  exports.Queue = Queue;
6056
6214
  exports.ResourcePool = ResourcePool;
6215
+ exports.SCHEDULER_JOB_FLAGS = SCHEDULER_JOB_FLAGS;
6216
+ exports.Scheduler = Scheduler;
6057
6217
  exports.SimpleEventEmitter = SimpleEventEmitter;
6058
6218
  exports.SortedArray = SortedArray;
6059
6219
  exports.TWEMOJI_REGEX = TWEMOJI_REGEX;
@@ -6113,6 +6273,7 @@ exports.createEJSONStream = createEJSONStream;
6113
6273
  exports.createEnvParser = createEnvParser;
6114
6274
  exports.createFunction = createFunction;
6115
6275
  exports.createRandomizer = createRandomizer;
6276
+ exports.createScheduler = createScheduler;
6116
6277
  exports.createSecureCustomizer = createSecureCustomizer;
6117
6278
  exports.createTimeObject = createTimeObject;
6118
6279
  exports.createTimeSpan = createTimeSpan;
@@ -6147,6 +6308,7 @@ exports.get = get;
6147
6308
  exports.getFileExtension = getFileExtension;
6148
6309
  exports.getFileName = getFileName;
6149
6310
  exports.getInitials = getInitials;
6311
+ exports.getLoggerLevel = getLoggerLevel;
6150
6312
  exports.getMostSpecificPaths = getMostSpecificPaths;
6151
6313
  exports.getRandomInt = getRandomInt;
6152
6314
  exports.getRandomTime = getRandomTime;
@@ -6204,7 +6366,6 @@ exports.isoToFlagEmoji = isoToFlagEmoji;
6204
6366
  exports.kebabCase = kebabCase;
6205
6367
  exports.keyBy = keyBy;
6206
6368
  exports.logger = logger;
6207
- exports.loggerSetLevel = loggerSetLevel;
6208
6369
  exports.lowerCase = lowerCase;
6209
6370
  exports.luminance = luminance;
6210
6371
  exports.maskingEmail = maskingEmail;
@@ -6233,6 +6394,7 @@ exports.rleEncode = rleEncode;
6233
6394
  exports.round2digits = round2digits;
6234
6395
  exports.secondsToHm = secondsToHm;
6235
6396
  exports.set = set;
6397
+ exports.setLoggerLevel = setLoggerLevel;
6236
6398
  exports.shuffle = shuffle;
6237
6399
  exports.snakeCase = snakeCase;
6238
6400
  exports.sprintf = sprintf;