WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
var regeneratorDefine = require("./regeneratorDefine.js");
|
||||
function _regenerator() {
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
||||
var e,
|
||||
t,
|
||||
r = "function" == typeof Symbol ? Symbol : {},
|
||||
n = r.iterator || "@@iterator",
|
||||
o = r.toStringTag || "@@toStringTag";
|
||||
function i(r, n, o, i) {
|
||||
var c = n && n.prototype instanceof Generator ? n : Generator,
|
||||
u = Object.create(c.prototype);
|
||||
return regeneratorDefine(u, "_invoke", function (r, n, o) {
|
||||
var i,
|
||||
c,
|
||||
u,
|
||||
f = 0,
|
||||
p = o || [],
|
||||
y = !1,
|
||||
G = {
|
||||
p: 0,
|
||||
n: 0,
|
||||
v: e,
|
||||
a: d,
|
||||
f: d.bind(e, 4),
|
||||
d: function d(t, r) {
|
||||
return i = t, c = 0, u = e, G.n = r, a;
|
||||
}
|
||||
};
|
||||
function d(r, n) {
|
||||
for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
|
||||
var o,
|
||||
i = p[t],
|
||||
d = G.p,
|
||||
l = i[2];
|
||||
r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
|
||||
}
|
||||
if (o || r > 1) return a;
|
||||
throw y = !0, n;
|
||||
}
|
||||
return function (o, p, l) {
|
||||
if (f > 1) throw TypeError("Generator is already running");
|
||||
for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
|
||||
i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
|
||||
try {
|
||||
if (f = 2, i) {
|
||||
if (c || (o = "next"), t = i[o]) {
|
||||
if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
|
||||
if (!t.done) return t;
|
||||
u = t.value, c < 2 && (c = 0);
|
||||
} else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
|
||||
i = e;
|
||||
} else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
|
||||
} catch (t) {
|
||||
i = e, c = 1, u = t;
|
||||
} finally {
|
||||
f = 1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: t,
|
||||
done: y
|
||||
};
|
||||
};
|
||||
}(r, o, i), !0), u;
|
||||
}
|
||||
var a = {};
|
||||
function Generator() {}
|
||||
function GeneratorFunction() {}
|
||||
function GeneratorFunctionPrototype() {}
|
||||
t = Object.getPrototypeOf;
|
||||
var c = [][n] ? t(t([][n]())) : (regeneratorDefine(t = {}, n, function () {
|
||||
return this;
|
||||
}), t),
|
||||
u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
|
||||
function f(e) {
|
||||
return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
|
||||
}
|
||||
return GeneratorFunction.prototype = GeneratorFunctionPrototype, regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), regeneratorDefine(u), regeneratorDefine(u, o, "Generator"), regeneratorDefine(u, n, function () {
|
||||
return this;
|
||||
}), regeneratorDefine(u, "toString", function () {
|
||||
return "[object Generator]";
|
||||
}), (module.exports = _regenerator = function _regenerator() {
|
||||
return {
|
||||
w: i,
|
||||
m: f
|
||||
};
|
||||
}, module.exports.__esModule = true, module.exports["default"] = module.exports)();
|
||||
}
|
||||
module.exports = _regenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,5 @@
|
||||
const file12 = require("./file12.js")
|
||||
|
||||
module.exports = function () {
|
||||
file12()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2024 = void 0;
|
||||
const es2023_1 = require("./es2023");
|
||||
const es2024_arraybuffer_1 = require("./es2024.arraybuffer");
|
||||
const es2024_collection_1 = require("./es2024.collection");
|
||||
const es2024_object_1 = require("./es2024.object");
|
||||
const es2024_promise_1 = require("./es2024.promise");
|
||||
const es2024_regexp_1 = require("./es2024.regexp");
|
||||
const es2024_sharedmemory_1 = require("./es2024.sharedmemory");
|
||||
const es2024_string_1 = require("./es2024.string");
|
||||
exports.es2024 = {
|
||||
libs: [
|
||||
es2023_1.es2023,
|
||||
es2024_arraybuffer_1.es2024_arraybuffer,
|
||||
es2024_collection_1.es2024_collection,
|
||||
es2024_object_1.es2024_object,
|
||||
es2024_promise_1.es2024_promise,
|
||||
es2024_regexp_1.es2024_regexp,
|
||||
es2024_sharedmemory_1.es2024_sharedmemory,
|
||||
es2024_string_1.es2024_string,
|
||||
],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2013, Joel Feenstra
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the ESQuery nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,5 @@
|
||||
var arrayLikeToArray = require("./arrayLikeToArray.js");
|
||||
function _arrayWithoutHoles(r) {
|
||||
if (Array.isArray(r)) return arrayLikeToArray(r);
|
||||
}
|
||||
module.exports = _arrayWithoutHoles, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { SyncWalker } from './sync.js';
|
||||
import { AsyncWalker } from './async.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('estree').Node} Node
|
||||
* @typedef {import('./sync.js').SyncHandler} SyncHandler
|
||||
* @typedef {import('./async.js').AsyncHandler} AsyncHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Node} ast
|
||||
* @param {{
|
||||
* enter?: SyncHandler
|
||||
* leave?: SyncHandler
|
||||
* }} walker
|
||||
* @returns {Node | null}
|
||||
*/
|
||||
export function walk(ast, { enter, leave }) {
|
||||
const instance = new SyncWalker(enter, leave);
|
||||
return instance.visit(ast, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} ast
|
||||
* @param {{
|
||||
* enter?: AsyncHandler
|
||||
* leave?: AsyncHandler
|
||||
* }} walker
|
||||
* @returns {Promise<Node | null>}
|
||||
*/
|
||||
export async function asyncWalk(ast, { enter, leave }) {
|
||||
const instance = new AsyncWalker(enter, leave);
|
||||
return await instance.visit(ast, null);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2021_full = void 0;
|
||||
const dom_1 = require("./dom");
|
||||
const dom_asynciterable_1 = require("./dom.asynciterable");
|
||||
const dom_iterable_1 = require("./dom.iterable");
|
||||
const es2021_1 = require("./es2021");
|
||||
const scripthost_1 = require("./scripthost");
|
||||
const webworker_importscripts_1 = require("./webworker.importscripts");
|
||||
exports.es2021_full = {
|
||||
libs: [
|
||||
es2021_1.es2021,
|
||||
dom_1.dom,
|
||||
webworker_importscripts_1.webworker_importscripts,
|
||||
scripthost_1.scripthost,
|
||||
dom_iterable_1.dom_iterable,
|
||||
dom_asynciterable_1.dom_asynciterable,
|
||||
],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1,517 @@
|
||||
'use strict'
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
|
||||
const NOOP = function () {}
|
||||
|
||||
const removeWhere = (list, predicate) => {
|
||||
const i = list.findIndex(predicate)
|
||||
|
||||
return i === -1 ? undefined : list.splice(i, 1)[0]
|
||||
}
|
||||
|
||||
class IdleItem {
|
||||
constructor(client, idleListener, timeoutId) {
|
||||
this.client = client
|
||||
this.idleListener = idleListener
|
||||
this.timeoutId = timeoutId
|
||||
}
|
||||
}
|
||||
|
||||
class PendingItem {
|
||||
constructor(callback) {
|
||||
this.callback = callback
|
||||
}
|
||||
}
|
||||
|
||||
function throwOnDoubleRelease() {
|
||||
throw new Error('Release called on client which has already been released to the pool.')
|
||||
}
|
||||
|
||||
function promisify(Promise, callback) {
|
||||
if (callback) {
|
||||
return { callback: callback, result: undefined }
|
||||
}
|
||||
let rej
|
||||
let res
|
||||
const cb = function (err, client) {
|
||||
err ? rej(err) : res(client)
|
||||
}
|
||||
const result = new Promise(function (resolve, reject) {
|
||||
res = resolve
|
||||
rej = reject
|
||||
}).catch((err) => {
|
||||
// replace the stack trace that leads to `TCP.onStreamRead` with one that leads back to the
|
||||
// application that created the query
|
||||
Error.captureStackTrace(err)
|
||||
throw err
|
||||
})
|
||||
return { callback: cb, result: result }
|
||||
}
|
||||
|
||||
function makeIdleListener(pool, client) {
|
||||
return function idleListener(err) {
|
||||
err.client = client
|
||||
|
||||
client.removeListener('error', idleListener)
|
||||
client.on('error', () => {
|
||||
pool.log('additional client error after disconnection due to error', err)
|
||||
})
|
||||
pool._remove(client)
|
||||
// TODO - document that once the pool emits an error
|
||||
// the client has already been closed & purged and is unusable
|
||||
pool.emit('error', err, client)
|
||||
}
|
||||
}
|
||||
|
||||
class Pool extends EventEmitter {
|
||||
constructor(options, Client) {
|
||||
super()
|
||||
this.options = Object.assign({}, options)
|
||||
|
||||
if (options != null && 'password' in options) {
|
||||
// "hiding" the password so it doesn't show up in stack traces
|
||||
// or if the client is console.logged
|
||||
Object.defineProperty(this.options, 'password', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: options.password,
|
||||
})
|
||||
}
|
||||
if (options != null && options.ssl && options.ssl.key) {
|
||||
// "hiding" the ssl->key so it doesn't show up in stack traces
|
||||
// or if the client is console.logged
|
||||
Object.defineProperty(this.options.ssl, 'key', {
|
||||
enumerable: false,
|
||||
})
|
||||
}
|
||||
|
||||
this.options.max = this.options.max || this.options.poolSize || 10
|
||||
this.options.min = this.options.min || 0
|
||||
this.options.maxUses = this.options.maxUses || Infinity
|
||||
this.options.allowExitOnIdle = this.options.allowExitOnIdle || false
|
||||
this.options.maxLifetimeSeconds = this.options.maxLifetimeSeconds || 0
|
||||
this.log = this.options.log || function () {}
|
||||
this.Client = this.options.Client || Client || require('pg').Client
|
||||
this.Promise = this.options.Promise || global.Promise
|
||||
|
||||
if (typeof this.options.idleTimeoutMillis === 'undefined') {
|
||||
this.options.idleTimeoutMillis = 10000
|
||||
}
|
||||
|
||||
this._clients = []
|
||||
this._idle = []
|
||||
this._expired = new WeakSet()
|
||||
this._pendingQueue = []
|
||||
this._endCallback = undefined
|
||||
this.ending = false
|
||||
this.ended = false
|
||||
}
|
||||
|
||||
_promiseTry(f) {
|
||||
const Promise = this.Promise
|
||||
if (typeof Promise.try === 'function') {
|
||||
return Promise.try(f)
|
||||
}
|
||||
return new Promise((resolve) => resolve(f()))
|
||||
}
|
||||
|
||||
_isFull() {
|
||||
return this._clients.length >= this.options.max
|
||||
}
|
||||
|
||||
_isAboveMin() {
|
||||
return this._clients.length > this.options.min
|
||||
}
|
||||
|
||||
_pulseQueue() {
|
||||
this.log('pulse queue')
|
||||
if (this.ended) {
|
||||
this.log('pulse queue ended')
|
||||
return
|
||||
}
|
||||
if (this.ending) {
|
||||
this.log('pulse queue on ending')
|
||||
if (this._idle.length) {
|
||||
this._idle.slice().map((item) => {
|
||||
this._remove(item.client)
|
||||
})
|
||||
}
|
||||
if (!this._clients.length) {
|
||||
this.ended = true
|
||||
this._endCallback()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if we don't have any waiting, do nothing
|
||||
if (!this._pendingQueue.length) {
|
||||
this.log('no queued requests')
|
||||
return
|
||||
}
|
||||
// if we don't have any idle clients and we have no more room do nothing
|
||||
if (!this._idle.length && this._isFull()) {
|
||||
return
|
||||
}
|
||||
const pendingItem = this._pendingQueue.shift()
|
||||
if (this._idle.length) {
|
||||
const idleItem = this._idle.pop()
|
||||
clearTimeout(idleItem.timeoutId)
|
||||
const client = idleItem.client
|
||||
client.ref && client.ref()
|
||||
const idleListener = idleItem.idleListener
|
||||
|
||||
return this._acquireClient(client, pendingItem, idleListener, false)
|
||||
}
|
||||
if (!this._isFull()) {
|
||||
return this.newClient(pendingItem)
|
||||
}
|
||||
throw new Error('unexpected condition')
|
||||
}
|
||||
|
||||
_remove(client, callback) {
|
||||
const removed = removeWhere(this._idle, (item) => item.client === client)
|
||||
|
||||
if (removed !== undefined) {
|
||||
clearTimeout(removed.timeoutId)
|
||||
}
|
||||
|
||||
this._clients = this._clients.filter((c) => c !== client)
|
||||
const context = this
|
||||
client.end(() => {
|
||||
context.emit('remove', client)
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
connect(cb) {
|
||||
if (this.ending) {
|
||||
const err = new Error('Cannot use a pool after calling end on the pool')
|
||||
return cb ? cb(err) : this.Promise.reject(err)
|
||||
}
|
||||
|
||||
const response = promisify(this.Promise, cb)
|
||||
const result = response.result
|
||||
|
||||
// if we don't have to connect a new client, don't do so
|
||||
if (this._isFull() || this._idle.length) {
|
||||
// if we have idle clients schedule a pulse immediately
|
||||
if (this._idle.length) {
|
||||
process.nextTick(() => this._pulseQueue())
|
||||
}
|
||||
|
||||
if (!this.options.connectionTimeoutMillis) {
|
||||
this._pendingQueue.push(new PendingItem(response.callback))
|
||||
return result
|
||||
}
|
||||
|
||||
const queueCallback = (err, res, done) => {
|
||||
clearTimeout(tid)
|
||||
response.callback(err, res, done)
|
||||
}
|
||||
|
||||
const pendingItem = new PendingItem(queueCallback)
|
||||
|
||||
// set connection timeout on checking out an existing client
|
||||
const tid = setTimeout(() => {
|
||||
// remove the callback from pending waiters because
|
||||
// we're going to call it with a timeout error
|
||||
removeWhere(this._pendingQueue, (i) => i.callback === queueCallback)
|
||||
pendingItem.timedOut = true
|
||||
response.callback(new Error('timeout exceeded when trying to connect'))
|
||||
}, this.options.connectionTimeoutMillis)
|
||||
|
||||
if (tid.unref) {
|
||||
tid.unref()
|
||||
}
|
||||
|
||||
this._pendingQueue.push(pendingItem)
|
||||
return result
|
||||
}
|
||||
|
||||
this.newClient(new PendingItem(response.callback))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
newClient(pendingItem) {
|
||||
const client = new this.Client(this.options)
|
||||
this._clients.push(client)
|
||||
const idleListener = makeIdleListener(this, client)
|
||||
|
||||
this.log('checking client timeout')
|
||||
|
||||
// connection timeout logic
|
||||
let tid
|
||||
let timeoutHit = false
|
||||
if (this.options.connectionTimeoutMillis) {
|
||||
tid = setTimeout(() => {
|
||||
if (client.connection) {
|
||||
this.log('ending client due to timeout')
|
||||
timeoutHit = true
|
||||
client.connection.stream.destroy()
|
||||
} else if (!client.isConnected()) {
|
||||
this.log('ending client due to timeout')
|
||||
timeoutHit = true
|
||||
// force kill the node driver, and let libpq do its teardown
|
||||
client.end()
|
||||
}
|
||||
}, this.options.connectionTimeoutMillis)
|
||||
}
|
||||
|
||||
this.log('connecting new client')
|
||||
client.connect((err) => {
|
||||
if (tid) {
|
||||
clearTimeout(tid)
|
||||
}
|
||||
client.on('error', idleListener)
|
||||
if (err) {
|
||||
this.log('client failed to connect', err)
|
||||
// remove the dead client from our list of clients
|
||||
this._clients = this._clients.filter((c) => c !== client)
|
||||
if (timeoutHit) {
|
||||
err = new Error('Connection terminated due to connection timeout', { cause: err })
|
||||
}
|
||||
|
||||
// this client won’t be released, so move on immediately
|
||||
this._pulseQueue()
|
||||
|
||||
if (!pendingItem.timedOut) {
|
||||
pendingItem.callback(err, undefined, NOOP)
|
||||
}
|
||||
} else {
|
||||
this.log('new client connected')
|
||||
|
||||
if (this.options.onConnect) {
|
||||
this._promiseTry(() => this.options.onConnect(client)).then(
|
||||
() => {
|
||||
this._afterConnect(client, pendingItem, idleListener)
|
||||
},
|
||||
(hookErr) => {
|
||||
this._clients = this._clients.filter((c) => c !== client)
|
||||
client.end(() => {
|
||||
this._pulseQueue()
|
||||
if (!pendingItem.timedOut) {
|
||||
pendingItem.callback(hookErr, undefined, NOOP)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
return this._afterConnect(client, pendingItem, idleListener)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_afterConnect(client, pendingItem, idleListener) {
|
||||
if (this.options.maxLifetimeSeconds !== 0) {
|
||||
const maxLifetimeTimeout = setTimeout(() => {
|
||||
this.log('ending client due to expired lifetime')
|
||||
this._expired.add(client)
|
||||
const idleIndex = this._idle.findIndex((idleItem) => idleItem.client === client)
|
||||
if (idleIndex !== -1) {
|
||||
this._acquireClient(
|
||||
client,
|
||||
new PendingItem((err, client, clientRelease) => clientRelease()),
|
||||
idleListener,
|
||||
false
|
||||
)
|
||||
}
|
||||
}, this.options.maxLifetimeSeconds * 1000)
|
||||
|
||||
maxLifetimeTimeout.unref()
|
||||
client.once('end', () => clearTimeout(maxLifetimeTimeout))
|
||||
}
|
||||
|
||||
return this._acquireClient(client, pendingItem, idleListener, true)
|
||||
}
|
||||
|
||||
// acquire a client for a pending work item
|
||||
_acquireClient(client, pendingItem, idleListener, isNew) {
|
||||
if (isNew) {
|
||||
this.emit('connect', client)
|
||||
}
|
||||
|
||||
this.emit('acquire', client)
|
||||
|
||||
client.release = this._releaseOnce(client, idleListener)
|
||||
|
||||
client.removeListener('error', idleListener)
|
||||
|
||||
if (!pendingItem.timedOut) {
|
||||
if (isNew && this.options.verify) {
|
||||
this.options.verify(client, (err) => {
|
||||
if (err) {
|
||||
client.release(err)
|
||||
return pendingItem.callback(err, undefined, NOOP)
|
||||
}
|
||||
|
||||
pendingItem.callback(undefined, client, client.release)
|
||||
})
|
||||
} else {
|
||||
pendingItem.callback(undefined, client, client.release)
|
||||
}
|
||||
} else {
|
||||
if (isNew && this.options.verify) {
|
||||
this.options.verify(client, client.release)
|
||||
} else {
|
||||
client.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns a function that wraps _release and throws if called more than once
|
||||
_releaseOnce(client, idleListener) {
|
||||
let released = false
|
||||
|
||||
return (err) => {
|
||||
if (released) {
|
||||
throwOnDoubleRelease()
|
||||
}
|
||||
|
||||
released = true
|
||||
this._release(client, idleListener, err)
|
||||
}
|
||||
}
|
||||
|
||||
// release a client back to the poll, include an error
|
||||
// to remove it from the pool
|
||||
_release(client, idleListener, err) {
|
||||
client.on('error', idleListener)
|
||||
|
||||
client._poolUseCount = (client._poolUseCount || 0) + 1
|
||||
|
||||
this.emit('release', err, client)
|
||||
|
||||
// TODO(bmc): expose a proper, public interface _queryable and _ending
|
||||
if (err || this.ending || !client._queryable || client._ending || client._poolUseCount >= this.options.maxUses) {
|
||||
if (client._poolUseCount >= this.options.maxUses) {
|
||||
this.log('remove expended client')
|
||||
}
|
||||
|
||||
return this._remove(client, this._pulseQueue.bind(this))
|
||||
}
|
||||
|
||||
const isExpired = this._expired.has(client)
|
||||
if (isExpired) {
|
||||
this.log('remove expired client')
|
||||
this._expired.delete(client)
|
||||
return this._remove(client, this._pulseQueue.bind(this))
|
||||
}
|
||||
|
||||
// idle timeout
|
||||
let tid
|
||||
if (this.options.idleTimeoutMillis && this._isAboveMin()) {
|
||||
tid = setTimeout(() => {
|
||||
if (this._isAboveMin()) {
|
||||
this.log('remove idle client')
|
||||
this._remove(client, this._pulseQueue.bind(this))
|
||||
}
|
||||
}, this.options.idleTimeoutMillis)
|
||||
|
||||
if (this.options.allowExitOnIdle) {
|
||||
// allow Node to exit if this is all that's left
|
||||
tid.unref()
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.allowExitOnIdle) {
|
||||
client.unref()
|
||||
}
|
||||
|
||||
this._idle.push(new IdleItem(client, idleListener, tid))
|
||||
this._pulseQueue()
|
||||
}
|
||||
|
||||
query(text, values, cb) {
|
||||
// guard clause against passing a function as the first parameter
|
||||
if (typeof text === 'function') {
|
||||
const response = promisify(this.Promise, text)
|
||||
setImmediate(function () {
|
||||
return response.callback(new Error('Passing a function as the first parameter to pool.query is not supported'))
|
||||
})
|
||||
return response.result
|
||||
}
|
||||
|
||||
// allow plain text query without values, but callback
|
||||
if (typeof values === 'function') {
|
||||
cb = values
|
||||
values = undefined
|
||||
}
|
||||
const response = promisify(this.Promise, cb)
|
||||
cb = response.callback
|
||||
|
||||
this.connect((err, client) => {
|
||||
if (err) {
|
||||
return cb(err)
|
||||
}
|
||||
|
||||
let clientReleased = false
|
||||
const onError = (err) => {
|
||||
if (clientReleased) {
|
||||
return
|
||||
}
|
||||
clientReleased = true
|
||||
client.release(err)
|
||||
cb(err)
|
||||
}
|
||||
|
||||
client.once('error', onError)
|
||||
this.log('dispatching query')
|
||||
try {
|
||||
client.query(text, values, (err, res) => {
|
||||
this.log('query dispatched')
|
||||
client.removeListener('error', onError)
|
||||
if (clientReleased) {
|
||||
return
|
||||
}
|
||||
clientReleased = true
|
||||
client.release(err)
|
||||
if (err) {
|
||||
return cb(err)
|
||||
}
|
||||
return cb(undefined, res)
|
||||
})
|
||||
} catch (err) {
|
||||
client.release(err)
|
||||
return cb(err)
|
||||
}
|
||||
})
|
||||
return response.result
|
||||
}
|
||||
|
||||
end(cb) {
|
||||
this.log('ending')
|
||||
if (this.ending) {
|
||||
const err = new Error('Called end on pool more than once')
|
||||
return cb ? cb(err) : this.Promise.reject(err)
|
||||
}
|
||||
this.ending = true
|
||||
const promised = promisify(this.Promise, cb)
|
||||
this._endCallback = promised.callback
|
||||
this._pulseQueue()
|
||||
return promised.result
|
||||
}
|
||||
|
||||
get waitingCount() {
|
||||
return this._pendingQueue.length
|
||||
}
|
||||
|
||||
get idleCount() {
|
||||
return this._idle.length
|
||||
}
|
||||
|
||||
get expiredCount() {
|
||||
return this._clients.reduce((acc, client) => acc + (this._expired.has(client) ? 1 : 0), 0)
|
||||
}
|
||||
|
||||
get totalCount() {
|
||||
return this._clients.length
|
||||
}
|
||||
}
|
||||
module.exports = Pool
|
||||
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
// Determine if version is greater than all the versions possible in the range.
|
||||
const outside = require('./outside')
|
||||
const gtr = (version, range, options) => outside(version, range, '>', options)
|
||||
module.exports = gtr
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,465 @@
|
||||
/**
|
||||
* Methods for elliptic curve multiplication by scalars.
|
||||
* Contains wNAF, pippenger.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { bitLen, bitMask, validateObject } from "../utils.js";
|
||||
import { Field, FpInvertBatch, nLength, validateField } from "./modular.js";
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
export function negateCt(condition, item) {
|
||||
const neg = item.negate();
|
||||
return condition ? neg : item;
|
||||
}
|
||||
/**
|
||||
* Takes a bunch of Projective Points but executes only one
|
||||
* inversion on all of them. Inversion is very slow operation,
|
||||
* so this improves performance massively.
|
||||
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
||||
*/
|
||||
export function normalizeZ(c, points) {
|
||||
const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
|
||||
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
|
||||
}
|
||||
function validateW(W, bits) {
|
||||
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
||||
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
||||
}
|
||||
function calcWOpts(W, scalarBits) {
|
||||
validateW(W, scalarBits);
|
||||
const windows = Math.ceil(scalarBits / W) + 1; // W=8 33. Not 32, because we skip zero
|
||||
const windowSize = 2 ** (W - 1); // W=8 128. Not 256, because we skip zero
|
||||
const maxNumber = 2 ** W; // W=8 256
|
||||
const mask = bitMask(W); // W=8 255 == mask 0b11111111
|
||||
const shiftBy = BigInt(W); // W=8 8
|
||||
return { windows, windowSize, mask, maxNumber, shiftBy };
|
||||
}
|
||||
function calcOffsets(n, window, wOpts) {
|
||||
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
|
||||
let wbits = Number(n & mask); // extract W bits.
|
||||
let nextN = n >> shiftBy; // shift number by W bits.
|
||||
// What actually happens here:
|
||||
// const highestBit = Number(mask ^ (mask >> 1n));
|
||||
// let wbits2 = wbits - 1; // skip zero
|
||||
// if (wbits2 & highestBit) { wbits2 ^= Number(mask); // (~);
|
||||
// split if bits > max: +224 => 256-32
|
||||
if (wbits > windowSize) {
|
||||
// we skip zero, which means instead of `>= size-1`, we do `> size`
|
||||
wbits -= maxNumber; // -32, can be maxNumber - wbits, but then we need to set isNeg here.
|
||||
nextN += _1n; // +256 (carry)
|
||||
}
|
||||
const offsetStart = window * windowSize;
|
||||
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero
|
||||
const isZero = wbits === 0; // is current window slice a 0?
|
||||
const isNeg = wbits < 0; // is current window slice negative?
|
||||
const isNegF = window % 2 !== 0; // fake random statement for noise
|
||||
const offsetF = offsetStart; // fake offset for noise
|
||||
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
||||
}
|
||||
function validateMSMPoints(points, c) {
|
||||
if (!Array.isArray(points))
|
||||
throw new Error('array expected');
|
||||
points.forEach((p, i) => {
|
||||
if (!(p instanceof c))
|
||||
throw new Error('invalid point at index ' + i);
|
||||
});
|
||||
}
|
||||
function validateMSMScalars(scalars, field) {
|
||||
if (!Array.isArray(scalars))
|
||||
throw new Error('array of scalars expected');
|
||||
scalars.forEach((s, i) => {
|
||||
if (!field.isValid(s))
|
||||
throw new Error('invalid scalar at index ' + i);
|
||||
});
|
||||
}
|
||||
// Since points in different groups cannot be equal (different object constructor),
|
||||
// we can have single place to store precomputes.
|
||||
// Allows to make points frozen / immutable.
|
||||
const pointPrecomputes = new WeakMap();
|
||||
const pointWindowSizes = new WeakMap();
|
||||
function getW(P) {
|
||||
// To disable precomputes:
|
||||
// return 1;
|
||||
return pointWindowSizes.get(P) || 1;
|
||||
}
|
||||
function assert0(n) {
|
||||
if (n !== _0n)
|
||||
throw new Error('invalid wNAF');
|
||||
}
|
||||
/**
|
||||
* Elliptic curve multiplication of Point by scalar. Fragile.
|
||||
* Table generation takes **30MB of ram and 10ms on high-end CPU**,
|
||||
* but may take much longer on slow devices. Actual generation will happen on
|
||||
* first call of `multiply()`. By default, `BASE` point is precomputed.
|
||||
*
|
||||
* Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
||||
* Creates precomputation tables for fast multiplication:
|
||||
* - private scalar is split by fixed size windows of W bits
|
||||
* - every window point is collected from window's table & added to accumulator
|
||||
* - since windows are different, same point inside tables won't be accessed more than once per calc
|
||||
* - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
|
||||
* - +1 window is neccessary for wNAF
|
||||
* - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
|
||||
*
|
||||
* @todo Research returning 2d JS array of windows, instead of a single window.
|
||||
* This would allow windows to be in different memory locations
|
||||
*/
|
||||
export class wNAF {
|
||||
// Parametrized with a given Point class (not individual point)
|
||||
constructor(Point, bits) {
|
||||
this.BASE = Point.BASE;
|
||||
this.ZERO = Point.ZERO;
|
||||
this.Fn = Point.Fn;
|
||||
this.bits = bits;
|
||||
}
|
||||
// non-const time multiplication ladder
|
||||
_unsafeLadder(elm, n, p = this.ZERO) {
|
||||
let d = elm;
|
||||
while (n > _0n) {
|
||||
if (n & _1n)
|
||||
p = p.add(d);
|
||||
d = d.double();
|
||||
n >>= _1n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
/**
|
||||
* Creates a wNAF precomputation window. Used for caching.
|
||||
* Default window size is set by `utils.precompute()` and is equal to 8.
|
||||
* Number of precomputed points depends on the curve size:
|
||||
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
||||
* - 𝑊 is the window size
|
||||
* - 𝑛 is the bitlength of the curve order.
|
||||
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
||||
* @param point Point instance
|
||||
* @param W window size
|
||||
* @returns precomputed point tables flattened to a single array
|
||||
*/
|
||||
precomputeWindow(point, W) {
|
||||
const { windows, windowSize } = calcWOpts(W, this.bits);
|
||||
const points = [];
|
||||
let p = point;
|
||||
let base = p;
|
||||
for (let window = 0; window < windows; window++) {
|
||||
base = p;
|
||||
points.push(base);
|
||||
// i=1, bc we skip 0
|
||||
for (let i = 1; i < windowSize; i++) {
|
||||
base = base.add(p);
|
||||
points.push(base);
|
||||
}
|
||||
p = base.double();
|
||||
}
|
||||
return points;
|
||||
}
|
||||
/**
|
||||
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
||||
* More compact implementation:
|
||||
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
|
||||
* @returns real and fake (for const-time) points
|
||||
*/
|
||||
wNAF(W, precomputes, n) {
|
||||
// Scalar should be smaller than field order
|
||||
if (!this.Fn.isValid(n))
|
||||
throw new Error('invalid scalar');
|
||||
// Accumulators
|
||||
let p = this.ZERO;
|
||||
let f = this.BASE;
|
||||
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
||||
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
||||
// there is negate now: it is possible that negated element from low value
|
||||
// would be the same as high element, which will create carry into next window.
|
||||
// It's not obvious how this can fail, but still worth investigating later.
|
||||
const wo = calcWOpts(W, this.bits);
|
||||
for (let window = 0; window < wo.windows; window++) {
|
||||
// (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
|
||||
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
||||
n = nextN;
|
||||
if (isZero) {
|
||||
// bits are 0: add garbage to fake point
|
||||
// Important part for const-time getPublicKey: add random "noise" point to f.
|
||||
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
||||
}
|
||||
else {
|
||||
// bits are 1: add to result point
|
||||
p = p.add(negateCt(isNeg, precomputes[offset]));
|
||||
}
|
||||
}
|
||||
assert0(n);
|
||||
// Return both real and fake points: JIT won't eliminate f.
|
||||
// At this point there is a way to F be infinity-point even if p is not,
|
||||
// which makes it less const-time: around 1 bigint multiply.
|
||||
return { p, f };
|
||||
}
|
||||
/**
|
||||
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
||||
* @param acc accumulator point to add result of multiplication
|
||||
* @returns point
|
||||
*/
|
||||
wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
|
||||
const wo = calcWOpts(W, this.bits);
|
||||
for (let window = 0; window < wo.windows; window++) {
|
||||
if (n === _0n)
|
||||
break; // Early-exit, skip 0 value
|
||||
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
||||
n = nextN;
|
||||
if (isZero) {
|
||||
// Window bits are 0: skip processing.
|
||||
// Move to next window.
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
const item = precomputes[offset];
|
||||
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
||||
}
|
||||
}
|
||||
assert0(n);
|
||||
return acc;
|
||||
}
|
||||
getPrecomputes(W, point, transform) {
|
||||
// Calculate precomputes on a first run, reuse them after
|
||||
let comp = pointPrecomputes.get(point);
|
||||
if (!comp) {
|
||||
comp = this.precomputeWindow(point, W);
|
||||
if (W !== 1) {
|
||||
// Doing transform outside of if brings 15% perf hit
|
||||
if (typeof transform === 'function')
|
||||
comp = transform(comp);
|
||||
pointPrecomputes.set(point, comp);
|
||||
}
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
cached(point, scalar, transform) {
|
||||
const W = getW(point);
|
||||
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
|
||||
}
|
||||
unsafe(point, scalar, transform, prev) {
|
||||
const W = getW(point);
|
||||
if (W === 1)
|
||||
return this._unsafeLadder(point, scalar, prev); // For W=1 ladder is ~x2 faster
|
||||
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
|
||||
}
|
||||
// We calculate precomputes for elliptic curve point multiplication
|
||||
// using windowed method. This specifies window size and
|
||||
// stores precomputed values. Usually only base point would be precomputed.
|
||||
createCache(P, W) {
|
||||
validateW(W, this.bits);
|
||||
pointWindowSizes.set(P, W);
|
||||
pointPrecomputes.delete(P);
|
||||
}
|
||||
hasCache(elm) {
|
||||
return getW(elm) !== 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Endomorphism-specific multiplication for Koblitz curves.
|
||||
* Cost: 128 dbl, 0-256 adds.
|
||||
*/
|
||||
export function mulEndoUnsafe(Point, point, k1, k2) {
|
||||
let acc = point;
|
||||
let p1 = Point.ZERO;
|
||||
let p2 = Point.ZERO;
|
||||
while (k1 > _0n || k2 > _0n) {
|
||||
if (k1 & _1n)
|
||||
p1 = p1.add(acc);
|
||||
if (k2 & _1n)
|
||||
p2 = p2.add(acc);
|
||||
acc = acc.double();
|
||||
k1 >>= _1n;
|
||||
k2 >>= _1n;
|
||||
}
|
||||
return { p1, p2 };
|
||||
}
|
||||
/**
|
||||
* Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
||||
* 30x faster vs naive addition on L=4096, 10x faster than precomputes.
|
||||
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
||||
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
||||
* @param c Curve Point constructor
|
||||
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
||||
* @param points array of L curve points
|
||||
* @param scalars array of L scalars (aka secret keys / bigints)
|
||||
*/
|
||||
export function pippenger(c, fieldN, points, scalars) {
|
||||
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
||||
// take 256 buckets even if there are 4096 scalars, also re-uses double.
|
||||
// TODO:
|
||||
// - https://eprint.iacr.org/2024/750.pdf
|
||||
// - https://tches.iacr.org/index.php/TCHES/article/view/10287
|
||||
// 0 is accepted in scalars
|
||||
validateMSMPoints(points, c);
|
||||
validateMSMScalars(scalars, fieldN);
|
||||
const plength = points.length;
|
||||
const slength = scalars.length;
|
||||
if (plength !== slength)
|
||||
throw new Error('arrays of points and scalars must have equal length');
|
||||
// if (plength === 0) throw new Error('array must be of length >= 2');
|
||||
const zero = c.ZERO;
|
||||
const wbits = bitLen(BigInt(plength));
|
||||
let windowSize = 1; // bits
|
||||
if (wbits > 12)
|
||||
windowSize = wbits - 3;
|
||||
else if (wbits > 4)
|
||||
windowSize = wbits - 2;
|
||||
else if (wbits > 0)
|
||||
windowSize = 2;
|
||||
const MASK = bitMask(windowSize);
|
||||
const buckets = new Array(Number(MASK) + 1).fill(zero); // +1 for zero array
|
||||
const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
|
||||
let sum = zero;
|
||||
for (let i = lastBits; i >= 0; i -= windowSize) {
|
||||
buckets.fill(zero);
|
||||
for (let j = 0; j < slength; j++) {
|
||||
const scalar = scalars[j];
|
||||
const wbits = Number((scalar >> BigInt(i)) & MASK);
|
||||
buckets[wbits] = buckets[wbits].add(points[j]);
|
||||
}
|
||||
let resI = zero; // not using this will do small speed-up, but will lose ct
|
||||
// Skip first bucket, because it is zero
|
||||
for (let j = buckets.length - 1, sumI = zero; j > 0; j--) {
|
||||
sumI = sumI.add(buckets[j]);
|
||||
resI = resI.add(sumI);
|
||||
}
|
||||
sum = sum.add(resI);
|
||||
if (i !== 0)
|
||||
for (let j = 0; j < windowSize; j++)
|
||||
sum = sum.double();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
/**
|
||||
* Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
||||
* @param c Curve Point constructor
|
||||
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
||||
* @param points array of L curve points
|
||||
* @returns function which multiplies points with scaars
|
||||
*/
|
||||
export function precomputeMSMUnsafe(c, fieldN, points, windowSize) {
|
||||
/**
|
||||
* Performance Analysis of Window-based Precomputation
|
||||
*
|
||||
* Base Case (256-bit scalar, 8-bit window):
|
||||
* - Standard precomputation requires:
|
||||
* - 31 additions per scalar × 256 scalars = 7,936 ops
|
||||
* - Plus 255 summary additions = 8,191 total ops
|
||||
* Note: Summary additions can be optimized via accumulator
|
||||
*
|
||||
* Chunked Precomputation Analysis:
|
||||
* - Using 32 chunks requires:
|
||||
* - 255 additions per chunk
|
||||
* - 256 doublings
|
||||
* - Total: (255 × 32) + 256 = 8,416 ops
|
||||
*
|
||||
* Memory Usage Comparison:
|
||||
* Window Size | Standard Points | Chunked Points
|
||||
* ------------|-----------------|---------------
|
||||
* 4-bit | 520 | 15
|
||||
* 8-bit | 4,224 | 255
|
||||
* 10-bit | 13,824 | 1,023
|
||||
* 16-bit | 557,056 | 65,535
|
||||
*
|
||||
* Key Advantages:
|
||||
* 1. Enables larger window sizes due to reduced memory overhead
|
||||
* 2. More efficient for smaller scalar counts:
|
||||
* - 16 chunks: (16 × 255) + 256 = 4,336 ops
|
||||
* - ~2x faster than standard 8,191 ops
|
||||
*
|
||||
* Limitations:
|
||||
* - Not suitable for plain precomputes (requires 256 constant doublings)
|
||||
* - Performance degrades with larger scalar counts:
|
||||
* - Optimal for ~256 scalars
|
||||
* - Less efficient for 4096+ scalars (Pippenger preferred)
|
||||
*/
|
||||
validateW(windowSize, fieldN.BITS);
|
||||
validateMSMPoints(points, c);
|
||||
const zero = c.ZERO;
|
||||
const tableSize = 2 ** windowSize - 1; // table size (without zero)
|
||||
const chunks = Math.ceil(fieldN.BITS / windowSize); // chunks of item
|
||||
const MASK = bitMask(windowSize);
|
||||
const tables = points.map((p) => {
|
||||
const res = [];
|
||||
for (let i = 0, acc = p; i < tableSize; i++) {
|
||||
res.push(acc);
|
||||
acc = acc.add(p);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
return (scalars) => {
|
||||
validateMSMScalars(scalars, fieldN);
|
||||
if (scalars.length > points.length)
|
||||
throw new Error('array of scalars must be smaller than array of points');
|
||||
let res = zero;
|
||||
for (let i = 0; i < chunks; i++) {
|
||||
// No need to double if accumulator is still zero.
|
||||
if (res !== zero)
|
||||
for (let j = 0; j < windowSize; j++)
|
||||
res = res.double();
|
||||
const shiftBy = BigInt(chunks * windowSize - (i + 1) * windowSize);
|
||||
for (let j = 0; j < scalars.length; j++) {
|
||||
const n = scalars[j];
|
||||
const curr = Number((n >> shiftBy) & MASK);
|
||||
if (!curr)
|
||||
continue; // skip zero scalars chunks
|
||||
res = res.add(tables[j][curr - 1]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
// TODO: remove
|
||||
/** @deprecated */
|
||||
export function validateBasic(curve) {
|
||||
validateField(curve.Fp);
|
||||
validateObject(curve, {
|
||||
n: 'bigint',
|
||||
h: 'bigint',
|
||||
Gx: 'field',
|
||||
Gy: 'field',
|
||||
}, {
|
||||
nBitLength: 'isSafeInteger',
|
||||
nByteLength: 'isSafeInteger',
|
||||
});
|
||||
// Set defaults
|
||||
return Object.freeze({
|
||||
...nLength(curve.n, curve.nBitLength),
|
||||
...curve,
|
||||
...{ p: curve.Fp.ORDER },
|
||||
});
|
||||
}
|
||||
function createField(order, field, isLE) {
|
||||
if (field) {
|
||||
if (field.ORDER !== order)
|
||||
throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
||||
validateField(field);
|
||||
return field;
|
||||
}
|
||||
else {
|
||||
return Field(order, { isLE });
|
||||
}
|
||||
}
|
||||
/** Validates CURVE opts and creates fields */
|
||||
export function _createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
|
||||
if (FpFnLE === undefined)
|
||||
FpFnLE = type === 'edwards';
|
||||
if (!CURVE || typeof CURVE !== 'object')
|
||||
throw new Error(`expected valid ${type} CURVE object`);
|
||||
for (const p of ['p', 'n', 'h']) {
|
||||
const val = CURVE[p];
|
||||
if (!(typeof val === 'bigint' && val > _0n))
|
||||
throw new Error(`CURVE.${p} must be positive bigint`);
|
||||
}
|
||||
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
|
||||
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
|
||||
const _b = type === 'weierstrass' ? 'b' : 'd';
|
||||
const params = ['Gx', 'Gy', 'a', _b];
|
||||
for (const p of params) {
|
||||
// @ts-ignore
|
||||
if (!Fp.isValid(CURVE[p]))
|
||||
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
||||
}
|
||||
CURVE = Object.freeze(Object.assign({}, CURVE));
|
||||
return { CURVE, Fp, Fn };
|
||||
}
|
||||
//# sourceMappingURL=curve.js.map
|
||||
@@ -0,0 +1,285 @@
|
||||
/// <reference path="./types/importMeta.d.ts" />
|
||||
|
||||
// virtual modules
|
||||
declare module 'vite/modulepreload-polyfill' {}
|
||||
|
||||
// CSS modules
|
||||
type CSSModuleClasses = { readonly [key: string]: string }
|
||||
|
||||
declare module '*.module.css' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.scss' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.sass' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.less' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.styl' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.stylus' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.pcss' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
declare module '*.module.sss' {
|
||||
const classes: CSSModuleClasses
|
||||
export default classes
|
||||
}
|
||||
|
||||
// CSS
|
||||
declare module '*.css' {}
|
||||
declare module '*.scss' {}
|
||||
declare module '*.sass' {}
|
||||
declare module '*.less' {}
|
||||
declare module '*.styl' {}
|
||||
declare module '*.stylus' {}
|
||||
declare module '*.pcss' {}
|
||||
declare module '*.sss' {}
|
||||
|
||||
// Built-in asset types
|
||||
// see `src/node/constants.ts`
|
||||
|
||||
// images
|
||||
declare module '*.apng' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.bmp' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.png' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.jpg' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.jpeg' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.jfif' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.pjpeg' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.pjp' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.gif' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.svg' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.ico' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.webp' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.avif' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.cur' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.jxl' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// media
|
||||
declare module '*.mp4' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.webm' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.ogg' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.mp3' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.wav' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.flac' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.aac' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.opus' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.mov' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.m4a' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.vtt' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// fonts
|
||||
declare module '*.woff' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.woff2' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.eot' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.ttf' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.otf' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// other
|
||||
declare module '*.webmanifest' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.pdf' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
declare module '*.txt' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// wasm?init
|
||||
declare module '*.wasm?init' {
|
||||
const initWasm: (
|
||||
options?: WebAssembly.Imports,
|
||||
) => Promise<WebAssembly.Instance>
|
||||
export default initWasm
|
||||
}
|
||||
|
||||
// wasm (ESM integration)
|
||||
declare module '*.wasm' {}
|
||||
|
||||
// web worker
|
||||
declare module '*?worker' {
|
||||
const workerConstructor: {
|
||||
new (options?: { name?: string }): Worker
|
||||
}
|
||||
export default workerConstructor
|
||||
}
|
||||
|
||||
declare module '*?worker&inline' {
|
||||
const workerConstructor: {
|
||||
new (options?: { name?: string }): Worker
|
||||
}
|
||||
export default workerConstructor
|
||||
}
|
||||
|
||||
declare module '*?worker&url' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?sharedworker' {
|
||||
const sharedWorkerConstructor: {
|
||||
new (options?: { name?: string }): SharedWorker
|
||||
}
|
||||
export default sharedWorkerConstructor
|
||||
}
|
||||
|
||||
declare module '*?sharedworker&inline' {
|
||||
const sharedWorkerConstructor: {
|
||||
new (options?: { name?: string }): SharedWorker
|
||||
}
|
||||
export default sharedWorkerConstructor
|
||||
}
|
||||
|
||||
declare module '*?sharedworker&url' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?raw' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?url' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?inline' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?no-inline' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?url&inline' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?url&no-inline' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare interface VitePreloadErrorEvent extends Event {
|
||||
payload: Error
|
||||
}
|
||||
|
||||
declare interface WindowEventMap {
|
||||
'vite:preloadError': VitePreloadErrorEvent
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
/// <reference lib="es2020" />
|
||||
/// <reference lib="es2021.promise" />
|
||||
/// <reference lib="es2021.string" />
|
||||
/// <reference lib="es2021.weakref" />
|
||||
/// <reference lib="es2021.intl" />
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAI9B,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,SAAS,GACT,QAAQ,GACR,SAAS,GACT,OAAO,GACP,OAAO,GACP,SAAS,GACT,OAAO,GACP,OAAO,GACP,QAAQ,GACR,QAAQ,CAAA;AAEZ,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qEAAqE;IACrE,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,kEAAkE;IAClE,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,qDAAqD;IACrD,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,eAAO,MAAM,SAAS;QACjB,MAAM,WACA,MAAM,YACN,gBAAgB;;;sBA4Gf,MAAM,YAAW,gBAAgB,MAC1C,GAAG,MAAM;oBAOkB,gBAAgB,KAAG,OAAO,SAAS;2BAuFtD,MAAM,YACN,gBAAgB;sBA2BK,MAAM,YAAW,gBAAgB;kBAKzD,MAAM,EAAE,WACL,MAAM,YACN,gBAAgB;;;;;CApO1B,CAAA;AAkED,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,CAAA;AAQ5B,eAAO,MAAM,GAAG,KAC+C,CAAA;AAG/D,eAAO,MAAM,QAAQ,eAAwB,CAAA;AAmB7C,eAAO,MAAM,MAAM,GAChB,SAAS,MAAM,EAAE,UAAS,gBAAqB,MAC/C,GAAG,MAAM,YACsB,CAAA;AAMlC,eAAO,MAAM,QAAQ,GAAI,KAAK,gBAAgB,KAAG,OAAO,SAyEvD,CAAA;AAaD,eAAO,MAAM,WAAW,GACtB,SAAS,MAAM,EACf,UAAS,gBAAqB,aAY/B,CAAA;AAeD,eAAO,MAAM,MAAM,GAAI,SAAS,MAAM,EAAE,UAAS,gBAAqB,qBAC5B,CAAA;AAG1C,eAAO,MAAM,KAAK,GAChB,MAAM,MAAM,EAAE,EACd,SAAS,MAAM,EACf,UAAS,gBAAqB,aAQ/B,CAAA;AAQD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,QAAQ,CAAA;AACrE,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,KAAK,CAAA;AAErD,qBAAa,SAAS;;IACpB,OAAO,EAAE,gBAAgB,CAAA;IACzB,GAAG,EAAE,mBAAmB,EAAE,EAAE,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IAEf,oBAAoB,EAAE,OAAO,CAAA;IAC7B,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,uBAAuB,EAAE,OAAO,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,SAAS,EAAE,MAAM,EAAE,EAAE,CAAA;IACrB,MAAM,EAAE,OAAO,CAAA;IAEf,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,QAAQ,CAAA;IAClB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAE5B,MAAM,EAAE,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAA;gBACnB,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAqC3D,QAAQ,IAAI,OAAO;IAYnB,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE;IAErB,IAAI;IA8FJ,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE;IA8BhC,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE;IAiB/C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE;IAoBtC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAoE7C,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE;IA0F1C,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE;IAkBxD,UAAU,CACR,CAAC,EAAE,MAAM,EAAE,EACX,CAAC,EAAE,MAAM,EAAE,EACX,YAAY,GAAE,OAAe,GAC5B,KAAK,GAAG,MAAM,EAAE;IA+CnB,WAAW;IAqBX,QAAQ,CACN,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,GAAE,OAAe;IAiX1B,WAAW;IAIX,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IA6CnC,MAAM;IAuGN,UAAU,CAAC,CAAC,EAAE,MAAM;IAepB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,UAAe;IAgEvC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,gBAAgB;CAGtC;AAED,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
|
||||
@@ -0,0 +1,585 @@
|
||||
import buffers from './testing/test-buffers'
|
||||
import BufferList from './testing/buffer-list'
|
||||
import { parse } from '.'
|
||||
import assert from 'assert'
|
||||
import { PassThrough } from 'stream'
|
||||
import { BackendMessage } from './messages'
|
||||
import { Parser } from './parser'
|
||||
|
||||
const authOkBuffer = buffers.authenticationOk()
|
||||
const paramStatusBuffer = buffers.parameterStatus('client_encoding', 'UTF8')
|
||||
const readyForQueryBuffer = buffers.readyForQuery()
|
||||
const backendKeyDataBuffer = buffers.backendKeyData(1, 2)
|
||||
const commandCompleteBuffer = buffers.commandComplete('SELECT 3')
|
||||
const parseCompleteBuffer = buffers.parseComplete()
|
||||
const bindCompleteBuffer = buffers.bindComplete()
|
||||
const portalSuspendedBuffer = buffers.portalSuspended()
|
||||
|
||||
const row1 = {
|
||||
name: 'id',
|
||||
tableID: 1,
|
||||
attributeNumber: 2,
|
||||
dataTypeID: 3,
|
||||
dataTypeSize: 4,
|
||||
typeModifier: 5,
|
||||
formatCode: 0,
|
||||
}
|
||||
const oneRowDescBuff = buffers.rowDescription([row1])
|
||||
row1.name = 'bang'
|
||||
|
||||
const twoRowBuf = buffers.rowDescription([
|
||||
row1,
|
||||
{
|
||||
name: 'whoah',
|
||||
tableID: 10,
|
||||
attributeNumber: 11,
|
||||
dataTypeID: 12,
|
||||
dataTypeSize: 13,
|
||||
typeModifier: 14,
|
||||
formatCode: 0,
|
||||
},
|
||||
])
|
||||
|
||||
const rowWithBigOids = {
|
||||
name: 'bigoid',
|
||||
tableID: 3000000001,
|
||||
attributeNumber: 2,
|
||||
dataTypeID: 3000000003,
|
||||
dataTypeSize: 4,
|
||||
typeModifier: 5,
|
||||
formatCode: 0,
|
||||
}
|
||||
const bigOidDescBuff = buffers.rowDescription([rowWithBigOids])
|
||||
|
||||
const emptyRowFieldBuf = buffers.dataRow([])
|
||||
|
||||
const oneFieldBuf = buffers.dataRow(['test'])
|
||||
|
||||
const expectedAuthenticationOkayMessage = {
|
||||
name: 'authenticationOk',
|
||||
length: 8,
|
||||
}
|
||||
|
||||
const expectedParameterStatusMessage = {
|
||||
name: 'parameterStatus',
|
||||
parameterName: 'client_encoding',
|
||||
parameterValue: 'UTF8',
|
||||
length: 25,
|
||||
}
|
||||
|
||||
const expectedBackendKeyDataMessage = {
|
||||
name: 'backendKeyData',
|
||||
processID: 1,
|
||||
secretKey: 2,
|
||||
}
|
||||
|
||||
const expectedReadyForQueryMessage = {
|
||||
name: 'readyForQuery',
|
||||
length: 5,
|
||||
status: 'I',
|
||||
}
|
||||
|
||||
const expectedCommandCompleteMessage = {
|
||||
name: 'commandComplete',
|
||||
length: 13,
|
||||
text: 'SELECT 3',
|
||||
}
|
||||
const emptyRowDescriptionBuffer = new BufferList()
|
||||
.addInt16(0) // number of fields
|
||||
.join(true, 'T')
|
||||
|
||||
const expectedEmptyRowDescriptionMessage = {
|
||||
name: 'rowDescription',
|
||||
length: 6,
|
||||
fieldCount: 0,
|
||||
fields: [],
|
||||
}
|
||||
const expectedOneRowMessage = {
|
||||
name: 'rowDescription',
|
||||
length: 27,
|
||||
fieldCount: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'id',
|
||||
tableID: 1,
|
||||
columnID: 2,
|
||||
dataTypeID: 3,
|
||||
dataTypeSize: 4,
|
||||
dataTypeModifier: 5,
|
||||
format: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const expectedTwoRowMessage = {
|
||||
name: 'rowDescription',
|
||||
length: 53,
|
||||
fieldCount: 2,
|
||||
fields: [
|
||||
{
|
||||
name: 'bang',
|
||||
tableID: 1,
|
||||
columnID: 2,
|
||||
dataTypeID: 3,
|
||||
dataTypeSize: 4,
|
||||
dataTypeModifier: 5,
|
||||
format: 'text',
|
||||
},
|
||||
{
|
||||
name: 'whoah',
|
||||
tableID: 10,
|
||||
columnID: 11,
|
||||
dataTypeID: 12,
|
||||
dataTypeSize: 13,
|
||||
dataTypeModifier: 14,
|
||||
format: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
const expectedBigOidMessage = {
|
||||
name: 'rowDescription',
|
||||
length: 31,
|
||||
fieldCount: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'bigoid',
|
||||
tableID: 3000000001,
|
||||
columnID: 2,
|
||||
dataTypeID: 3000000003,
|
||||
dataTypeSize: 4,
|
||||
dataTypeModifier: 5,
|
||||
format: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const emptyParameterDescriptionBuffer = new BufferList()
|
||||
.addInt16(0) // number of parameters
|
||||
.join(true, 't')
|
||||
|
||||
const oneParameterDescBuf = buffers.parameterDescription([1111])
|
||||
|
||||
const twoParameterDescBuf = buffers.parameterDescription([2222, 3333])
|
||||
|
||||
const bigOidParameterDescBuf = buffers.parameterDescription([3000000003])
|
||||
|
||||
const expectedEmptyParameterDescriptionMessage = {
|
||||
name: 'parameterDescription',
|
||||
length: 6,
|
||||
parameterCount: 0,
|
||||
dataTypeIDs: [],
|
||||
}
|
||||
|
||||
const expectedOneParameterMessage = {
|
||||
name: 'parameterDescription',
|
||||
length: 10,
|
||||
parameterCount: 1,
|
||||
dataTypeIDs: [1111],
|
||||
}
|
||||
|
||||
const expectedTwoParameterMessage = {
|
||||
name: 'parameterDescription',
|
||||
length: 14,
|
||||
parameterCount: 2,
|
||||
dataTypeIDs: [2222, 3333],
|
||||
}
|
||||
|
||||
const expectedBigOidParameterMessage = {
|
||||
name: 'parameterDescription',
|
||||
length: 10,
|
||||
parameterCount: 1,
|
||||
dataTypeIDs: [3000000003],
|
||||
}
|
||||
|
||||
const testForMessage = function (buffer: Buffer, expectedMessage: any) {
|
||||
it('receives and parses ' + expectedMessage.name, async () => {
|
||||
const messages = await parseBuffers([buffer])
|
||||
const [lastMessage] = messages
|
||||
|
||||
for (const key in expectedMessage) {
|
||||
assert.deepEqual((lastMessage as any)[key], expectedMessage[key])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const plainPasswordBuffer = buffers.authenticationCleartextPassword()
|
||||
const md5PasswordBuffer = buffers.authenticationMD5Password()
|
||||
const SASLBuffer = buffers.authenticationSASL()
|
||||
const SASLContinueBuffer = buffers.authenticationSASLContinue()
|
||||
const SASLFinalBuffer = buffers.authenticationSASLFinal()
|
||||
|
||||
const expectedPlainPasswordMessage = {
|
||||
name: 'authenticationCleartextPassword',
|
||||
}
|
||||
|
||||
const expectedMD5PasswordMessage = {
|
||||
name: 'authenticationMD5Password',
|
||||
salt: Buffer.from([1, 2, 3, 4]),
|
||||
}
|
||||
|
||||
const expectedSASLMessage = {
|
||||
name: 'authenticationSASL',
|
||||
mechanisms: ['SCRAM-SHA-256'],
|
||||
}
|
||||
|
||||
const expectedSASLContinueMessage = {
|
||||
name: 'authenticationSASLContinue',
|
||||
data: 'data',
|
||||
}
|
||||
|
||||
const expectedSASLFinalMessage = {
|
||||
name: 'authenticationSASLFinal',
|
||||
data: 'data',
|
||||
}
|
||||
|
||||
const notificationResponseBuffer = buffers.notification(4, 'hi', 'boom')
|
||||
const expectedNotificationResponseMessage = {
|
||||
name: 'notification',
|
||||
processId: 4,
|
||||
channel: 'hi',
|
||||
payload: 'boom',
|
||||
}
|
||||
|
||||
const parseBuffers = async (buffers: Buffer[]): Promise<BackendMessage[]> => {
|
||||
const stream = new PassThrough()
|
||||
for (const buffer of buffers) {
|
||||
stream.write(buffer)
|
||||
}
|
||||
stream.end()
|
||||
const msgs: BackendMessage[] = []
|
||||
await parse(stream, (msg) => msgs.push(msg))
|
||||
return msgs
|
||||
}
|
||||
|
||||
describe('PgPacketStream', function () {
|
||||
testForMessage(authOkBuffer, expectedAuthenticationOkayMessage)
|
||||
testForMessage(plainPasswordBuffer, expectedPlainPasswordMessage)
|
||||
testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage)
|
||||
testForMessage(SASLBuffer, expectedSASLMessage)
|
||||
testForMessage(SASLContinueBuffer, expectedSASLContinueMessage)
|
||||
|
||||
// this exercises a found bug in the parser:
|
||||
// https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084
|
||||
// and adds a test which is deterministic, rather than relying on network packet chunking
|
||||
const extendedSASLContinueBuffer = Buffer.concat([SASLContinueBuffer, Buffer.from([1, 2, 3, 4])])
|
||||
testForMessage(extendedSASLContinueBuffer, expectedSASLContinueMessage)
|
||||
|
||||
testForMessage(SASLFinalBuffer, expectedSASLFinalMessage)
|
||||
|
||||
// this exercises a found bug in the parser:
|
||||
// https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084
|
||||
// and adds a test which is deterministic, rather than relying on network packet chunking
|
||||
const extendedSASLFinalBuffer = Buffer.concat([SASLFinalBuffer, Buffer.from([1, 2, 4, 5])])
|
||||
testForMessage(extendedSASLFinalBuffer, expectedSASLFinalMessage)
|
||||
|
||||
testForMessage(paramStatusBuffer, expectedParameterStatusMessage)
|
||||
testForMessage(backendKeyDataBuffer, expectedBackendKeyDataMessage)
|
||||
testForMessage(readyForQueryBuffer, expectedReadyForQueryMessage)
|
||||
testForMessage(commandCompleteBuffer, expectedCommandCompleteMessage)
|
||||
testForMessage(notificationResponseBuffer, expectedNotificationResponseMessage)
|
||||
testForMessage(buffers.emptyQuery(), {
|
||||
name: 'emptyQuery',
|
||||
length: 4,
|
||||
})
|
||||
|
||||
testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), {
|
||||
name: 'noData',
|
||||
})
|
||||
|
||||
describe('rowDescription messages', function () {
|
||||
testForMessage(emptyRowDescriptionBuffer, expectedEmptyRowDescriptionMessage)
|
||||
testForMessage(oneRowDescBuff, expectedOneRowMessage)
|
||||
testForMessage(twoRowBuf, expectedTwoRowMessage)
|
||||
testForMessage(bigOidDescBuff, expectedBigOidMessage)
|
||||
})
|
||||
|
||||
describe('parameterDescription messages', function () {
|
||||
testForMessage(emptyParameterDescriptionBuffer, expectedEmptyParameterDescriptionMessage)
|
||||
testForMessage(oneParameterDescBuf, expectedOneParameterMessage)
|
||||
testForMessage(twoParameterDescBuf, expectedTwoParameterMessage)
|
||||
testForMessage(bigOidParameterDescBuf, expectedBigOidParameterMessage)
|
||||
})
|
||||
|
||||
describe('parsing rows', function () {
|
||||
describe('parsing empty row', function () {
|
||||
testForMessage(emptyRowFieldBuf, {
|
||||
name: 'dataRow',
|
||||
fieldCount: 0,
|
||||
})
|
||||
})
|
||||
|
||||
describe('parsing data row with fields', function () {
|
||||
testForMessage(oneFieldBuf, {
|
||||
name: 'dataRow',
|
||||
fieldCount: 1,
|
||||
fields: ['test'],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('notice message', function () {
|
||||
// this uses the same logic as error message
|
||||
const buff = buffers.notice([{ type: 'C', value: 'code' }])
|
||||
testForMessage(buff, {
|
||||
name: 'notice',
|
||||
code: 'code',
|
||||
})
|
||||
})
|
||||
|
||||
testForMessage(buffers.error([]), {
|
||||
name: 'error',
|
||||
})
|
||||
|
||||
describe('with all the fields', function () {
|
||||
const buffer = buffers.error([
|
||||
{
|
||||
type: 'S',
|
||||
value: 'ERROR',
|
||||
},
|
||||
{
|
||||
type: 'C',
|
||||
value: 'code',
|
||||
},
|
||||
{
|
||||
type: 'M',
|
||||
value: 'message',
|
||||
},
|
||||
{
|
||||
type: 'D',
|
||||
value: 'details',
|
||||
},
|
||||
{
|
||||
type: 'H',
|
||||
value: 'hint',
|
||||
},
|
||||
{
|
||||
type: 'P',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
type: 'p',
|
||||
value: '101',
|
||||
},
|
||||
{
|
||||
type: 'q',
|
||||
value: 'query',
|
||||
},
|
||||
{
|
||||
type: 'W',
|
||||
value: 'where',
|
||||
},
|
||||
{
|
||||
type: 'F',
|
||||
value: 'file',
|
||||
},
|
||||
{
|
||||
type: 'L',
|
||||
value: 'line',
|
||||
},
|
||||
{
|
||||
type: 'R',
|
||||
value: 'routine',
|
||||
},
|
||||
{
|
||||
type: 'Z', // ignored
|
||||
value: 'alsdkf',
|
||||
},
|
||||
])
|
||||
|
||||
testForMessage(buffer, {
|
||||
name: 'error',
|
||||
severity: 'ERROR',
|
||||
code: 'code',
|
||||
message: 'message',
|
||||
detail: 'details',
|
||||
hint: 'hint',
|
||||
position: '100',
|
||||
internalPosition: '101',
|
||||
internalQuery: 'query',
|
||||
where: 'where',
|
||||
file: 'file',
|
||||
line: 'line',
|
||||
routine: 'routine',
|
||||
})
|
||||
})
|
||||
|
||||
testForMessage(parseCompleteBuffer, {
|
||||
name: 'parseComplete',
|
||||
})
|
||||
|
||||
testForMessage(bindCompleteBuffer, {
|
||||
name: 'bindComplete',
|
||||
})
|
||||
|
||||
testForMessage(bindCompleteBuffer, {
|
||||
name: 'bindComplete',
|
||||
})
|
||||
|
||||
testForMessage(buffers.closeComplete(), {
|
||||
name: 'closeComplete',
|
||||
})
|
||||
|
||||
describe('parses portal suspended message', function () {
|
||||
testForMessage(portalSuspendedBuffer, {
|
||||
name: 'portalSuspended',
|
||||
})
|
||||
})
|
||||
|
||||
describe('parses replication start message', function () {
|
||||
testForMessage(Buffer.from([0x57, 0x00, 0x00, 0x00, 0x04]), {
|
||||
name: 'replicationStart',
|
||||
length: 4,
|
||||
})
|
||||
})
|
||||
|
||||
describe('copy', () => {
|
||||
testForMessage(buffers.copyIn(0), {
|
||||
name: 'copyInResponse',
|
||||
length: 7,
|
||||
binary: false,
|
||||
columnTypes: [],
|
||||
})
|
||||
|
||||
testForMessage(buffers.copyIn(2), {
|
||||
name: 'copyInResponse',
|
||||
length: 11,
|
||||
binary: false,
|
||||
columnTypes: [0, 1],
|
||||
})
|
||||
|
||||
testForMessage(buffers.copyOut(0), {
|
||||
name: 'copyOutResponse',
|
||||
length: 7,
|
||||
binary: false,
|
||||
columnTypes: [],
|
||||
})
|
||||
|
||||
testForMessage(buffers.copyOut(3), {
|
||||
name: 'copyOutResponse',
|
||||
length: 13,
|
||||
binary: false,
|
||||
columnTypes: [0, 1, 2],
|
||||
})
|
||||
|
||||
testForMessage(buffers.copyDone(), {
|
||||
name: 'copyDone',
|
||||
length: 4,
|
||||
})
|
||||
|
||||
testForMessage(buffers.copyData(Buffer.from([5, 6, 7])), {
|
||||
name: 'copyData',
|
||||
length: 7,
|
||||
chunk: Buffer.from([5, 6, 7]),
|
||||
})
|
||||
})
|
||||
|
||||
// since the data message on a stream can randomly divide the incomming
|
||||
// tcp packets anywhere, we need to make sure we can parse every single
|
||||
// split on a tcp message
|
||||
describe('split buffer, single message parsing', function () {
|
||||
const fullBuffer = buffers.dataRow([null, 'bang', 'zug zug', null, '!'])
|
||||
|
||||
it('parses when full buffer comes in', async function () {
|
||||
const messages = await parseBuffers([fullBuffer])
|
||||
const message = messages[0] as any
|
||||
assert.equal(message.fields.length, 5)
|
||||
assert.equal(message.fields[0], null)
|
||||
assert.equal(message.fields[1], 'bang')
|
||||
assert.equal(message.fields[2], 'zug zug')
|
||||
assert.equal(message.fields[3], null)
|
||||
assert.equal(message.fields[4], '!')
|
||||
})
|
||||
|
||||
const testMessageReceivedAfterSplitAt = async function (split: number) {
|
||||
const firstBuffer = Buffer.alloc(fullBuffer.length - split)
|
||||
const secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length)
|
||||
fullBuffer.copy(firstBuffer, 0, 0)
|
||||
fullBuffer.copy(secondBuffer, 0, firstBuffer.length)
|
||||
const messages = await parseBuffers([firstBuffer, secondBuffer])
|
||||
const message = messages[0] as any
|
||||
assert.equal(message.fields.length, 5)
|
||||
assert.equal(message.fields[0], null)
|
||||
assert.equal(message.fields[1], 'bang')
|
||||
assert.equal(message.fields[2], 'zug zug')
|
||||
assert.equal(message.fields[3], null)
|
||||
assert.equal(message.fields[4], '!')
|
||||
}
|
||||
|
||||
it('parses when split in the middle', function () {
|
||||
return testMessageReceivedAfterSplitAt(6)
|
||||
})
|
||||
|
||||
it('parses when split at end', function () {
|
||||
return testMessageReceivedAfterSplitAt(2)
|
||||
})
|
||||
|
||||
it('parses when split at beginning', function () {
|
||||
return Promise.all([
|
||||
testMessageReceivedAfterSplitAt(fullBuffer.length - 2),
|
||||
testMessageReceivedAfterSplitAt(fullBuffer.length - 1),
|
||||
testMessageReceivedAfterSplitAt(fullBuffer.length - 5),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('split buffer, multiple message parsing', function () {
|
||||
const dataRowBuffer = buffers.dataRow(['!'])
|
||||
const readyForQueryBuffer = buffers.readyForQuery()
|
||||
const fullBuffer = Buffer.alloc(dataRowBuffer.length + readyForQueryBuffer.length)
|
||||
dataRowBuffer.copy(fullBuffer, 0, 0)
|
||||
readyForQueryBuffer.copy(fullBuffer, dataRowBuffer.length, 0)
|
||||
|
||||
const verifyMessages = function (messages: any[]) {
|
||||
assert.strictEqual(messages.length, 2)
|
||||
assert.deepEqual(messages[0], {
|
||||
name: 'dataRow',
|
||||
fieldCount: 1,
|
||||
length: 11,
|
||||
fields: ['!'],
|
||||
})
|
||||
assert.equal(messages[0].fields[0], '!')
|
||||
assert.deepEqual(messages[1], {
|
||||
name: 'readyForQuery',
|
||||
length: 5,
|
||||
status: 'I',
|
||||
})
|
||||
}
|
||||
// sanity check
|
||||
it('receives both messages when packet is not split', async function () {
|
||||
const messages = await parseBuffers([fullBuffer])
|
||||
verifyMessages(messages)
|
||||
})
|
||||
|
||||
const splitAndVerifyTwoMessages = async function (split: number) {
|
||||
const firstBuffer = Buffer.alloc(fullBuffer.length - split)
|
||||
const secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length)
|
||||
fullBuffer.copy(firstBuffer, 0, 0)
|
||||
fullBuffer.copy(secondBuffer, 0, firstBuffer.length)
|
||||
const messages = await parseBuffers([firstBuffer, secondBuffer])
|
||||
verifyMessages(messages)
|
||||
}
|
||||
|
||||
describe('receives both messages when packet is split', function () {
|
||||
it('in the middle', function () {
|
||||
return splitAndVerifyTwoMessages(11)
|
||||
})
|
||||
it('at the front', function () {
|
||||
return Promise.all([
|
||||
splitAndVerifyTwoMessages(fullBuffer.length - 1),
|
||||
splitAndVerifyTwoMessages(fullBuffer.length - 4),
|
||||
splitAndVerifyTwoMessages(fullBuffer.length - 6),
|
||||
])
|
||||
})
|
||||
|
||||
it('at the end', function () {
|
||||
return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('cleans up the reader after handling a packet', function () {
|
||||
const parser = new Parser()
|
||||
parser.parse(oneFieldBuf, () => {})
|
||||
assert.strictEqual((parser as any).reader.buffer.byteLength, 0)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,481 @@
|
||||
# debug
|
||||
[](#backers)
|
||||
[](#sponsors)
|
||||
|
||||
<img width="647" src="https://user-images.githubusercontent.com/71256/29091486-fa38524c-7c37-11e7-895f-e7ec8e1039b6.png">
|
||||
|
||||
A tiny JavaScript debugging utility modelled after Node.js core's debugging
|
||||
technique. Works in Node.js and web browsers.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install debug
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
`debug` exposes a function; simply pass this function the name of your module, and it will return a decorated version of `console.error` for you to pass debug statements to. This will allow you to toggle the debug output for different parts of your module as well as the module as a whole.
|
||||
|
||||
Example [_app.js_](./examples/node/app.js):
|
||||
|
||||
```js
|
||||
var debug = require('debug')('http')
|
||||
, http = require('http')
|
||||
, name = 'My App';
|
||||
|
||||
// fake app
|
||||
|
||||
debug('booting %o', name);
|
||||
|
||||
http.createServer(function(req, res){
|
||||
debug(req.method + ' ' + req.url);
|
||||
res.end('hello\n');
|
||||
}).listen(3000, function(){
|
||||
debug('listening');
|
||||
});
|
||||
|
||||
// fake worker of some kind
|
||||
|
||||
require('./worker');
|
||||
```
|
||||
|
||||
Example [_worker.js_](./examples/node/worker.js):
|
||||
|
||||
```js
|
||||
var a = require('debug')('worker:a')
|
||||
, b = require('debug')('worker:b');
|
||||
|
||||
function work() {
|
||||
a('doing lots of uninteresting work');
|
||||
setTimeout(work, Math.random() * 1000);
|
||||
}
|
||||
|
||||
work();
|
||||
|
||||
function workb() {
|
||||
b('doing some work');
|
||||
setTimeout(workb, Math.random() * 2000);
|
||||
}
|
||||
|
||||
workb();
|
||||
```
|
||||
|
||||
The `DEBUG` environment variable is then used to enable these based on space or
|
||||
comma-delimited names.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
<img width="647" alt="screen shot 2017-08-08 at 12 53 04 pm" src="https://user-images.githubusercontent.com/71256/29091703-a6302cdc-7c38-11e7-8304-7c0b3bc600cd.png">
|
||||
<img width="647" alt="screen shot 2017-08-08 at 12 53 38 pm" src="https://user-images.githubusercontent.com/71256/29091700-a62a6888-7c38-11e7-800b-db911291ca2b.png">
|
||||
<img width="647" alt="screen shot 2017-08-08 at 12 53 25 pm" src="https://user-images.githubusercontent.com/71256/29091701-a62ea114-7c38-11e7-826a-2692bedca740.png">
|
||||
|
||||
#### Windows command prompt notes
|
||||
|
||||
##### CMD
|
||||
|
||||
On Windows the environment variable is set using the `set` command.
|
||||
|
||||
```cmd
|
||||
set DEBUG=*,-not_this
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```cmd
|
||||
set DEBUG=* & node app.js
|
||||
```
|
||||
|
||||
##### PowerShell (VS Code default)
|
||||
|
||||
PowerShell uses different syntax to set environment variables.
|
||||
|
||||
```cmd
|
||||
$env:DEBUG = "*,-not_this"
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```cmd
|
||||
$env:DEBUG='app';node app.js
|
||||
```
|
||||
|
||||
Then, run the program to be debugged as usual.
|
||||
|
||||
npm script example:
|
||||
```js
|
||||
"windowsDebug": "@powershell -Command $env:DEBUG='*';node app.js",
|
||||
```
|
||||
|
||||
## Namespace Colors
|
||||
|
||||
Every debug instance has a color generated for it based on its namespace name.
|
||||
This helps when visually parsing the debug output to identify which debug instance
|
||||
a debug line belongs to.
|
||||
|
||||
#### Node.js
|
||||
|
||||
In Node.js, colors are enabled when stderr is a TTY. You also _should_ install
|
||||
the [`supports-color`](https://npmjs.org/supports-color) module alongside debug,
|
||||
otherwise debug will only use a small handful of basic colors.
|
||||
|
||||
<img width="521" src="https://user-images.githubusercontent.com/71256/29092181-47f6a9e6-7c3a-11e7-9a14-1928d8a711cd.png">
|
||||
|
||||
#### Web Browser
|
||||
|
||||
Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
|
||||
option. These are WebKit web inspectors, Firefox ([since version
|
||||
31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
|
||||
and the Firebug plugin for Firefox (any version).
|
||||
|
||||
<img width="524" src="https://user-images.githubusercontent.com/71256/29092033-b65f9f2e-7c39-11e7-8e32-f6f0d8e865c1.png">
|
||||
|
||||
|
||||
## Millisecond diff
|
||||
|
||||
When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
|
||||
|
||||
<img width="647" src="https://user-images.githubusercontent.com/71256/29091486-fa38524c-7c37-11e7-895f-e7ec8e1039b6.png">
|
||||
|
||||
When stdout is not a TTY, `Date#toISOString()` is used, making it more useful for logging the debug information as shown below:
|
||||
|
||||
<img width="647" src="https://user-images.githubusercontent.com/71256/29091956-6bd78372-7c39-11e7-8c55-c948396d6edd.png">
|
||||
|
||||
|
||||
## Conventions
|
||||
|
||||
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". If you append a "*" to the end of your name, it will always be enabled regardless of the setting of the DEBUG environment variable. You can then use it for normal output as well as debug output.
|
||||
|
||||
## Wildcards
|
||||
|
||||
The `*` character may be used as a wildcard. Suppose for example your library has
|
||||
debuggers named "connect:bodyParser", "connect:compress", "connect:session",
|
||||
instead of listing all three with
|
||||
`DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do
|
||||
`DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
|
||||
|
||||
You can also exclude specific debuggers by prefixing them with a "-" character.
|
||||
For example, `DEBUG=*,-connect:*` would include all debuggers except those
|
||||
starting with "connect:".
|
||||
|
||||
## Environment Variables
|
||||
|
||||
When running through Node.js, you can set a few environment variables that will
|
||||
change the behavior of the debug logging:
|
||||
|
||||
| Name | Purpose |
|
||||
|-----------|-------------------------------------------------|
|
||||
| `DEBUG` | Enables/disables specific debugging namespaces. |
|
||||
| `DEBUG_HIDE_DATE` | Hide date from debug output (non-TTY). |
|
||||
| `DEBUG_COLORS`| Whether or not to use colors in the debug output. |
|
||||
| `DEBUG_DEPTH` | Object inspection depth. |
|
||||
| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. |
|
||||
|
||||
|
||||
__Note:__ The environment variables beginning with `DEBUG_` end up being
|
||||
converted into an Options object that gets used with `%o`/`%O` formatters.
|
||||
See the Node.js documentation for
|
||||
[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
|
||||
for the complete list.
|
||||
|
||||
## Formatters
|
||||
|
||||
Debug uses [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting.
|
||||
Below are the officially supported formatters:
|
||||
|
||||
| Formatter | Representation |
|
||||
|-----------|----------------|
|
||||
| `%O` | Pretty-print an Object on multiple lines. |
|
||||
| `%o` | Pretty-print an Object all on a single line. |
|
||||
| `%s` | String. |
|
||||
| `%d` | Number (both integer and float). |
|
||||
| `%j` | JSON. Replaced with the string '[Circular]' if the argument contains circular references. |
|
||||
| `%%` | Single percent sign ('%'). This does not consume an argument. |
|
||||
|
||||
|
||||
### Custom formatters
|
||||
|
||||
You can add custom formatters by extending the `debug.formatters` object.
|
||||
For example, if you wanted to add support for rendering a Buffer as hex with
|
||||
`%h`, you could do something like:
|
||||
|
||||
```js
|
||||
const createDebug = require('debug')
|
||||
createDebug.formatters.h = (v) => {
|
||||
return v.toString('hex')
|
||||
}
|
||||
|
||||
// …elsewhere
|
||||
const debug = createDebug('foo')
|
||||
debug('this is hex: %h', new Buffer('hello world'))
|
||||
// foo this is hex: 68656c6c6f20776f726c6421 +0ms
|
||||
```
|
||||
|
||||
|
||||
## Browser Support
|
||||
|
||||
You can build a browser-ready script using [browserify](https://github.com/substack/node-browserify),
|
||||
or just use the [browserify-as-a-service](https://wzrd.in/) [build](https://wzrd.in/standalone/debug@latest),
|
||||
if you don't want to build it yourself.
|
||||
|
||||
Debug's enable state is currently persisted by `localStorage`.
|
||||
Consider the situation shown below where you have `worker:a` and `worker:b`,
|
||||
and wish to debug both. You can enable this using `localStorage.debug`:
|
||||
|
||||
```js
|
||||
localStorage.debug = 'worker:*'
|
||||
```
|
||||
|
||||
And then refresh the page.
|
||||
|
||||
```js
|
||||
a = debug('worker:a');
|
||||
b = debug('worker:b');
|
||||
|
||||
setInterval(function(){
|
||||
a('doing some work');
|
||||
}, 1000);
|
||||
|
||||
setInterval(function(){
|
||||
b('doing some work');
|
||||
}, 1200);
|
||||
```
|
||||
|
||||
In Chromium-based web browsers (e.g. Brave, Chrome, and Electron), the JavaScript console will—by default—only show messages logged by `debug` if the "Verbose" log level is _enabled_.
|
||||
|
||||
<img width="647" src="https://user-images.githubusercontent.com/7143133/152083257-29034707-c42c-4959-8add-3cee850e6fcf.png">
|
||||
|
||||
## Output streams
|
||||
|
||||
By default `debug` will log to stderr, however this can be configured per-namespace by overriding the `log` method:
|
||||
|
||||
Example [_stdout.js_](./examples/node/stdout.js):
|
||||
|
||||
```js
|
||||
var debug = require('debug');
|
||||
var error = debug('app:error');
|
||||
|
||||
// by default stderr is used
|
||||
error('goes to stderr!');
|
||||
|
||||
var log = debug('app:log');
|
||||
// set this namespace to log via console.log
|
||||
log.log = console.log.bind(console); // don't forget to bind to console!
|
||||
log('goes to stdout');
|
||||
error('still goes to stderr!');
|
||||
|
||||
// set all output to go via console.info
|
||||
// overrides all per-namespace log settings
|
||||
debug.log = console.info.bind(console);
|
||||
error('now goes to stdout via console.info');
|
||||
log('still goes to stdout, but via console.info now');
|
||||
```
|
||||
|
||||
## Extend
|
||||
You can simply extend debugger
|
||||
```js
|
||||
const log = require('debug')('auth');
|
||||
|
||||
//creates new debug instance with extended namespace
|
||||
const logSign = log.extend('sign');
|
||||
const logLogin = log.extend('login');
|
||||
|
||||
log('hello'); // auth hello
|
||||
logSign('hello'); //auth:sign hello
|
||||
logLogin('hello'); //auth:login hello
|
||||
```
|
||||
|
||||
## Set dynamically
|
||||
|
||||
You can also enable debug dynamically by calling the `enable()` method :
|
||||
|
||||
```js
|
||||
let debug = require('debug');
|
||||
|
||||
console.log(1, debug.enabled('test'));
|
||||
|
||||
debug.enable('test');
|
||||
console.log(2, debug.enabled('test'));
|
||||
|
||||
debug.disable();
|
||||
console.log(3, debug.enabled('test'));
|
||||
|
||||
```
|
||||
|
||||
print :
|
||||
```
|
||||
1 false
|
||||
2 true
|
||||
3 false
|
||||
```
|
||||
|
||||
Usage :
|
||||
`enable(namespaces)`
|
||||
`namespaces` can include modes separated by a colon and wildcards.
|
||||
|
||||
Note that calling `enable()` completely overrides previously set DEBUG variable :
|
||||
|
||||
```
|
||||
$ DEBUG=foo node -e 'var dbg = require("debug"); dbg.enable("bar"); console.log(dbg.enabled("foo"))'
|
||||
=> false
|
||||
```
|
||||
|
||||
`disable()`
|
||||
|
||||
Will disable all namespaces. The functions returns the namespaces currently
|
||||
enabled (and skipped). This can be useful if you want to disable debugging
|
||||
temporarily without knowing what was enabled to begin with.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
let debug = require('debug');
|
||||
debug.enable('foo:*,-foo:bar');
|
||||
let namespaces = debug.disable();
|
||||
debug.enable(namespaces);
|
||||
```
|
||||
|
||||
Note: There is no guarantee that the string will be identical to the initial
|
||||
enable string, but semantically they will be identical.
|
||||
|
||||
## Checking whether a debug target is enabled
|
||||
|
||||
After you've created a debug instance, you can determine whether or not it is
|
||||
enabled by checking the `enabled` property:
|
||||
|
||||
```javascript
|
||||
const debug = require('debug')('http');
|
||||
|
||||
if (debug.enabled) {
|
||||
// do stuff...
|
||||
}
|
||||
```
|
||||
|
||||
You can also manually toggle this property to force the debug instance to be
|
||||
enabled or disabled.
|
||||
|
||||
## Usage in child processes
|
||||
|
||||
Due to the way `debug` detects if the output is a TTY or not, colors are not shown in child processes when `stderr` is piped. A solution is to pass the `DEBUG_COLORS=1` environment variable to the child process.
|
||||
For example:
|
||||
|
||||
```javascript
|
||||
worker = fork(WORKER_WRAP_PATH, [workerPath], {
|
||||
stdio: [
|
||||
/* stdin: */ 0,
|
||||
/* stdout: */ 'pipe',
|
||||
/* stderr: */ 'pipe',
|
||||
'ipc',
|
||||
],
|
||||
env: Object.assign({}, process.env, {
|
||||
DEBUG_COLORS: 1 // without this settings, colors won't be shown
|
||||
}),
|
||||
});
|
||||
|
||||
worker.stderr.pipe(process.stderr, { end: false });
|
||||
```
|
||||
|
||||
|
||||
## Authors
|
||||
|
||||
- TJ Holowaychuk
|
||||
- Nathan Rajlich
|
||||
- Andrew Rhyne
|
||||
- Josh Junon
|
||||
|
||||
## Backers
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/debug#backer)]
|
||||
|
||||
<a href="https://opencollective.com/debug/backer/0/website" target="_blank"><img src="https://opencollective.com/debug/backer/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/1/website" target="_blank"><img src="https://opencollective.com/debug/backer/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/2/website" target="_blank"><img src="https://opencollective.com/debug/backer/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/3/website" target="_blank"><img src="https://opencollective.com/debug/backer/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/4/website" target="_blank"><img src="https://opencollective.com/debug/backer/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/5/website" target="_blank"><img src="https://opencollective.com/debug/backer/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/6/website" target="_blank"><img src="https://opencollective.com/debug/backer/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/7/website" target="_blank"><img src="https://opencollective.com/debug/backer/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/8/website" target="_blank"><img src="https://opencollective.com/debug/backer/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/9/website" target="_blank"><img src="https://opencollective.com/debug/backer/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/10/website" target="_blank"><img src="https://opencollective.com/debug/backer/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/11/website" target="_blank"><img src="https://opencollective.com/debug/backer/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/12/website" target="_blank"><img src="https://opencollective.com/debug/backer/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/13/website" target="_blank"><img src="https://opencollective.com/debug/backer/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/14/website" target="_blank"><img src="https://opencollective.com/debug/backer/14/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/15/website" target="_blank"><img src="https://opencollective.com/debug/backer/15/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/16/website" target="_blank"><img src="https://opencollective.com/debug/backer/16/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/17/website" target="_blank"><img src="https://opencollective.com/debug/backer/17/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/18/website" target="_blank"><img src="https://opencollective.com/debug/backer/18/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/19/website" target="_blank"><img src="https://opencollective.com/debug/backer/19/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/20/website" target="_blank"><img src="https://opencollective.com/debug/backer/20/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/21/website" target="_blank"><img src="https://opencollective.com/debug/backer/21/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/22/website" target="_blank"><img src="https://opencollective.com/debug/backer/22/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/23/website" target="_blank"><img src="https://opencollective.com/debug/backer/23/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/24/website" target="_blank"><img src="https://opencollective.com/debug/backer/24/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/25/website" target="_blank"><img src="https://opencollective.com/debug/backer/25/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/26/website" target="_blank"><img src="https://opencollective.com/debug/backer/26/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/27/website" target="_blank"><img src="https://opencollective.com/debug/backer/27/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/28/website" target="_blank"><img src="https://opencollective.com/debug/backer/28/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/backer/29/website" target="_blank"><img src="https://opencollective.com/debug/backer/29/avatar.svg"></a>
|
||||
|
||||
|
||||
## Sponsors
|
||||
|
||||
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/debug#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/debug/sponsor/0/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/1/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/2/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/3/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/4/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/5/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/6/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/7/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/8/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/9/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/10/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/11/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/12/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/13/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/14/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/14/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/15/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/15/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/16/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/16/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/17/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/17/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/18/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/18/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/19/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/19/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/20/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/20/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/21/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/21/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/22/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/22/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/23/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/23/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/24/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/24/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/25/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/25/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/26/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/26/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/27/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/27/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/28/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/28/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/debug/sponsor/29/website" target="_blank"><img src="https://opencollective.com/debug/sponsor/29/avatar.svg"></a>
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2018-2021 Josh Junon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,77 @@
|
||||
'use strict'
|
||||
|
||||
// Maximum wait time for a single waitAsync call
|
||||
// Used as a fallback poll interval in case notifications are missed
|
||||
// Keep this low enough for good throughput but high enough to not busy-loop
|
||||
const WAIT_MS = 10000
|
||||
|
||||
function wait (state, index, expected, timeout, done) {
|
||||
const max = timeout === Infinity ? Infinity : Date.now() + timeout
|
||||
|
||||
const check = () => {
|
||||
const current = Atomics.load(state, index)
|
||||
if (current === expected) {
|
||||
done(null, 'ok')
|
||||
return
|
||||
}
|
||||
|
||||
if (max !== Infinity && Date.now() > max) {
|
||||
done(null, 'timed-out')
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for any change from current value
|
||||
const remaining = max === Infinity ? WAIT_MS : Math.min(WAIT_MS, Math.max(1, max - Date.now()))
|
||||
const result = Atomics.waitAsync(state, index, current, remaining)
|
||||
|
||||
if (result.async) {
|
||||
result.value.then(check)
|
||||
} else {
|
||||
// Value already changed (not-equal) - recheck on next tick
|
||||
setImmediate(check)
|
||||
}
|
||||
}
|
||||
|
||||
check()
|
||||
}
|
||||
|
||||
function waitDiff (state, index, expected, timeout, done) {
|
||||
const max = timeout === Infinity ? Infinity : Date.now() + timeout
|
||||
|
||||
const check = () => {
|
||||
const current = Atomics.load(state, index)
|
||||
if (current !== expected) {
|
||||
done(null, 'ok')
|
||||
return
|
||||
}
|
||||
|
||||
if (max !== Infinity && Date.now() > max) {
|
||||
done(null, 'timed-out')
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for value to change from expected.
|
||||
// If we are notified, resume immediately even if the value cycled back
|
||||
// to the same number before we could re-read it.
|
||||
const remaining = max === Infinity ? WAIT_MS : Math.min(WAIT_MS, Math.max(1, max - Date.now()))
|
||||
const result = Atomics.waitAsync(state, index, expected, remaining)
|
||||
|
||||
if (result.async) {
|
||||
result.value.then((res) => {
|
||||
if (res === 'ok') {
|
||||
done(null, 'ok')
|
||||
return
|
||||
}
|
||||
|
||||
check()
|
||||
})
|
||||
} else {
|
||||
// Value already changed (not-equal) - recheck on next tick
|
||||
setImmediate(check)
|
||||
}
|
||||
}
|
||||
|
||||
check()
|
||||
}
|
||||
|
||||
module.exports = { wait, waitDiff }
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
const compare = require('./compare')
|
||||
const lte = (a, b, loose) => compare(a, b, loose) <= 0
|
||||
module.exports = lte
|
||||
@@ -0,0 +1 @@
|
||||
const t=new Set(["Custom ESM Loaders is an experimental feature. This feature could change at any time","Custom ESM Loaders is an experimental feature and might change at any time","Import assertions are not a stable feature of the JavaScript language. Avoid relying on their current behavior and syntax as those might change in a future version of Node.js."]),{emit:n}=process;process.emit=function(e,a){if(!(e==="warning"&&t.has(a.message)))return Reflect.apply(n,this,arguments)};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2019: LibDefinition;
|
||||
@@ -0,0 +1,24 @@
|
||||
import rng from './rng.js';
|
||||
import stringify from './stringify.js';
|
||||
|
||||
function v4(options, buf, offset) {
|
||||
options = options || {};
|
||||
const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
||||
|
||||
rnds[6] = rnds[6] & 0x0f | 0x40;
|
||||
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
|
||||
|
||||
if (buf) {
|
||||
offset = offset || 0;
|
||||
|
||||
for (let i = 0; i < 16; ++i) {
|
||||
buf[offset + i] = rnds[i];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
return stringify(rnds);
|
||||
}
|
||||
|
||||
export default v4;
|
||||
@@ -0,0 +1,101 @@
|
||||
'use strict'
|
||||
|
||||
const { describe, test } = require('node:test')
|
||||
const assert = require('node:assert')
|
||||
const pino = require('../browser')
|
||||
|
||||
const customLevels = {
|
||||
trace: 10,
|
||||
debug: 20,
|
||||
info: 30,
|
||||
warn: 40,
|
||||
error: 50,
|
||||
fatal: 60
|
||||
}
|
||||
|
||||
describe('Default levels suite', () => {
|
||||
test('can check if current level enabled', async () => {
|
||||
const log = pino({ level: 'debug' })
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
})
|
||||
|
||||
test('can check if current level enabled when as object', async () => {
|
||||
const log = pino({ asObject: true, level: 'debug' })
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
})
|
||||
|
||||
test('can check if level enabled after level set', async () => {
|
||||
const log = pino()
|
||||
assert.equal(false, log.isLevelEnabled('debug'))
|
||||
log.level = 'debug'
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
})
|
||||
|
||||
test('can check if higher level enabled', async () => {
|
||||
const log = pino({ level: 'debug' })
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
})
|
||||
|
||||
test('can check if lower level is disabled', async () => {
|
||||
const log = pino({ level: 'error' })
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
|
||||
test('ASC: can check if child has current level enabled', async () => {
|
||||
const log = pino().child({}, { level: 'debug' })
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
|
||||
test('can check if custom level is enabled', async () => {
|
||||
const log = pino({
|
||||
customLevels: { foo: 35 },
|
||||
level: 'debug'
|
||||
})
|
||||
assert.equal(true, log.isLevelEnabled('foo'))
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('Custom levels suite', () => {
|
||||
test('can check if current level enabled', async () => {
|
||||
const log = pino({ level: 'debug', customLevels })
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
})
|
||||
|
||||
test('can check if level enabled after level set', async () => {
|
||||
const log = pino({ customLevels })
|
||||
assert.equal(false, log.isLevelEnabled('debug'))
|
||||
log.level = 'debug'
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
})
|
||||
|
||||
test('can check if higher level enabled', async () => {
|
||||
const log = pino({ level: 'debug', customLevels })
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
})
|
||||
|
||||
test('can check if lower level is disabled', async () => {
|
||||
const log = pino({ level: 'error', customLevels })
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
|
||||
test('can check if child has current level enabled', async () => {
|
||||
const log = pino().child({ customLevels }, { level: 'debug' })
|
||||
assert.equal(true, log.isLevelEnabled('debug'))
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
|
||||
test('can check if custom level is enabled', async () => {
|
||||
const log = pino({
|
||||
customLevels: { foo: 35, ...customLevels },
|
||||
level: 'debug'
|
||||
})
|
||||
assert.equal(true, log.isLevelEnabled('foo'))
|
||||
assert.equal(true, log.isLevelEnabled('error'))
|
||||
assert.equal(false, log.isLevelEnabled('trace'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
export * from './dist/node.js'
|
||||
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
function _check_private_redeclaration(obj, privateCollection) {
|
||||
if (privateCollection.has(obj)) {
|
||||
throw new TypeError("Cannot initialize the same private elements twice on an object");
|
||||
}
|
||||
}
|
||||
exports._ = _check_private_redeclaration;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user