WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"for + if": {
|
||||
"name": "for + if",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-long",
|
||||
"hz": 24532.66436126496,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.024335714081936355,
|
||||
"rhz": 0.8134502756892201,
|
||||
"sampleSize": 210
|
||||
},
|
||||
"while + if": {
|
||||
"name": "while + if",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-long",
|
||||
"hz": 22714.555324734756,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.02508863769322542,
|
||||
"rhz": 0.7531656985548391,
|
||||
"sampleSize": 210
|
||||
},
|
||||
"array join": {
|
||||
"name": "array join",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-long",
|
||||
"hz": 30158.775643021236,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.02294916733281892,
|
||||
"rhz": 1,
|
||||
"sampleSize": 214
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* NIST secp256r1 aka p256.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { type H2CMethod } from './abstract/hash-to-curve.ts';
|
||||
import { p256_hasher, p256 as p256n } from './nist.ts';
|
||||
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
|
||||
export const p256: typeof p256n = p256n;
|
||||
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
|
||||
export const secp256r1: typeof p256n = p256n;
|
||||
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
|
||||
export const hashToCurve: H2CMethod<bigint> = /* @__PURE__ */ (() => p256_hasher.hashToCurve)();
|
||||
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
|
||||
export const encodeToCurve: H2CMethod<bigint> = /* @__PURE__ */ (() => p256_hasher.encodeToCurve)();
|
||||
@@ -0,0 +1,217 @@
|
||||
class Traces {
|
||||
/**
|
||||
* otel stands for OpenTelemetry
|
||||
*/
|
||||
#otel = null;
|
||||
#sdk = null;
|
||||
#init = null;
|
||||
#noopSpan = createNoopSpan();
|
||||
#noopContext = createNoopContext();
|
||||
#initStartTime = performance.now();
|
||||
#initEndTime = 0;
|
||||
#initRecorded = false;
|
||||
constructor(options) {
|
||||
if (options.enabled) {
|
||||
const apiInit = import('@opentelemetry/api').then((api) => {
|
||||
this.#otel = {
|
||||
tracer: api.trace.getTracer(options.tracerName || "vitest"),
|
||||
context: api.context,
|
||||
propagation: api.propagation,
|
||||
trace: api.trace,
|
||||
SpanKind: api.SpanKind,
|
||||
SpanStatusCode: api.SpanStatusCode
|
||||
};
|
||||
}).catch(() => {
|
||||
throw new Error(`"@opentelemetry/api" is not installed locally. Make sure you have setup OpenTelemetry instrumentation: https://vitest.dev/guide/open-telemetry`);
|
||||
});
|
||||
const sdkInit = (options.sdkPath ? import(
|
||||
/* @vite-ignore */
|
||||
options.sdkPath
|
||||
) : Promise.resolve()).catch((cause) => {
|
||||
throw new Error(`Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message}`);
|
||||
});
|
||||
this.#init = Promise.all([sdkInit, apiInit]).then(([sdk]) => {
|
||||
if (sdk != null) {
|
||||
if (sdk.default != null && typeof sdk.default === "object" && typeof sdk.default.shutdown === "function") this.#sdk = sdk.default;
|
||||
else if (options.watchMode !== true && process.env.VITEST_MODE !== "watch") console.warn(`OpenTelemetry instrumentation module (${options.sdkPath}) does not have a default export with a "shutdown" method. Vitest won't be able to ensure that all traces are processed in time. Try running Vitest in watch mode instead.`);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.#initEndTime = performance.now();
|
||||
this.#init = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
isEnabled() {
|
||||
return !!this.#otel;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async waitInit() {
|
||||
if (this.#init) await this.#init;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
recordInitSpan(context) {
|
||||
if (this.#initRecorded) return;
|
||||
this.#initRecorded = true;
|
||||
this.startSpan("vitest.runtime.traces", { startTime: this.#initStartTime }, context).end(this.#initEndTime);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
startContextSpan(name, currentContext) {
|
||||
if (!this.#otel) return {
|
||||
span: this.#noopSpan,
|
||||
context: this.#noopContext
|
||||
};
|
||||
const activeContext = currentContext || this.#otel.context.active();
|
||||
const span = this.#otel.tracer.startSpan(name, {}, activeContext);
|
||||
return {
|
||||
span,
|
||||
context: this.#otel.trace.setSpan(activeContext, span)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getContextFromCarrier(carrier) {
|
||||
if (!this.#otel) return this.#noopContext;
|
||||
const activeContext = this.#otel.context.active();
|
||||
if (!carrier) return activeContext;
|
||||
return this.#otel.propagation.extract(activeContext, carrier);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getContextFromEnv(env) {
|
||||
if (!this.#otel) return this.#noopContext;
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/env-carriers.md
|
||||
// some tools sets only `TRACEPARENT` but not `TRACESTATE`
|
||||
const carrier = {};
|
||||
if (typeof env.TRACEPARENT === "string") carrier.traceparent = env.TRACEPARENT;
|
||||
if (typeof env.TRACESTATE === "string") carrier.tracestate = env.TRACESTATE;
|
||||
return this.getContextFromCarrier(carrier);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getContextCarrier(context) {
|
||||
if (!this.#otel) return;
|
||||
const carrier = {};
|
||||
this.#otel.propagation.inject(context || this.#otel.context.active(), carrier);
|
||||
return carrier;
|
||||
}
|
||||
#callActiveSpan(span, callback) {
|
||||
const otel = this.#otel;
|
||||
let result;
|
||||
try {
|
||||
result = callback(span);
|
||||
if (result instanceof Promise) return result.catch((error) => {
|
||||
span.recordException({
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
span.setStatus({ code: otel.SpanStatusCode.ERROR });
|
||||
throw error;
|
||||
}).finally(() => span.end());
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
span.recordException({
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
span.setStatus({ code: otel.SpanStatusCode.ERROR });
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
// end sync callback
|
||||
if (!(result instanceof Promise)) span.end();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
$(name, optionsOrFn, fn) {
|
||||
const callback = typeof optionsOrFn === "function" ? optionsOrFn : fn;
|
||||
if (!this.#otel) return callback(this.#noopSpan);
|
||||
const otel = this.#otel;
|
||||
const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
|
||||
const context = options.context;
|
||||
if (context) return otel.tracer.startActiveSpan(name, options, context, (span) => this.#callActiveSpan(span, callback));
|
||||
return otel.tracer.startActiveSpan(name, options, (span) => this.#callActiveSpan(span, callback));
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
startSpan(name, options, context) {
|
||||
if (!this.#otel) return this.#noopSpan;
|
||||
const { tracer } = this.#otel;
|
||||
return tracer.startSpan(name, options, context);
|
||||
}
|
||||
// On browser mode, async context is not automatically propagated,
|
||||
// so we manually bind the `$` calls to the provided context.
|
||||
// TODO: this doesn't bind to user land's `@optelemetry/api` calls
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
bind(context) {
|
||||
if (!this.#otel) return;
|
||||
const original = this.$.__original ?? this.$;
|
||||
this.$ = this.#otel.context.bind(context, original);
|
||||
this.$.__original = original;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async finish() {
|
||||
await this.#sdk?.shutdown();
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async flush() {
|
||||
await this.#sdk?.forceFlush?.();
|
||||
}
|
||||
}
|
||||
function noopSpan() {
|
||||
return this;
|
||||
}
|
||||
function createNoopSpan() {
|
||||
return {
|
||||
setAttribute: noopSpan,
|
||||
setStatus: noopSpan,
|
||||
addEvent: noopSpan,
|
||||
addLink: noopSpan,
|
||||
addLinks: noopSpan,
|
||||
setAttributes: noopSpan,
|
||||
updateName: noopSpan,
|
||||
end: () => {},
|
||||
isRecording: () => false,
|
||||
recordException: noopSpan,
|
||||
spanContext() {
|
||||
return {
|
||||
spanId: "",
|
||||
traceFlags: 0,
|
||||
traceId: ""
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
function noopContext() {
|
||||
return this;
|
||||
}
|
||||
function createNoopContext() {
|
||||
return {
|
||||
getValue: noopContext,
|
||||
setValue: noopContext,
|
||||
deleteValue: noopContext
|
||||
};
|
||||
}
|
||||
|
||||
export { Traces as T };
|
||||
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (github.com/kevva)
|
||||
|
||||
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,23 @@
|
||||
"use strict";
|
||||
// file for microbenchmarking
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const buffer_reader_1 = require("./buffer-reader");
|
||||
const LOOPS = 1000;
|
||||
let count = 0;
|
||||
const start = performance.now();
|
||||
const reader = new buffer_reader_1.BufferReader();
|
||||
const buffer = Buffer.from([33, 33, 33, 33, 33, 33, 33, 0]);
|
||||
const run = () => {
|
||||
if (count > LOOPS) {
|
||||
console.log(performance.now() - start);
|
||||
return;
|
||||
}
|
||||
count++;
|
||||
for (let i = 0; i < LOOPS; i++) {
|
||||
reader.setBuffer(0, buffer);
|
||||
reader.cstring();
|
||||
}
|
||||
setImmediate(run);
|
||||
};
|
||||
run();
|
||||
//# sourceMappingURL=b.js.map
|
||||
@@ -0,0 +1,669 @@
|
||||
declare module "node:worker_threads" {
|
||||
import {
|
||||
EventEmitter,
|
||||
InternalEventEmitter,
|
||||
InternalEventTargetEventProperties,
|
||||
NodeEventTarget,
|
||||
} from "node:events";
|
||||
import { FileHandle } from "node:fs/promises";
|
||||
import { Performance } from "node:perf_hooks";
|
||||
import { Readable, Writable } from "node:stream";
|
||||
import { ReadableStream, TransformStream, WritableStream } from "node:stream/web";
|
||||
import { URL } from "node:url";
|
||||
import { CPUProfileHandle, CPUProfileOptions, HeapInfo, HeapProfileHandle, HeapProfileOptions } from "node:v8";
|
||||
import { Context } from "node:vm";
|
||||
import { MessageEvent } from "undici-types";
|
||||
const isInternalThread: boolean;
|
||||
const isMainThread: boolean;
|
||||
const parentPort: null | MessagePort;
|
||||
const resourceLimits: ResourceLimits;
|
||||
const SHARE_ENV: unique symbol;
|
||||
const threadId: number;
|
||||
const threadName: string | null;
|
||||
const workerData: any;
|
||||
interface WorkerPerformance extends Pick<Performance, "eventLoopUtilization"> {}
|
||||
interface WorkerOptions {
|
||||
/**
|
||||
* List of arguments which would be stringified and appended to
|
||||
* `process.argv` in the worker. This is mostly similar to the `workerData`
|
||||
* but the values will be available on the global `process.argv` as if they
|
||||
* were passed as CLI options to the script.
|
||||
*/
|
||||
argv?: any[] | undefined;
|
||||
env?: NodeJS.Dict<string> | typeof SHARE_ENV | undefined;
|
||||
eval?: boolean | undefined;
|
||||
workerData?: any;
|
||||
stdin?: boolean | undefined;
|
||||
stdout?: boolean | undefined;
|
||||
stderr?: boolean | undefined;
|
||||
execArgv?: string[] | undefined;
|
||||
resourceLimits?: ResourceLimits | undefined;
|
||||
/**
|
||||
* Additional data to send in the first worker message.
|
||||
*/
|
||||
transferList?: Transferable[] | undefined;
|
||||
/**
|
||||
* @default true
|
||||
*/
|
||||
trackUnmanagedFds?: boolean | undefined;
|
||||
/**
|
||||
* An optional `name` to be appended to the worker title
|
||||
* for debugging/identification purposes, making the final title as
|
||||
* `[worker ${id}] ${name}`.
|
||||
*/
|
||||
name?: string | undefined;
|
||||
}
|
||||
interface ResourceLimits {
|
||||
/**
|
||||
* The maximum size of a heap space for recently created objects.
|
||||
*/
|
||||
maxYoungGenerationSizeMb?: number | undefined;
|
||||
/**
|
||||
* The maximum size of the main heap in MB.
|
||||
*/
|
||||
maxOldGenerationSizeMb?: number | undefined;
|
||||
/**
|
||||
* The size of a pre-allocated memory range used for generated code.
|
||||
*/
|
||||
codeRangeSizeMb?: number | undefined;
|
||||
/**
|
||||
* The default maximum stack size for the thread. Small values may lead to unusable Worker instances.
|
||||
* @default 4
|
||||
*/
|
||||
stackSizeMb?: number | undefined;
|
||||
}
|
||||
interface WorkerEventMap {
|
||||
"error": [err: unknown];
|
||||
"exit": [exitCode: number];
|
||||
"message": [value: any];
|
||||
"messageerror": [error: Error];
|
||||
"online": [];
|
||||
}
|
||||
/**
|
||||
* The `Worker` class represents an independent JavaScript execution thread.
|
||||
* Most Node.js APIs are available inside of it.
|
||||
*
|
||||
* Notable differences inside a Worker environment are:
|
||||
*
|
||||
* * The `process.stdin`, `process.stdout`, and `process.stderr` streams may be redirected by the parent thread.
|
||||
* * The `import { isMainThread } from 'node:worker_threads'` variable is set to `false`.
|
||||
* * The `import { parentPort } from 'node:worker_threads'` message port is available.
|
||||
* * `process.exit()` does not stop the whole program, just the single thread,
|
||||
* and `process.abort()` is not available.
|
||||
* * `process.chdir()` and `process` methods that set group or user ids
|
||||
* are not available.
|
||||
* * `process.env` is a copy of the parent thread's environment variables,
|
||||
* unless otherwise specified. Changes to one copy are not visible in other
|
||||
* threads, and are not visible to native add-ons (unless `worker.SHARE_ENV` is passed as the `env` option to the `Worker` constructor). On Windows, unlike the main thread, a copy of the
|
||||
* environment variables operates in a case-sensitive manner.
|
||||
* * `process.title` cannot be modified.
|
||||
* * Signals are not delivered through `process.on('...')`.
|
||||
* * Execution may stop at any point as a result of `worker.terminate()` being invoked.
|
||||
* * IPC channels from parent processes are not accessible.
|
||||
* * The `trace_events` module is not supported.
|
||||
* * Native add-ons can only be loaded from multiple threads if they fulfill `certain conditions`.
|
||||
*
|
||||
* Creating `Worker` instances inside of other `Worker`s is possible.
|
||||
*
|
||||
* Like [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) and the `node:cluster module`, two-way communication
|
||||
* can be achieved through inter-thread message passing. Internally, a `Worker` has
|
||||
* a built-in pair of `MessagePort` s that are already associated with each
|
||||
* other when the `Worker` is created. While the `MessagePort` object on the parent
|
||||
* side is not directly exposed, its functionalities are exposed through `worker.postMessage()` and the `worker.on('message')` event
|
||||
* on the `Worker` object for the parent thread.
|
||||
*
|
||||
* To create custom messaging channels (which is encouraged over using the default
|
||||
* global channel because it facilitates separation of concerns), users can create
|
||||
* a `MessageChannel` object on either thread and pass one of the`MessagePort`s on that `MessageChannel` to the other thread through a
|
||||
* pre-existing channel, such as the global one.
|
||||
*
|
||||
* See `port.postMessage()` for more information on how messages are passed,
|
||||
* and what kind of JavaScript values can be successfully transported through
|
||||
* the thread barrier.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert';
|
||||
* import {
|
||||
* Worker, MessageChannel, MessagePort, isMainThread, parentPort,
|
||||
* } from 'node:worker_threads';
|
||||
* if (isMainThread) {
|
||||
* const worker = new Worker(__filename);
|
||||
* const subChannel = new MessageChannel();
|
||||
* worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
|
||||
* subChannel.port2.on('message', (value) => {
|
||||
* console.log('received:', value);
|
||||
* });
|
||||
* } else {
|
||||
* parentPort.once('message', (value) => {
|
||||
* assert(value.hereIsYourPort instanceof MessagePort);
|
||||
* value.hereIsYourPort.postMessage('the worker is sending this');
|
||||
* value.hereIsYourPort.close();
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @since v10.5.0
|
||||
*/
|
||||
class Worker implements EventEmitter {
|
||||
/**
|
||||
* If `stdin: true` was passed to the `Worker` constructor, this is a
|
||||
* writable stream. The data written to this stream will be made available in
|
||||
* the worker thread as `process.stdin`.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
readonly stdin: Writable | null;
|
||||
/**
|
||||
* This is a readable stream which contains data written to `process.stdout` inside the worker thread. If `stdout: true` was not passed to the `Worker` constructor, then data is piped to the
|
||||
* parent thread's `process.stdout` stream.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
readonly stdout: Readable;
|
||||
/**
|
||||
* This is a readable stream which contains data written to `process.stderr` inside the worker thread. If `stderr: true` was not passed to the `Worker` constructor, then data is piped to the
|
||||
* parent thread's `process.stderr` stream.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
readonly stderr: Readable;
|
||||
/**
|
||||
* An integer identifier for the referenced thread. Inside the worker thread,
|
||||
* it is available as `import { threadId } from 'node:worker_threads'`.
|
||||
* This value is unique for each `Worker` instance inside a single process.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
readonly threadId: number;
|
||||
/**
|
||||
* A string identifier for the referenced thread or null if the thread is not running.
|
||||
* Inside the worker thread, it is available as `require('node:worker_threads').threadName`.
|
||||
* @since v24.6.0
|
||||
*/
|
||||
readonly threadName: string | null;
|
||||
/**
|
||||
* Provides the set of JS engine resource constraints for this Worker thread.
|
||||
* If the `resourceLimits` option was passed to the `Worker` constructor,
|
||||
* this matches its values.
|
||||
*
|
||||
* If the worker has stopped, the return value is an empty object.
|
||||
* @since v13.2.0, v12.16.0
|
||||
*/
|
||||
readonly resourceLimits?: ResourceLimits | undefined;
|
||||
/**
|
||||
* An object that can be used to query performance information from a worker
|
||||
* instance. Similar to `perf_hooks.performance`.
|
||||
* @since v15.1.0, v14.17.0, v12.22.0
|
||||
*/
|
||||
readonly performance: WorkerPerformance;
|
||||
/**
|
||||
* @param filename The path to the Worker’s main script or module.
|
||||
* Must be either an absolute path or a relative path (i.e. relative to the current working directory) starting with ./ or ../,
|
||||
* or a WHATWG URL object using file: protocol. If options.eval is true, this is a string containing JavaScript code rather than a path.
|
||||
*/
|
||||
constructor(filename: string | URL, options?: WorkerOptions);
|
||||
/**
|
||||
* Send a message to the worker that is received via `require('node:worker_threads').parentPort.on('message')`.
|
||||
* See `port.postMessage()` for more details.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
postMessage(value: any, transferList?: readonly Transferable[]): void;
|
||||
/**
|
||||
* Opposite of `unref()`, calling `ref()` on a previously `unref()`ed worker does _not_ let the program exit if it's the only active handle left (the default
|
||||
* behavior). If the worker is `ref()`ed, calling `ref()` again has
|
||||
* no effect.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
ref(): void;
|
||||
/**
|
||||
* Calling `unref()` on a worker allows the thread to exit if this is the only
|
||||
* active handle in the event system. If the worker is already `unref()`ed calling `unref()` again has no effect.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
unref(): void;
|
||||
/**
|
||||
* Stop all JavaScript execution in the worker thread as soon as possible.
|
||||
* Returns a Promise for the exit code that is fulfilled when the `'exit' event` is emitted.
|
||||
* @since v10.5.0
|
||||
*/
|
||||
terminate(): Promise<number>;
|
||||
/**
|
||||
* This method returns a `Promise` that will resolve to an object identical to `process.threadCpuUsage()`,
|
||||
* or reject with an `ERR_WORKER_NOT_RUNNING` error if the worker is no longer running.
|
||||
* This methods allows the statistics to be observed from outside the actual thread.
|
||||
* @since v24.6.0
|
||||
*/
|
||||
cpuUsage(prev?: NodeJS.CpuUsage): Promise<NodeJS.CpuUsage>;
|
||||
/**
|
||||
* Returns a readable stream for a V8 snapshot of the current state of the Worker.
|
||||
* See `v8.getHeapSnapshot()` for more details.
|
||||
*
|
||||
* If the Worker thread is no longer running, which may occur before the `'exit' event` is emitted, the returned `Promise` is rejected
|
||||
* immediately with an `ERR_WORKER_NOT_RUNNING` error.
|
||||
* @since v13.9.0, v12.17.0
|
||||
* @return A promise for a Readable Stream containing a V8 heap snapshot
|
||||
*/
|
||||
getHeapSnapshot(): Promise<Readable>;
|
||||
/**
|
||||
* This method returns a `Promise` that will resolve to an object identical to `v8.getHeapStatistics()`,
|
||||
* or reject with an `ERR_WORKER_NOT_RUNNING` error if the worker is no longer running.
|
||||
* This methods allows the statistics to be observed from outside the actual thread.
|
||||
* @since v24.0.0
|
||||
*/
|
||||
getHeapStatistics(): Promise<HeapInfo>;
|
||||
/**
|
||||
* Starting a CPU profile then return a Promise that fulfills with an error
|
||||
* or an `CPUProfileHandle` object. This API supports `await using` syntax.
|
||||
*
|
||||
* ```js
|
||||
* const { Worker } = require('node:worker_threads');
|
||||
*
|
||||
* const worker = new Worker(`
|
||||
* const { parentPort } = require('worker_threads');
|
||||
* parentPort.on('message', () => {});
|
||||
* `, { eval: true });
|
||||
*
|
||||
* worker.on('online', async () => {
|
||||
* const handle = await worker.startCpuProfile({ sampleInterval: 1 });
|
||||
* const profile = await handle.stop();
|
||||
* console.log(profile);
|
||||
* worker.terminate();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* `await using` example.
|
||||
*
|
||||
* ```js
|
||||
* const { Worker } = require('node:worker_threads');
|
||||
*
|
||||
* const w = new Worker(`
|
||||
* const { parentPort } = require('node:worker_threads');
|
||||
* parentPort.on('message', () => {});
|
||||
* `, { eval: true });
|
||||
*
|
||||
* w.on('online', async () => {
|
||||
* // Stop profile automatically when return and profile will be discarded
|
||||
* await using handle = await w.startCpuProfile();
|
||||
* });
|
||||
* ```
|
||||
* @since v24.8.0
|
||||
*/
|
||||
startCpuProfile(options?: CPUProfileOptions): Promise<CPUProfileHandle>;
|
||||
/**
|
||||
* Starting a Heap profile then return a Promise that fulfills with an error
|
||||
* or an `HeapProfileHandle` object. This API supports `await using` syntax.
|
||||
*
|
||||
* ```js
|
||||
* import { Worker } from 'node:worker_threads';
|
||||
*
|
||||
* const worker = new Worker(`
|
||||
* const { parentPort } = require('node:worker_threads');
|
||||
* parentPort.on('message', () => {});
|
||||
* `, { eval: true });
|
||||
*
|
||||
* worker.on('online', async () => {
|
||||
* const handle = await worker.startHeapProfile();
|
||||
* const profile = await handle.stop();
|
||||
* console.log(profile);
|
||||
* worker.terminate();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* `await using` example.
|
||||
*
|
||||
* ```js
|
||||
* import { Worker } from 'node:worker_threads';
|
||||
*
|
||||
* const w = new Worker(`
|
||||
* const { parentPort } = require('node:worker_threads');
|
||||
* parentPort.on('message', () => {});
|
||||
* `, { eval: true });
|
||||
*
|
||||
* w.on('online', async () => {
|
||||
* // Stop profile automatically when return and profile will be discarded
|
||||
* await using handle = await w.startHeapProfile();
|
||||
* });
|
||||
* ```
|
||||
* @since v24.9.0
|
||||
*/
|
||||
startHeapProfile(options?: HeapProfileOptions): Promise<HeapProfileHandle>;
|
||||
/**
|
||||
* Calls `worker.terminate()` when the dispose scope is exited.
|
||||
*
|
||||
* ```js
|
||||
* async function example() {
|
||||
* await using worker = new Worker('for (;;) {}', { eval: true });
|
||||
* // Worker is automatically terminate when the scope is exited.
|
||||
* }
|
||||
* ```
|
||||
* @since v24.2.0
|
||||
*/
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
interface Worker extends InternalEventEmitter<WorkerEventMap> {}
|
||||
/**
|
||||
* Mark an object as not transferable. If `object` occurs in the transfer list of
|
||||
* a [`port.postMessage()`](https://nodejs.org/docs/latest-v26.x/api/worker_threads.html#portpostmessagevalue-transferlist) call, an error is thrown. This is a no-op if
|
||||
* `object` is a primitive value.
|
||||
*
|
||||
* In particular, this makes sense for objects that can be cloned, rather than
|
||||
* transferred, and which are used by other objects on the sending side.
|
||||
* For example, Node.js marks the `ArrayBuffer`s it uses for its
|
||||
* [`Buffer` pool](https://nodejs.org/docs/latest-v26.x/api/buffer.html#static-method-bufferallocunsafesize) with this.
|
||||
* `ArrayBuffer.prototype.transfer()` is disallowed on such array buffer
|
||||
* instances.
|
||||
*
|
||||
* This operation cannot be undone.
|
||||
*
|
||||
* ```js
|
||||
* import { MessageChannel, markAsUntransferable } from 'node:worker_threads';
|
||||
*
|
||||
* const pooledBuffer = new ArrayBuffer(8);
|
||||
* const typedArray1 = new Uint8Array(pooledBuffer);
|
||||
* const typedArray2 = new Float64Array(pooledBuffer);
|
||||
*
|
||||
* markAsUntransferable(pooledBuffer);
|
||||
*
|
||||
* const { port1 } = new MessageChannel();
|
||||
* try {
|
||||
* // This will throw an error, because pooledBuffer is not transferable.
|
||||
* port1.postMessage(typedArray1, [ typedArray1.buffer ]);
|
||||
* } catch (error) {
|
||||
* // error.name === 'DataCloneError'
|
||||
* }
|
||||
*
|
||||
* // The following line prints the contents of typedArray1 -- it still owns
|
||||
* // its memory and has not been transferred. Without
|
||||
* // `markAsUntransferable()`, this would print an empty Uint8Array and the
|
||||
* // postMessage call would have succeeded.
|
||||
* // typedArray2 is intact as well.
|
||||
* console.log(typedArray1);
|
||||
* console.log(typedArray2);
|
||||
* ```
|
||||
*
|
||||
* There is no equivalent to this API in browsers.
|
||||
* @since v14.5.0, v12.19.0
|
||||
*/
|
||||
function markAsUntransferable(object: object): void;
|
||||
/**
|
||||
* Check if an object is marked as not transferable with
|
||||
* {@link markAsUntransferable}.
|
||||
* @since v21.0.0
|
||||
*/
|
||||
function isMarkedAsUntransferable(object: object): boolean;
|
||||
/**
|
||||
* Mark an object as not cloneable. If `object` is used as `message` in
|
||||
* a `port.postMessage()` call, an error is thrown. This is a no-op if `object` is a
|
||||
* primitive value.
|
||||
*
|
||||
* This has no effect on `ArrayBuffer`, or any `Buffer` like objects.
|
||||
*
|
||||
* This operation cannot be undone.
|
||||
*
|
||||
* ```js
|
||||
* const { markAsUncloneable } = require('node:worker_threads');
|
||||
*
|
||||
* const anyObject = { foo: 'bar' };
|
||||
* markAsUncloneable(anyObject);
|
||||
* const { port1 } = new MessageChannel();
|
||||
* try {
|
||||
* // This will throw an error, because anyObject is not cloneable.
|
||||
* port1.postMessage(anyObject)
|
||||
* } catch (error) {
|
||||
* // error.name === 'DataCloneError'
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* There is no equivalent to this API in browsers.
|
||||
* @since v22.10.0
|
||||
*/
|
||||
function markAsUncloneable(object: object): void;
|
||||
/**
|
||||
* Transfer a `MessagePort` to a different `vm` Context. The original `port` object is rendered unusable, and the returned `MessagePort` instance
|
||||
* takes its place.
|
||||
*
|
||||
* The returned `MessagePort` is an object in the target context and
|
||||
* inherits from its global `Object` class. Objects passed to the [`port.onmessage()`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/onmessage) listener are also created in the
|
||||
* target context
|
||||
* and inherit from its global `Object` class.
|
||||
*
|
||||
* However, the created `MessagePort` no longer inherits from [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget), and only
|
||||
* [`port.onmessage()`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/onmessage) can be used to receive
|
||||
* events using it.
|
||||
* @since v11.13.0
|
||||
* @param port The message port to transfer.
|
||||
* @param contextifiedSandbox A `contextified` object as returned by the `vm.createContext()` method.
|
||||
*/
|
||||
function moveMessagePortToContext(port: MessagePort, contextifiedSandbox: Context): MessagePort;
|
||||
/**
|
||||
* Receive a single message from a given `MessagePort`. If no message is available,`undefined` is returned, otherwise an object with a single `message` property
|
||||
* that contains the message payload, corresponding to the oldest message in the `MessagePort`'s queue.
|
||||
*
|
||||
* ```js
|
||||
* import { MessageChannel, receiveMessageOnPort } from 'node:worker_threads';
|
||||
* const { port1, port2 } = new MessageChannel();
|
||||
* port1.postMessage({ hello: 'world' });
|
||||
*
|
||||
* console.log(receiveMessageOnPort(port2));
|
||||
* // Prints: { message: { hello: 'world' } }
|
||||
* console.log(receiveMessageOnPort(port2));
|
||||
* // Prints: undefined
|
||||
* ```
|
||||
*
|
||||
* When this function is used, no `'message'` event is emitted and the `onmessage` listener is not invoked.
|
||||
* @since v12.3.0
|
||||
*/
|
||||
function receiveMessageOnPort(port: MessagePort):
|
||||
| {
|
||||
message: any;
|
||||
}
|
||||
| undefined;
|
||||
type Serializable = string | object | number | boolean | bigint;
|
||||
/**
|
||||
* Within a worker thread, `worker.getEnvironmentData()` returns a clone
|
||||
* of data passed to the spawning thread's `worker.setEnvironmentData()`.
|
||||
* Every new `Worker` receives its own copy of the environment data
|
||||
* automatically.
|
||||
*
|
||||
* ```js
|
||||
* import {
|
||||
* Worker,
|
||||
* isMainThread,
|
||||
* setEnvironmentData,
|
||||
* getEnvironmentData,
|
||||
* } from 'node:worker_threads';
|
||||
*
|
||||
* if (isMainThread) {
|
||||
* setEnvironmentData('Hello', 'World!');
|
||||
* const worker = new Worker(__filename);
|
||||
* } else {
|
||||
* console.log(getEnvironmentData('Hello')); // Prints 'World!'.
|
||||
* }
|
||||
* ```
|
||||
* @since v15.12.0, v14.18.0
|
||||
* @param key Any arbitrary, cloneable JavaScript value that can be used as a {Map} key.
|
||||
*/
|
||||
function getEnvironmentData(key: Serializable): Serializable;
|
||||
/**
|
||||
* The `worker.setEnvironmentData()` API sets the content of `worker.getEnvironmentData()` in the current thread and all new `Worker` instances spawned from the current context.
|
||||
* @since v15.12.0, v14.18.0
|
||||
* @param key Any arbitrary, cloneable JavaScript value that can be used as a {Map} key.
|
||||
* @param value Any arbitrary, cloneable JavaScript value that will be cloned and passed automatically to all new `Worker` instances. If `value` is passed as `undefined`, any previously set value
|
||||
* for the `key` will be deleted.
|
||||
*/
|
||||
function setEnvironmentData(key: Serializable, value?: Serializable): void;
|
||||
/**
|
||||
* Sends a value to another worker, identified by its thread ID.
|
||||
* @param threadId The target thread ID. If the thread ID is invalid, a `ERR_WORKER_MESSAGING_FAILED` error will be thrown.
|
||||
* If the target thread ID is the current thread ID, a `ERR_WORKER_MESSAGING_SAME_THREAD` error will be thrown.
|
||||
* @param value The value to send.
|
||||
* @param transferList If one or more `MessagePort`-like objects are passed in value, a `transferList` is required for those items
|
||||
* or `ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST` is thrown. See `port.postMessage()` for more information.
|
||||
* @param timeout Time to wait for the message to be delivered in milliseconds. By default it's `undefined`, which means wait forever.
|
||||
* If the operation times out, a `ERR_WORKER_MESSAGING_TIMEOUT` error is thrown.
|
||||
* @since v22.5.0
|
||||
*/
|
||||
function postMessageToThread(threadId: number, value: any, timeout?: number): Promise<void>;
|
||||
function postMessageToThread(
|
||||
threadId: number,
|
||||
value: any,
|
||||
transferList: readonly Transferable[],
|
||||
timeout?: number,
|
||||
): Promise<void>;
|
||||
// #region web types
|
||||
type LockMode = "exclusive" | "shared";
|
||||
type Transferable =
|
||||
| ArrayBuffer
|
||||
| MessagePort
|
||||
| AbortSignal
|
||||
| FileHandle
|
||||
| ReadableStream
|
||||
| WritableStream
|
||||
| TransformStream;
|
||||
interface LockGrantedCallback<T> {
|
||||
(lock: Lock | null): T;
|
||||
}
|
||||
interface LockInfo {
|
||||
clientId: string;
|
||||
mode: LockMode;
|
||||
name: string;
|
||||
}
|
||||
interface LockManagerSnapshot {
|
||||
held: LockInfo[];
|
||||
pending: LockInfo[];
|
||||
}
|
||||
interface LockOptions {
|
||||
ifAvailable?: boolean;
|
||||
mode?: LockMode;
|
||||
signal?: AbortSignal;
|
||||
steal?: boolean;
|
||||
}
|
||||
interface StructuredSerializeOptions {
|
||||
transfer?: Transferable[];
|
||||
}
|
||||
interface BroadcastChannelEventMap {
|
||||
"message": MessageEvent;
|
||||
"messageerror": MessageEvent;
|
||||
}
|
||||
interface BroadcastChannel
|
||||
extends EventTarget, InternalEventTargetEventProperties<BroadcastChannelEventMap>, NodeJS.RefCounted
|
||||
{
|
||||
readonly name: string;
|
||||
close(): void;
|
||||
postMessage(message: any): void;
|
||||
addEventListener<K extends keyof BroadcastChannelEventMap>(
|
||||
type: K,
|
||||
listener: (ev: BroadcastChannelEventMap[K]) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListener | EventListenerObject,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
removeEventListener<K extends keyof BroadcastChannelEventMap>(
|
||||
type: K,
|
||||
listener: (ev: BroadcastChannelEventMap[K]) => void,
|
||||
options?: EventListenerOptions | boolean,
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListener | EventListenerObject,
|
||||
options?: EventListenerOptions | boolean,
|
||||
): void;
|
||||
}
|
||||
var BroadcastChannel: {
|
||||
prototype: BroadcastChannel;
|
||||
new(name: string): BroadcastChannel;
|
||||
};
|
||||
interface Lock {
|
||||
readonly mode: LockMode;
|
||||
readonly name: string;
|
||||
}
|
||||
// var Lock: {
|
||||
// prototype: Lock;
|
||||
// new(): Lock;
|
||||
// };
|
||||
interface LockManager {
|
||||
query(): Promise<LockManagerSnapshot>;
|
||||
request<T>(name: string, callback: LockGrantedCallback<T>): Promise<Awaited<T>>;
|
||||
request<T>(name: string, options: LockOptions, callback: LockGrantedCallback<T>): Promise<Awaited<T>>;
|
||||
}
|
||||
// var LockManager: {
|
||||
// prototype: LockManager;
|
||||
// new(): LockManager;
|
||||
// };
|
||||
interface MessageChannel {
|
||||
readonly port1: MessagePort;
|
||||
readonly port2: MessagePort;
|
||||
}
|
||||
var MessageChannel: {
|
||||
prototype: MessageChannel;
|
||||
new(): MessageChannel;
|
||||
};
|
||||
interface MessagePortEventMap {
|
||||
"close": Event;
|
||||
"message": MessageEvent;
|
||||
"messageerror": MessageEvent;
|
||||
}
|
||||
interface MessagePort extends NodeEventTarget, InternalEventTargetEventProperties<MessagePortEventMap> {
|
||||
close(): void;
|
||||
postMessage(message: any, transfer: Transferable[]): void;
|
||||
postMessage(message: any, options?: StructuredSerializeOptions): void;
|
||||
start(): void;
|
||||
hasRef(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
addEventListener<K extends keyof MessagePortEventMap>(
|
||||
type: K,
|
||||
listener: (ev: MessagePortEventMap[K]) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListener | EventListenerObject,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
removeEventListener<K extends keyof MessagePortEventMap>(
|
||||
type: K,
|
||||
listener: (ev: MessagePortEventMap[K]) => void,
|
||||
options?: EventListenerOptions | boolean,
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListener | EventListenerObject,
|
||||
options?: EventListenerOptions | boolean,
|
||||
): void;
|
||||
// #region NodeEventTarget
|
||||
addListener(event: "close", listener: (ev: Event) => void): this;
|
||||
addListener(event: "message", listener: (value: any) => void): this;
|
||||
addListener(event: "messageerror", listener: (error: Error) => void): this;
|
||||
addListener(event: string, listener: (arg: any) => void): this;
|
||||
emit(event: "close", ev: Event): boolean;
|
||||
emit(event: "message", value: any): boolean;
|
||||
emit(event: "messageerror", error: Error): boolean;
|
||||
emit(event: string, arg: any): boolean;
|
||||
off(event: "close", listener: (ev: Event) => void, options?: EventListenerOptions): this;
|
||||
off(event: "message", listener: (value: any) => void, options?: EventListenerOptions): this;
|
||||
off(event: "messageerror", listener: (error: Error) => void, options?: EventListenerOptions): this;
|
||||
off(event: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
|
||||
on(event: "close", listener: (ev: Event) => void): this;
|
||||
on(event: "message", listener: (value: any) => void): this;
|
||||
on(event: "messageerror", listener: (error: Error) => void): this;
|
||||
on(event: string, listener: (arg: any) => void): this;
|
||||
once(event: "close", listener: (ev: Event) => void): this;
|
||||
once(event: "message", listener: (value: any) => void): this;
|
||||
once(event: "messageerror", listener: (error: Error) => void): this;
|
||||
once(event: string, listener: (arg: any) => void): this;
|
||||
removeListener(event: "close", listener: (ev: Event) => void, options?: EventListenerOptions): this;
|
||||
removeListener(event: "message", listener: (value: any) => void, options?: EventListenerOptions): this;
|
||||
removeListener(event: "messageerror", listener: (error: Error) => void, options?: EventListenerOptions): this;
|
||||
removeListener(event: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
|
||||
// #endregion
|
||||
}
|
||||
var MessagePort: {
|
||||
prototype: MessagePort;
|
||||
new(): MessagePort;
|
||||
};
|
||||
var locks: LockManager;
|
||||
export import structuredClone = globalThis.structuredClone;
|
||||
// #endregion
|
||||
}
|
||||
declare module "worker_threads" {
|
||||
export * from "node:worker_threads";
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"sourceFileCache.d.ts","sourceRoot":"","sources":["../../src/api/sourceFileCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,IAAI,EACJ,UAAU,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,oCAAoC;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAe;IACxB,wDAAwD;IACxD,OAAO,CAAC,KAAK,CAA4C;IACzD,qFAAqF;IACrF,OAAO,CAAC,oBAAoB,CAAkD;IAE9E;;;;;;;;OAQG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAQtF;;;OAGG;IACH,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU;IAmBlI;;;;;;OAMG;IACH,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI;IAmChH;;;;OAIG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAsBzC,OAAO,CAAC,SAAS;IAcjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;CAG3B"}
|
||||
@@ -0,0 +1,144 @@
|
||||
//#region src/utils.ts
|
||||
/**
|
||||
* Coerce `value`.
|
||||
*/
|
||||
function coerce(value) {
|
||||
if (value instanceof Error) return value.stack || value.message;
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Selects a color for a debug namespace
|
||||
* @return An ANSI color code for the given namespace
|
||||
*/
|
||||
function selectColor(colors, namespace) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < namespace.length; i++) {
|
||||
hash = (hash << 5) - hash + namespace.charCodeAt(i);
|
||||
hash |= 0;
|
||||
}
|
||||
return colors[Math.abs(hash) % colors.length];
|
||||
}
|
||||
/**
|
||||
* Checks if the given string matches a namespace template, honoring
|
||||
* asterisks as wildcards.
|
||||
*/
|
||||
function matchesTemplate(search, template) {
|
||||
let searchIndex = 0;
|
||||
let templateIndex = 0;
|
||||
let starIndex = -1;
|
||||
let matchIndex = 0;
|
||||
while (searchIndex < search.length) if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) if (template[templateIndex] === "*") {
|
||||
starIndex = templateIndex;
|
||||
matchIndex = searchIndex;
|
||||
templateIndex++;
|
||||
} else {
|
||||
searchIndex++;
|
||||
templateIndex++;
|
||||
}
|
||||
else if (starIndex !== -1) {
|
||||
templateIndex = starIndex + 1;
|
||||
matchIndex++;
|
||||
searchIndex = matchIndex;
|
||||
} else return false;
|
||||
while (templateIndex < template.length && template[templateIndex] === "*") templateIndex++;
|
||||
return templateIndex === template.length;
|
||||
}
|
||||
function humanize(value) {
|
||||
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}s`;
|
||||
return `${value}ms`;
|
||||
}
|
||||
//#endregion
|
||||
//#region src/core.ts
|
||||
let globalNamespaces = "";
|
||||
/**
|
||||
* Returns a string of the currently enabled debug namespaces.
|
||||
*/
|
||||
function namespaces() {
|
||||
return globalNamespaces;
|
||||
}
|
||||
function createDebug(namespace, options) {
|
||||
let prevTime;
|
||||
let enableOverride;
|
||||
let namespacesCache;
|
||||
let enabledCache;
|
||||
const debug = (...args) => {
|
||||
if (!debug.enabled) return;
|
||||
const curr = Date.now();
|
||||
const diff = curr - (prevTime || curr);
|
||||
prevTime = curr;
|
||||
args[0] = coerce(args[0]);
|
||||
if (typeof args[0] !== "string") args.unshift("%O");
|
||||
let index = 0;
|
||||
args[0] = args[0].replace(/%([a-z%])/gi, (match, format) => {
|
||||
if (match === "%%") return "%";
|
||||
index++;
|
||||
const formatter = options.formatters[format];
|
||||
if (typeof formatter === "function") {
|
||||
const value = args[index];
|
||||
match = formatter.call(debug, value);
|
||||
args.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
options.formatArgs.call(debug, diff, args);
|
||||
debug.log(...args);
|
||||
};
|
||||
debug.extend = function(namespace, delimiter = ":") {
|
||||
return createDebug(this.namespace + delimiter + namespace, {
|
||||
useColors: this.useColors,
|
||||
color: this.color,
|
||||
formatArgs: this.formatArgs,
|
||||
formatters: this.formatters,
|
||||
inspectOpts: this.inspectOpts,
|
||||
log: this.log,
|
||||
humanize: this.humanize
|
||||
});
|
||||
};
|
||||
Object.assign(debug, options);
|
||||
debug.namespace = namespace;
|
||||
Object.defineProperty(debug, "enabled", {
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
get: () => {
|
||||
if (enableOverride != null) return enableOverride;
|
||||
if (namespacesCache !== globalNamespaces) {
|
||||
namespacesCache = globalNamespaces;
|
||||
enabledCache = enabled(namespace);
|
||||
}
|
||||
return enabledCache;
|
||||
},
|
||||
set: (v) => {
|
||||
enableOverride = v;
|
||||
}
|
||||
});
|
||||
return debug;
|
||||
}
|
||||
let names = [];
|
||||
let skips = [];
|
||||
function enable(namespaces) {
|
||||
globalNamespaces = namespaces;
|
||||
names = [];
|
||||
skips = [];
|
||||
const split = globalNamespaces.trim().replace(/\s+/g, ",").split(",").filter(Boolean);
|
||||
for (const ns of split) if (ns[0] === "-") skips.push(ns.slice(1));
|
||||
else names.push(ns);
|
||||
}
|
||||
/**
|
||||
* Disable debug output.
|
||||
*/
|
||||
function disable() {
|
||||
const namespaces = [...names, ...skips.map((namespace) => `-${namespace}`)].join(",");
|
||||
enable("");
|
||||
return namespaces;
|
||||
}
|
||||
/**
|
||||
* Returns true if the given mode name is enabled, false otherwise.
|
||||
*/
|
||||
function enabled(name) {
|
||||
for (const skip of skips) if (matchesTemplate(name, skip)) return false;
|
||||
for (const ns of names) if (matchesTemplate(name, ns)) return true;
|
||||
return false;
|
||||
}
|
||||
//#endregion
|
||||
export { namespaces as a, enabled as i, disable as n, humanize as o, enable as r, selectColor as s, createDebug as t };
|
||||
@@ -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.es2025_full = void 0;
|
||||
const dom_1 = require("./dom");
|
||||
const dom_asynciterable_1 = require("./dom.asynciterable");
|
||||
const dom_iterable_1 = require("./dom.iterable");
|
||||
const es2025_1 = require("./es2025");
|
||||
const scripthost_1 = require("./scripthost");
|
||||
const webworker_importscripts_1 = require("./webworker.importscripts");
|
||||
exports.es2025_full = {
|
||||
libs: [
|
||||
es2025_1.es2025,
|
||||
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,9 @@
|
||||
var get = require("./get.js");
|
||||
var getPrototypeOf = require("./getPrototypeOf.js");
|
||||
function _superPropGet(t, o, e, r) {
|
||||
var p = get(getPrototypeOf(1 & r ? t.prototype : t), o, e);
|
||||
return 2 & r && "function" == typeof p ? function (t) {
|
||||
return p.apply(e, t);
|
||||
} : p;
|
||||
}
|
||||
module.exports = _superPropGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// SEE https://typescript-eslint.io/users/configs
|
||||
//
|
||||
// For developers working in the typescript-eslint monorepo:
|
||||
// You can regenerate it using `pnpm run generate-configs`
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const base_1 = __importDefault(require("./base"));
|
||||
const eslint_recommended_1 = __importDefault(require("./eslint-recommended"));
|
||||
/**
|
||||
* A version of `recommended` that only contains type-checked rules and disables of any corresponding core ESLint rules.
|
||||
* @see {@link https://typescript-eslint.io/users/configs#recommended-type-checked-only}
|
||||
*/
|
||||
exports.default = (plugin, parser) => [
|
||||
(0, base_1.default)(plugin, parser),
|
||||
(0, eslint_recommended_1.default)(plugin, parser),
|
||||
{
|
||||
name: 'typescript-eslint/recommended-type-checked-only',
|
||||
rules: {
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/no-array-delete': 'error',
|
||||
'@typescript-eslint/no-base-to-string': 'error',
|
||||
'@typescript-eslint/no-duplicate-type-constituents': 'error',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-for-in-array': 'error',
|
||||
'no-implied-eval': 'off',
|
||||
'@typescript-eslint/no-implied-eval': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||
'@typescript-eslint/no-unsafe-argument': 'error',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'error',
|
||||
'@typescript-eslint/no-unsafe-call': 'error',
|
||||
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'error',
|
||||
'@typescript-eslint/no-unsafe-return': 'error',
|
||||
'@typescript-eslint/no-unsafe-unary-minus': 'error',
|
||||
'no-throw-literal': 'off',
|
||||
'@typescript-eslint/only-throw-error': 'error',
|
||||
'prefer-promise-reject-errors': 'off',
|
||||
'@typescript-eslint/prefer-promise-reject-errors': 'error',
|
||||
'require-await': 'off',
|
||||
'@typescript-eslint/require-await': 'error',
|
||||
'@typescript-eslint/restrict-plus-operands': 'error',
|
||||
'@typescript-eslint/restrict-template-expressions': 'error',
|
||||
'@typescript-eslint/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
declare const versions: readonly ['4.7', '4.8', '4.9', '5.0', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6', '5.7', '5.8', '5.9', '6.0'];
|
||||
type Versions = typeof versions extends ArrayLike<infer U> ? U : never;
|
||||
export declare const typescriptVersionIsAtLeast: Record<Versions, boolean>;
|
||||
export {};
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @fileoverview Warn when using template string syntax in regular strings
|
||||
* @author Jeroen Engels
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow template literal placeholder syntax in regular strings",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-template-curly-in-string",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
unexpectedTemplateExpression:
|
||||
"Unexpected template string expression.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const regex = /\$\{[^}]+\}/u;
|
||||
|
||||
return {
|
||||
Literal(node) {
|
||||
if (typeof node.value === "string" && regex.test(node.value)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedTemplateExpression",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('node:test')
|
||||
const proxyquire = require('proxyquire')
|
||||
const tspl = require('@matteo.collina/tspl')
|
||||
|
||||
test('should import', async (t) => {
|
||||
const plan = tspl(t, { plan: 2 })
|
||||
const mockRealRequire = (target) => {
|
||||
return {
|
||||
default: {
|
||||
default: () => {
|
||||
plan.equal(target, 'pino-pretty')
|
||||
return Promise.resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const mockRealImport = async () => {
|
||||
await Promise.resolve()
|
||||
throw Object.assign(new Error(), { code: 'ERR_MODULE_NOT_FOUND' })
|
||||
}
|
||||
|
||||
const loadTransportStreamBuilder = proxyquire(
|
||||
'../lib/transport-stream.js',
|
||||
{
|
||||
'real-require': {
|
||||
realRequire: mockRealRequire,
|
||||
realImport: mockRealImport
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const fn = await loadTransportStreamBuilder('pino-pretty')
|
||||
|
||||
await fn()
|
||||
plan.ok('returned promise resolved')
|
||||
|
||||
await plan
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.applyDefault = applyDefault;
|
||||
const deepMerge_1 = require("./deepMerge");
|
||||
/**
|
||||
* Pure function - doesn't mutate either parameter!
|
||||
* Uses the default options and overrides with the options provided by the user
|
||||
* @param defaultOptions the defaults
|
||||
* @param userOptions the user opts
|
||||
* @returns the options with defaults
|
||||
*/
|
||||
function applyDefault(defaultOptions, userOptions) {
|
||||
// clone defaults
|
||||
const options = structuredClone(defaultOptions);
|
||||
if (userOptions == null) {
|
||||
return options;
|
||||
}
|
||||
// For avoiding the type error
|
||||
// `This expression is not callable. Type 'unknown' has no call signatures.ts(2349)`
|
||||
options.forEach((opt, i) => {
|
||||
// eslint-disable-next-line @typescript-eslint/internal/eqeq-nullish
|
||||
if (userOptions[i] !== undefined) {
|
||||
const userOpt = userOptions[i];
|
||||
if ((0, deepMerge_1.isObjectNotArray)(userOpt) && (0, deepMerge_1.isObjectNotArray)(opt)) {
|
||||
options[i] = (0, deepMerge_1.deepMerge)(opt, userOpt);
|
||||
}
|
||||
else {
|
||||
options[i] = userOpt;
|
||||
}
|
||||
}
|
||||
});
|
||||
return options;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
import { FileSpecification, Task, CancelReason } from '@vitest/runner';
|
||||
import { EvaluatedModules } from 'vite/module-runner';
|
||||
import { S as SerializedConfig } from './config.d.A1h_Y6Jt.js';
|
||||
import { E as Environment } from './environment.d.CrsxCzP1.js';
|
||||
import { R as RuntimeRPC, a as RunnerRPC } from './rpc.d.B_8sPU0w.js';
|
||||
|
||||
//#region src/messages.d.ts
|
||||
declare const TYPE_REQUEST: "q";
|
||||
interface RpcRequest {
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
t: typeof TYPE_REQUEST;
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
i?: string;
|
||||
/**
|
||||
* Method
|
||||
*/
|
||||
m: string;
|
||||
/**
|
||||
* Arguments
|
||||
*/
|
||||
a: any[];
|
||||
/**
|
||||
* Optional
|
||||
*/
|
||||
o?: boolean;
|
||||
}
|
||||
//#endregion
|
||||
//#region src/utils.d.ts
|
||||
type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never;
|
||||
type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never;
|
||||
type Thenable<T> = T | PromiseLike<T>;
|
||||
//#endregion
|
||||
//#region src/main.d.ts
|
||||
type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>;
|
||||
type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>;
|
||||
interface ChannelOptions {
|
||||
/**
|
||||
* Function to post raw message
|
||||
*/
|
||||
post: (data: any, ...extras: any[]) => Thenable<any>;
|
||||
/**
|
||||
* Listener to receive raw message
|
||||
*/
|
||||
on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
|
||||
/**
|
||||
* Clear the listener when `$close` is called
|
||||
*/
|
||||
off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
|
||||
/**
|
||||
* Custom function to serialize data
|
||||
*
|
||||
* by default it passes the data as-is
|
||||
*/
|
||||
serialize?: (data: any) => any;
|
||||
/**
|
||||
* Custom function to deserialize data
|
||||
*
|
||||
* by default it passes the data as-is
|
||||
*/
|
||||
deserialize?: (data: any) => any;
|
||||
/**
|
||||
* Call the methods with the RPC context or the original functions object
|
||||
*/
|
||||
bind?: 'rpc' | 'functions';
|
||||
/**
|
||||
* Custom meta data to attached to the RPC instance's `$meta` property
|
||||
*/
|
||||
meta?: any;
|
||||
}
|
||||
interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> {
|
||||
/**
|
||||
* Names of remote functions that do not need response.
|
||||
*/
|
||||
eventNames?: (keyof RemoteFunctions)[];
|
||||
/**
|
||||
* Maximum timeout for waiting for response, in milliseconds.
|
||||
*
|
||||
* @default 60_000
|
||||
*/
|
||||
timeout?: number;
|
||||
/**
|
||||
* Whether to proxy the remote functions.
|
||||
*
|
||||
* When `proxify` is false, calling the remote function
|
||||
* with `rpc.$call('method', ...args)` instead of `rpc.method(...args)`
|
||||
* explicitly is required.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
proxify?: Proxify;
|
||||
/**
|
||||
* Custom resolver to resolve function to be called
|
||||
*
|
||||
* For advanced use cases only
|
||||
*/
|
||||
resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>;
|
||||
/**
|
||||
* Hook triggered before an event is sent to the remote
|
||||
*
|
||||
* @param req - Request parameters
|
||||
* @param next - Function to continue the request
|
||||
* @param resolve - Function to resolve the response directly
|
||||
*/
|
||||
onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>;
|
||||
/**
|
||||
* Custom error handler for errors occurred in local functions being called
|
||||
*
|
||||
* @returns `true` to prevent the error from being thrown
|
||||
*/
|
||||
onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void;
|
||||
/**
|
||||
* Custom error handler for errors occurred during serialization or messsaging
|
||||
*
|
||||
* @returns `true` to prevent the error from being thrown
|
||||
*/
|
||||
onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void;
|
||||
/**
|
||||
* Custom error handler for timeouts
|
||||
*
|
||||
* @returns `true` to prevent the error from being thrown
|
||||
*/
|
||||
onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void;
|
||||
}
|
||||
type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions;
|
||||
type BirpcFn<T> = PromisifyFn<T> & {
|
||||
/**
|
||||
* Send event without asking for response
|
||||
*/
|
||||
asEvent: (...args: ArgumentsType<T>) => Promise<void>;
|
||||
};
|
||||
interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> {
|
||||
/**
|
||||
* Raw functions object
|
||||
*/
|
||||
$functions: LocalFunctions;
|
||||
/**
|
||||
* Whether the RPC is closed
|
||||
*/
|
||||
readonly $closed: boolean;
|
||||
/**
|
||||
* Custom meta data attached to the RPC instance
|
||||
*/
|
||||
readonly $meta: any;
|
||||
/**
|
||||
* Close the RPC connection
|
||||
*/
|
||||
$close: (error?: Error) => void;
|
||||
/**
|
||||
* Reject pending calls
|
||||
*/
|
||||
$rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[];
|
||||
/**
|
||||
* Call the remote function and wait for the result.
|
||||
* An alternative to directly calling the function
|
||||
*/
|
||||
$call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>;
|
||||
/**
|
||||
* Same as `$call`, but returns `undefined` if the function is not defined on the remote side.
|
||||
*/
|
||||
$callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>;
|
||||
/**
|
||||
* Send event without asking for response
|
||||
*/
|
||||
$callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>;
|
||||
/**
|
||||
* Call the remote function with the raw options.
|
||||
*/
|
||||
$callRaw: (options: {
|
||||
method: string;
|
||||
args: unknown[];
|
||||
event?: boolean;
|
||||
optional?: boolean;
|
||||
}) => Promise<Awaited<ReturnType<any>>[]>;
|
||||
}
|
||||
type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> };
|
||||
type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>;
|
||||
type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>;
|
||||
interface PromiseEntry {
|
||||
resolve: (arg: any) => void;
|
||||
reject: (error: any) => void;
|
||||
method: string;
|
||||
timeoutId?: ReturnType<typeof setTimeout>;
|
||||
}
|
||||
declare const setTimeout: typeof globalThis.setTimeout;
|
||||
|
||||
type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>;
|
||||
interface ContextTestEnvironment {
|
||||
name: string;
|
||||
options: Record<string, any> | null;
|
||||
}
|
||||
interface WorkerTestEnvironment {
|
||||
name: string;
|
||||
options: Record<string, any> | null;
|
||||
}
|
||||
type TestExecutionMethod = "run" | "collect";
|
||||
interface WorkerExecuteContext {
|
||||
files: FileSpecification[];
|
||||
providedContext: Record<string, any>;
|
||||
invalidates?: string[];
|
||||
environment: ContextTestEnvironment;
|
||||
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
|
||||
workerId: number;
|
||||
}
|
||||
interface ContextRPC {
|
||||
pool: string;
|
||||
config: SerializedConfig;
|
||||
projectName: string;
|
||||
environment: WorkerTestEnvironment;
|
||||
rpc: WorkerRPC;
|
||||
files: FileSpecification[];
|
||||
providedContext: Record<string, any>;
|
||||
invalidates?: string[];
|
||||
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
|
||||
workerId: number;
|
||||
}
|
||||
interface WorkerSetupContext {
|
||||
environment: WorkerTestEnvironment;
|
||||
pool: string;
|
||||
config: SerializedConfig;
|
||||
projectName: string;
|
||||
rpc: WorkerRPC;
|
||||
}
|
||||
interface WorkerGlobalState {
|
||||
ctx: ContextRPC;
|
||||
config: SerializedConfig;
|
||||
rpc: WorkerRPC;
|
||||
current?: Task;
|
||||
filepath?: string;
|
||||
metaEnv: {
|
||||
[key: string]: any;
|
||||
BASE_URL: string;
|
||||
MODE: string;
|
||||
DEV: boolean;
|
||||
PROD: boolean;
|
||||
SSR: boolean;
|
||||
};
|
||||
environment: Environment;
|
||||
evaluatedModules: EvaluatedModules;
|
||||
resolvingModules: Set<string>;
|
||||
moduleExecutionInfo: Map<string, any>;
|
||||
onCancel: (listener: (reason: CancelReason) => unknown) => void;
|
||||
onCleanup: (listener: () => unknown) => void;
|
||||
providedContext: Record<string, any>;
|
||||
durations: {
|
||||
environment: number;
|
||||
prepare: number;
|
||||
};
|
||||
onFilterStackTrace?: (trace: string) => string;
|
||||
}
|
||||
|
||||
export type { BirpcOptions as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, WorkerSetupContext as a, BirpcReturn as b, ContextTestEnvironment as c, WorkerExecuteContext as d, WorkerTestEnvironment as e };
|
||||
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Internal module for NIST P256, P384, P521 curves.
|
||||
* Do not use for now.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256, sha384, sha512 } from '@noble/hashes/sha2.js';
|
||||
import { createCurve, type CurveFnWithCreate } from './_shortw_utils.ts';
|
||||
import { createHasher, type H2CHasher } from './abstract/hash-to-curve.ts';
|
||||
import { Field } from './abstract/modular.ts';
|
||||
import {
|
||||
mapToCurveSimpleSWU,
|
||||
type WeierstrassOpts,
|
||||
type WeierstrassPointCons,
|
||||
} from './abstract/weierstrass.ts';
|
||||
|
||||
// p = 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n - 1n
|
||||
// a = Fp256.create(BigInt('-3'));
|
||||
const p256_CURVE: WeierstrassOpts<bigint> = {
|
||||
p: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
|
||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||
h: BigInt(1),
|
||||
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
|
||||
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
|
||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||
};
|
||||
|
||||
// p = 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||
const p384_CURVE: WeierstrassOpts<bigint> = {
|
||||
p: BigInt(
|
||||
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff'
|
||||
),
|
||||
n: BigInt(
|
||||
'0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'
|
||||
),
|
||||
h: BigInt(1),
|
||||
a: BigInt(
|
||||
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc'
|
||||
),
|
||||
b: BigInt(
|
||||
'0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef'
|
||||
),
|
||||
Gx: BigInt(
|
||||
'0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'
|
||||
),
|
||||
Gy: BigInt(
|
||||
'0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'
|
||||
),
|
||||
};
|
||||
|
||||
// p = 2n**521n - 1n
|
||||
const p521_CURVE: WeierstrassOpts<bigint> = {
|
||||
p: BigInt(
|
||||
'0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
||||
),
|
||||
n: BigInt(
|
||||
'0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'
|
||||
),
|
||||
h: BigInt(1),
|
||||
a: BigInt(
|
||||
'0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc'
|
||||
),
|
||||
b: BigInt(
|
||||
'0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'
|
||||
),
|
||||
Gx: BigInt(
|
||||
'0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'
|
||||
),
|
||||
Gy: BigInt(
|
||||
'0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'
|
||||
),
|
||||
};
|
||||
|
||||
const Fp256 = Field(p256_CURVE.p);
|
||||
const Fp384 = Field(p384_CURVE.p);
|
||||
const Fp521 = Field(p521_CURVE.p);
|
||||
type SwuOpts = {
|
||||
A: bigint;
|
||||
B: bigint;
|
||||
Z: bigint;
|
||||
};
|
||||
function createSWU(Point: WeierstrassPointCons<bigint>, opts: SwuOpts) {
|
||||
const map = mapToCurveSimpleSWU(Point.Fp, opts);
|
||||
return (scalars: bigint[]) => map(scalars[0]);
|
||||
}
|
||||
|
||||
/** NIST P256 (aka secp256r1, prime256v1) curve, ECDSA and ECDH methods. */
|
||||
export const p256: CurveFnWithCreate = createCurve(
|
||||
{ ...p256_CURVE, Fp: Fp256, lowS: false },
|
||||
sha256
|
||||
);
|
||||
/** Hashing / encoding to p256 points / field. RFC 9380 methods. */
|
||||
export const p256_hasher: H2CHasher<bigint> = /* @__PURE__ */ (() => {
|
||||
return createHasher(
|
||||
p256.Point,
|
||||
createSWU(p256.Point, {
|
||||
A: p256_CURVE.a,
|
||||
B: p256_CURVE.b,
|
||||
Z: p256.Point.Fp.create(BigInt('-10')),
|
||||
}),
|
||||
{
|
||||
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
||||
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
|
||||
p: p256_CURVE.p,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
// export const p256_oprf: OPRF = createORPF({
|
||||
// name: 'P256-SHA256',
|
||||
// Point: p256.Point,
|
||||
// hash: sha256,
|
||||
// hashToGroup: p256_hasher.hashToCurve,
|
||||
// hashToScalar: p256_hasher.hashToScalar,
|
||||
// });
|
||||
|
||||
/** NIST P384 (aka secp384r1) curve, ECDSA and ECDH methods. */
|
||||
export const p384: CurveFnWithCreate = createCurve(
|
||||
{ ...p384_CURVE, Fp: Fp384, lowS: false },
|
||||
sha384
|
||||
);
|
||||
/** Hashing / encoding to p384 points / field. RFC 9380 methods. */
|
||||
export const p384_hasher: H2CHasher<bigint> = /* @__PURE__ */ (() => {
|
||||
return createHasher(
|
||||
p384.Point,
|
||||
createSWU(p384.Point, {
|
||||
A: p384_CURVE.a,
|
||||
B: p384_CURVE.b,
|
||||
Z: p384.Point.Fp.create(BigInt('-12')),
|
||||
}),
|
||||
{
|
||||
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
||||
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
|
||||
p: p384_CURVE.p,
|
||||
m: 1,
|
||||
k: 192,
|
||||
expand: 'xmd',
|
||||
hash: sha384,
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
// export const p384_oprf: OPRF = createORPF({
|
||||
// name: 'P384-SHA384',
|
||||
// Point: p384.Point,
|
||||
// hash: sha384,
|
||||
// hashToGroup: p384_hasher.hashToCurve,
|
||||
// hashToScalar: p384_hasher.hashToScalar,
|
||||
// });
|
||||
|
||||
// const Fn521 = Field(p521_CURVE.n, { allowedScalarLengths: [65, 66] });
|
||||
/** NIST P521 (aka secp521r1) curve, ECDSA and ECDH methods. */
|
||||
export const p521: CurveFnWithCreate = createCurve(
|
||||
{ ...p521_CURVE, Fp: Fp521, lowS: false, allowedPrivateKeyLengths: [130, 131, 132] },
|
||||
sha512
|
||||
);
|
||||
|
||||
/** @deprecated use `p256` for consistency with `p256_hasher` */
|
||||
export const secp256r1: typeof p256 = p256;
|
||||
/** @deprecated use `p384` for consistency with `p384_hasher` */
|
||||
export const secp384r1: typeof p384 = p384;
|
||||
/** @deprecated use `p521` for consistency with `p521_hasher` */
|
||||
export const secp521r1: typeof p521 = p521;
|
||||
|
||||
/** Hashing / encoding to p521 points / field. RFC 9380 methods. */
|
||||
export const p521_hasher: H2CHasher<bigint> = /* @__PURE__ */ (() => {
|
||||
return createHasher(
|
||||
p521.Point,
|
||||
createSWU(p521.Point, {
|
||||
A: p521_CURVE.a,
|
||||
B: p521_CURVE.b,
|
||||
Z: p521.Point.Fp.create(BigInt('-4')),
|
||||
}),
|
||||
{
|
||||
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
||||
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
|
||||
p: p521_CURVE.p,
|
||||
m: 1,
|
||||
k: 256,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
// export const p521_oprf: OPRF = createORPF({
|
||||
// name: 'P521-SHA512',
|
||||
// Point: p521.Point,
|
||||
// hash: sha512,
|
||||
// hashToGroup: p521_hasher.hashToCurve,
|
||||
// hashToScalar: p521_hasher.hashToScalar, // produces L=98 just like in RFC
|
||||
// });
|
||||
@@ -0,0 +1,47 @@
|
||||
import { a as SerializedCoverageConfig, S as SerializedConfig } from './chunks/config.d.A1h_Y6Jt.js';
|
||||
import { R as RuntimeCoverageModuleLoader } from './chunks/coverage.d.BZtK59WP.js';
|
||||
import { SerializedDiffOptions } from '@vitest/utils/diff';
|
||||
export { O as OTELCarrier, T as Traces } from './chunks/traces.d.D2T_R8rx.js';
|
||||
export { collectTests, startTests } from '@vitest/runner';
|
||||
import * as _vitest_spy from '@vitest/spy';
|
||||
export { _vitest_spy as SpyModule };
|
||||
export { LoupeOptions, ParsedStack, StringifyOptions } from '@vitest/utils';
|
||||
export { browserFormat, format, inspect, stringify } from '@vitest/utils/display';
|
||||
export { processError } from '@vitest/utils/error';
|
||||
export { getType } from '@vitest/utils/helpers';
|
||||
export { DecodedMap, getOriginalPosition } from '@vitest/utils/source-map';
|
||||
export { getSafeTimers, setSafeTimers } from '@vitest/utils/timers';
|
||||
import '@vitest/pretty-format';
|
||||
import '@vitest/snapshot';
|
||||
|
||||
declare function startCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader, runtimeOptions: {
|
||||
isolate: boolean;
|
||||
}): Promise<unknown>;
|
||||
declare function takeCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader): Promise<unknown>;
|
||||
declare function stopCoverageInsideWorker(options: SerializedCoverageConfig | undefined, loader: RuntimeCoverageModuleLoader, runtimeOptions: {
|
||||
isolate: boolean;
|
||||
}): Promise<unknown>;
|
||||
|
||||
interface PublicModuleRunner {
|
||||
import: (id: string) => Promise<any>;
|
||||
}
|
||||
|
||||
declare function setupCommonEnv(config: SerializedConfig): Promise<void>;
|
||||
declare function loadDiffConfig(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<SerializedDiffOptions | undefined>;
|
||||
declare function loadSnapshotSerializers(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<void>;
|
||||
|
||||
interface FsOptions {
|
||||
encoding?: BufferEncoding;
|
||||
flag?: string | number;
|
||||
}
|
||||
interface BrowserCommands {
|
||||
readFile: (path: string, options?: BufferEncoding | FsOptions) => Promise<string>;
|
||||
writeFile: (path: string, content: string, options?: BufferEncoding | (FsOptions & {
|
||||
mode?: number | string;
|
||||
})) => Promise<void>;
|
||||
removeFile: (path: string) => Promise<void>;
|
||||
}
|
||||
interface CDPSession {}
|
||||
|
||||
export { loadDiffConfig, loadSnapshotSerializers, setupCommonEnv, startCoverageInsideWorker, stopCoverageInsideWorker, takeCoverageInsideWorker };
|
||||
export type { BrowserCommands, CDPSession, FsOptions };
|
||||
@@ -0,0 +1,13 @@
|
||||
export declare enum DefinitionType {
|
||||
CatchClause = "CatchClause",
|
||||
ClassName = "ClassName",
|
||||
FunctionName = "FunctionName",
|
||||
ImplicitGlobalVariable = "ImplicitGlobalVariable",
|
||||
ImportBinding = "ImportBinding",
|
||||
Parameter = "Parameter",
|
||||
TSEnumName = "TSEnumName",
|
||||
TSEnumMember = "TSEnumMemberName",
|
||||
TSModuleName = "TSModuleName",
|
||||
Type = "Type",
|
||||
Variable = "Variable"
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 Near
|
||||
|
||||
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
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,584 @@
|
||||
# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
|
||||
|
||||
[travis-image]: https://img.shields.io/travis/feross/safe-buffer/master.svg
|
||||
[travis-url]: https://travis-ci.org/feross/safe-buffer
|
||||
[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg
|
||||
[npm-url]: https://npmjs.org/package/safe-buffer
|
||||
[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg
|
||||
[downloads-url]: https://npmjs.org/package/safe-buffer
|
||||
[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg
|
||||
[standard-url]: https://standardjs.com
|
||||
|
||||
#### Safer Node.js Buffer API
|
||||
|
||||
**Use the new Node.js Buffer APIs (`Buffer.from`, `Buffer.alloc`,
|
||||
`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in all versions of Node.js.**
|
||||
|
||||
**Uses the built-in implementation when available.**
|
||||
|
||||
## install
|
||||
|
||||
```
|
||||
npm install safe-buffer
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
The goal of this package is to provide a safe replacement for the node.js `Buffer`.
|
||||
|
||||
It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to
|
||||
the top of your node.js modules:
|
||||
|
||||
```js
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
|
||||
// Existing buffer code will continue to work without issues:
|
||||
|
||||
new Buffer('hey', 'utf8')
|
||||
new Buffer([1, 2, 3], 'utf8')
|
||||
new Buffer(obj)
|
||||
new Buffer(16) // create an uninitialized buffer (potentially unsafe)
|
||||
|
||||
// But you can use these new explicit APIs to make clear what you want:
|
||||
|
||||
Buffer.from('hey', 'utf8') // convert from many types to a Buffer
|
||||
Buffer.alloc(16) // create a zero-filled buffer (safe)
|
||||
Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe)
|
||||
```
|
||||
|
||||
## api
|
||||
|
||||
### Class Method: Buffer.from(array)
|
||||
<!-- YAML
|
||||
added: v3.0.0
|
||||
-->
|
||||
|
||||
* `array` {Array}
|
||||
|
||||
Allocates a new `Buffer` using an `array` of octets.
|
||||
|
||||
```js
|
||||
const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]);
|
||||
// creates a new Buffer containing ASCII bytes
|
||||
// ['b','u','f','f','e','r']
|
||||
```
|
||||
|
||||
A `TypeError` will be thrown if `array` is not an `Array`.
|
||||
|
||||
### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])
|
||||
<!-- YAML
|
||||
added: v5.10.0
|
||||
-->
|
||||
|
||||
* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or
|
||||
a `new ArrayBuffer()`
|
||||
* `byteOffset` {Number} Default: `0`
|
||||
* `length` {Number} Default: `arrayBuffer.length - byteOffset`
|
||||
|
||||
When passed a reference to the `.buffer` property of a `TypedArray` instance,
|
||||
the newly created `Buffer` will share the same allocated memory as the
|
||||
TypedArray.
|
||||
|
||||
```js
|
||||
const arr = new Uint16Array(2);
|
||||
arr[0] = 5000;
|
||||
arr[1] = 4000;
|
||||
|
||||
const buf = Buffer.from(arr.buffer); // shares the memory with arr;
|
||||
|
||||
console.log(buf);
|
||||
// Prints: <Buffer 88 13 a0 0f>
|
||||
|
||||
// changing the TypedArray changes the Buffer also
|
||||
arr[1] = 6000;
|
||||
|
||||
console.log(buf);
|
||||
// Prints: <Buffer 88 13 70 17>
|
||||
```
|
||||
|
||||
The optional `byteOffset` and `length` arguments specify a memory range within
|
||||
the `arrayBuffer` that will be shared by the `Buffer`.
|
||||
|
||||
```js
|
||||
const ab = new ArrayBuffer(10);
|
||||
const buf = Buffer.from(ab, 0, 2);
|
||||
console.log(buf.length);
|
||||
// Prints: 2
|
||||
```
|
||||
|
||||
A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`.
|
||||
|
||||
### Class Method: Buffer.from(buffer)
|
||||
<!-- YAML
|
||||
added: v3.0.0
|
||||
-->
|
||||
|
||||
* `buffer` {Buffer}
|
||||
|
||||
Copies the passed `buffer` data onto a new `Buffer` instance.
|
||||
|
||||
```js
|
||||
const buf1 = Buffer.from('buffer');
|
||||
const buf2 = Buffer.from(buf1);
|
||||
|
||||
buf1[0] = 0x61;
|
||||
console.log(buf1.toString());
|
||||
// 'auffer'
|
||||
console.log(buf2.toString());
|
||||
// 'buffer' (copy is not changed)
|
||||
```
|
||||
|
||||
A `TypeError` will be thrown if `buffer` is not a `Buffer`.
|
||||
|
||||
### Class Method: Buffer.from(str[, encoding])
|
||||
<!-- YAML
|
||||
added: v5.10.0
|
||||
-->
|
||||
|
||||
* `str` {String} String to encode.
|
||||
* `encoding` {String} Encoding to use, Default: `'utf8'`
|
||||
|
||||
Creates a new `Buffer` containing the given JavaScript string `str`. If
|
||||
provided, the `encoding` parameter identifies the character encoding.
|
||||
If not provided, `encoding` defaults to `'utf8'`.
|
||||
|
||||
```js
|
||||
const buf1 = Buffer.from('this is a tést');
|
||||
console.log(buf1.toString());
|
||||
// prints: this is a tést
|
||||
console.log(buf1.toString('ascii'));
|
||||
// prints: this is a tC)st
|
||||
|
||||
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
|
||||
console.log(buf2.toString());
|
||||
// prints: this is a tést
|
||||
```
|
||||
|
||||
A `TypeError` will be thrown if `str` is not a string.
|
||||
|
||||
### Class Method: Buffer.alloc(size[, fill[, encoding]])
|
||||
<!-- YAML
|
||||
added: v5.10.0
|
||||
-->
|
||||
|
||||
* `size` {Number}
|
||||
* `fill` {Value} Default: `undefined`
|
||||
* `encoding` {String} Default: `utf8`
|
||||
|
||||
Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the
|
||||
`Buffer` will be *zero-filled*.
|
||||
|
||||
```js
|
||||
const buf = Buffer.alloc(5);
|
||||
console.log(buf);
|
||||
// <Buffer 00 00 00 00 00>
|
||||
```
|
||||
|
||||
The `size` must be less than or equal to the value of
|
||||
`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
|
||||
`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
|
||||
be created if a `size` less than or equal to 0 is specified.
|
||||
|
||||
If `fill` is specified, the allocated `Buffer` will be initialized by calling
|
||||
`buf.fill(fill)`. See [`buf.fill()`][] for more information.
|
||||
|
||||
```js
|
||||
const buf = Buffer.alloc(5, 'a');
|
||||
console.log(buf);
|
||||
// <Buffer 61 61 61 61 61>
|
||||
```
|
||||
|
||||
If both `fill` and `encoding` are specified, the allocated `Buffer` will be
|
||||
initialized by calling `buf.fill(fill, encoding)`. For example:
|
||||
|
||||
```js
|
||||
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
|
||||
console.log(buf);
|
||||
// <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
|
||||
```
|
||||
|
||||
Calling `Buffer.alloc(size)` can be significantly slower than the alternative
|
||||
`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance
|
||||
contents will *never contain sensitive data*.
|
||||
|
||||
A `TypeError` will be thrown if `size` is not a number.
|
||||
|
||||
### Class Method: Buffer.allocUnsafe(size)
|
||||
<!-- YAML
|
||||
added: v5.10.0
|
||||
-->
|
||||
|
||||
* `size` {Number}
|
||||
|
||||
Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must
|
||||
be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit
|
||||
architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is
|
||||
thrown. A zero-length Buffer will be created if a `size` less than or equal to
|
||||
0 is specified.
|
||||
|
||||
The underlying memory for `Buffer` instances created in this way is *not
|
||||
initialized*. The contents of the newly created `Buffer` are unknown and
|
||||
*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
|
||||
`Buffer` instances to zeroes.
|
||||
|
||||
```js
|
||||
const buf = Buffer.allocUnsafe(5);
|
||||
console.log(buf);
|
||||
// <Buffer 78 e0 82 02 01>
|
||||
// (octets will be different, every time)
|
||||
buf.fill(0);
|
||||
console.log(buf);
|
||||
// <Buffer 00 00 00 00 00>
|
||||
```
|
||||
|
||||
A `TypeError` will be thrown if `size` is not a number.
|
||||
|
||||
Note that the `Buffer` module pre-allocates an internal `Buffer` instance of
|
||||
size `Buffer.poolSize` that is used as a pool for the fast allocation of new
|
||||
`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated
|
||||
`new Buffer(size)` constructor) only when `size` is less than or equal to
|
||||
`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default
|
||||
value of `Buffer.poolSize` is `8192` but can be modified.
|
||||
|
||||
Use of this pre-allocated internal memory pool is a key difference between
|
||||
calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
|
||||
Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer
|
||||
pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal
|
||||
Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The
|
||||
difference is subtle but can be important when an application requires the
|
||||
additional performance that `Buffer.allocUnsafe(size)` provides.
|
||||
|
||||
### Class Method: Buffer.allocUnsafeSlow(size)
|
||||
<!-- YAML
|
||||
added: v5.10.0
|
||||
-->
|
||||
|
||||
* `size` {Number}
|
||||
|
||||
Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The
|
||||
`size` must be less than or equal to the value of
|
||||
`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
|
||||
`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
|
||||
be created if a `size` less than or equal to 0 is specified.
|
||||
|
||||
The underlying memory for `Buffer` instances created in this way is *not
|
||||
initialized*. The contents of the newly created `Buffer` are unknown and
|
||||
*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
|
||||
`Buffer` instances to zeroes.
|
||||
|
||||
When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
|
||||
allocations under 4KB are, by default, sliced from a single pre-allocated
|
||||
`Buffer`. This allows applications to avoid the garbage collection overhead of
|
||||
creating many individually allocated Buffers. This approach improves both
|
||||
performance and memory usage by eliminating the need to track and cleanup as
|
||||
many `Persistent` objects.
|
||||
|
||||
However, in the case where a developer may need to retain a small chunk of
|
||||
memory from a pool for an indeterminate amount of time, it may be appropriate
|
||||
to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then
|
||||
copy out the relevant bits.
|
||||
|
||||
```js
|
||||
// need to keep around a few small chunks of memory
|
||||
const store = [];
|
||||
|
||||
socket.on('readable', () => {
|
||||
const data = socket.read();
|
||||
// allocate for retained data
|
||||
const sb = Buffer.allocUnsafeSlow(10);
|
||||
// copy the data into the new allocation
|
||||
data.copy(sb, 0, 0, 10);
|
||||
store.push(sb);
|
||||
});
|
||||
```
|
||||
|
||||
Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*
|
||||
a developer has observed undue memory retention in their applications.
|
||||
|
||||
A `TypeError` will be thrown if `size` is not a number.
|
||||
|
||||
### All the Rest
|
||||
|
||||
The rest of the `Buffer` API is exactly the same as in node.js.
|
||||
[See the docs](https://nodejs.org/api/buffer.html).
|
||||
|
||||
|
||||
## Related links
|
||||
|
||||
- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
|
||||
- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4)
|
||||
|
||||
## Why is `Buffer` unsafe?
|
||||
|
||||
Today, the node.js `Buffer` constructor is overloaded to handle many different argument
|
||||
types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.),
|
||||
`ArrayBuffer`, and also `Number`.
|
||||
|
||||
The API is optimized for convenience: you can throw any type at it, and it will try to do
|
||||
what you want.
|
||||
|
||||
Because the Buffer constructor is so powerful, you often see code like this:
|
||||
|
||||
```js
|
||||
// Convert UTF-8 strings to hex
|
||||
function toHex (str) {
|
||||
return new Buffer(str).toString('hex')
|
||||
}
|
||||
```
|
||||
|
||||
***But what happens if `toHex` is called with a `Number` argument?***
|
||||
|
||||
### Remote Memory Disclosure
|
||||
|
||||
If an attacker can make your program call the `Buffer` constructor with a `Number`
|
||||
argument, then they can make it allocate uninitialized memory from the node.js process.
|
||||
This could potentially disclose TLS private keys, user data, or database passwords.
|
||||
|
||||
When the `Buffer` constructor is passed a `Number` argument, it returns an
|
||||
**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like
|
||||
this, you **MUST** overwrite the contents before returning it to the user.
|
||||
|
||||
From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size):
|
||||
|
||||
> `new Buffer(size)`
|
||||
>
|
||||
> - `size` Number
|
||||
>
|
||||
> The underlying memory for `Buffer` instances created in this way is not initialized.
|
||||
> **The contents of a newly created `Buffer` are unknown and could contain sensitive
|
||||
> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes.
|
||||
|
||||
(Emphasis our own.)
|
||||
|
||||
Whenever the programmer intended to create an uninitialized `Buffer` you often see code
|
||||
like this:
|
||||
|
||||
```js
|
||||
var buf = new Buffer(16)
|
||||
|
||||
// Immediately overwrite the uninitialized buffer with data from another buffer
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
buf[i] = otherBuf[i]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Would this ever be a problem in real code?
|
||||
|
||||
Yes. It's surprisingly common to forget to check the type of your variables in a
|
||||
dynamically-typed language like JavaScript.
|
||||
|
||||
Usually the consequences of assuming the wrong type is that your program crashes with an
|
||||
uncaught exception. But the failure mode for forgetting to check the type of arguments to
|
||||
the `Buffer` constructor is more catastrophic.
|
||||
|
||||
Here's an example of a vulnerable service that takes a JSON payload and converts it to
|
||||
hex:
|
||||
|
||||
```js
|
||||
// Take a JSON payload {str: "some string"} and convert it to hex
|
||||
var server = http.createServer(function (req, res) {
|
||||
var data = ''
|
||||
req.setEncoding('utf8')
|
||||
req.on('data', function (chunk) {
|
||||
data += chunk
|
||||
})
|
||||
req.on('end', function () {
|
||||
var body = JSON.parse(data)
|
||||
res.end(new Buffer(body.str).toString('hex'))
|
||||
})
|
||||
})
|
||||
|
||||
server.listen(8080)
|
||||
```
|
||||
|
||||
In this example, an http client just has to send:
|
||||
|
||||
```json
|
||||
{
|
||||
"str": 1000
|
||||
}
|
||||
```
|
||||
|
||||
and it will get back 1,000 bytes of uninitialized memory from the server.
|
||||
|
||||
This is a very serious bug. It's similar in severity to the
|
||||
[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process
|
||||
memory by remote attackers.
|
||||
|
||||
|
||||
### Which real-world packages were vulnerable?
|
||||
|
||||
#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht)
|
||||
|
||||
[Mathias Buus](https://github.com/mafintosh) and I
|
||||
([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages,
|
||||
[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow
|
||||
anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get
|
||||
them to reveal 20 bytes at a time of uninitialized memory from the node.js process.
|
||||
|
||||
Here's
|
||||
[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8)
|
||||
that fixed it. We released a new fixed version, created a
|
||||
[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all
|
||||
vulnerable versions on npm so users will get a warning to upgrade to a newer version.
|
||||
|
||||
#### [`ws`](https://www.npmjs.com/package/ws)
|
||||
|
||||
That got us wondering if there were other vulnerable packages. Sure enough, within a short
|
||||
period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the
|
||||
most popular WebSocket implementation in node.js.
|
||||
|
||||
If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as
|
||||
expected, then uninitialized server memory would be disclosed to the remote peer.
|
||||
|
||||
These were the vulnerable methods:
|
||||
|
||||
```js
|
||||
socket.send(number)
|
||||
socket.ping(number)
|
||||
socket.pong(number)
|
||||
```
|
||||
|
||||
Here's a vulnerable socket server with some echo functionality:
|
||||
|
||||
```js
|
||||
server.on('connection', function (socket) {
|
||||
socket.on('message', function (message) {
|
||||
message = JSON.parse(message)
|
||||
if (message.type === 'echo') {
|
||||
socket.send(message.data) // send back the user's message
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
`socket.send(number)` called on the server, will disclose server memory.
|
||||
|
||||
Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue
|
||||
was fixed, with a more detailed explanation. Props to
|
||||
[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the
|
||||
[Node Security Project disclosure](https://nodesecurity.io/advisories/67).
|
||||
|
||||
|
||||
### What's the solution?
|
||||
|
||||
It's important that node.js offers a fast way to get memory otherwise performance-critical
|
||||
applications would needlessly get a lot slower.
|
||||
|
||||
But we need a better way to *signal our intent* as programmers. **When we want
|
||||
uninitialized memory, we should request it explicitly.**
|
||||
|
||||
Sensitive functionality should not be packed into a developer-friendly API that loosely
|
||||
accepts many different types. This type of API encourages the lazy practice of passing
|
||||
variables in without checking the type very carefully.
|
||||
|
||||
#### A new API: `Buffer.allocUnsafe(number)`
|
||||
|
||||
The functionality of creating buffers with uninitialized memory should be part of another
|
||||
API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that
|
||||
frequently gets user input of all sorts of different types passed into it.
|
||||
|
||||
```js
|
||||
var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory!
|
||||
|
||||
// Immediately overwrite the uninitialized buffer with data from another buffer
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
buf[i] = otherBuf[i]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### How do we fix node.js core?
|
||||
|
||||
We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as
|
||||
`semver-major`) which defends against one case:
|
||||
|
||||
```js
|
||||
var str = 16
|
||||
new Buffer(str, 'utf8')
|
||||
```
|
||||
|
||||
In this situation, it's implied that the programmer intended the first argument to be a
|
||||
string, since they passed an encoding as a second argument. Today, node.js will allocate
|
||||
uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not
|
||||
what the programmer intended.
|
||||
|
||||
But this is only a partial solution, since if the programmer does `new Buffer(variable)`
|
||||
(without an `encoding` parameter) there's no way to know what they intended. If `variable`
|
||||
is sometimes a number, then uninitialized memory will sometimes be returned.
|
||||
|
||||
### What's the real long-term fix?
|
||||
|
||||
We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when
|
||||
we need uninitialized memory. But that would break 1000s of packages.
|
||||
|
||||
~~We believe the best solution is to:~~
|
||||
|
||||
~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~
|
||||
|
||||
~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~
|
||||
|
||||
#### Update
|
||||
|
||||
We now support adding three new APIs:
|
||||
|
||||
- `Buffer.from(value)` - convert from any type to a buffer
|
||||
- `Buffer.alloc(size)` - create a zero-filled buffer
|
||||
- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size
|
||||
|
||||
This solves the core problem that affected `ws` and `bittorrent-dht` which is
|
||||
`Buffer(variable)` getting tricked into taking a number argument.
|
||||
|
||||
This way, existing code continues working and the impact on the npm ecosystem will be
|
||||
minimal. Over time, npm maintainers can migrate performance-critical code to use
|
||||
`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`.
|
||||
|
||||
|
||||
### Conclusion
|
||||
|
||||
We think there's a serious design issue with the `Buffer` API as it exists today. It
|
||||
promotes insecure software by putting high-risk functionality into a convenient API
|
||||
with friendly "developer ergonomics".
|
||||
|
||||
This wasn't merely a theoretical exercise because we found the issue in some of the
|
||||
most popular npm packages.
|
||||
|
||||
Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of
|
||||
`buffer`.
|
||||
|
||||
```js
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
```
|
||||
|
||||
Eventually, we hope that node.js core can switch to this new, safer behavior. We believe
|
||||
the impact on the ecosystem would be minimal since it's not a breaking change.
|
||||
Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while
|
||||
older, insecure packages would magically become safe from this attack vector.
|
||||
|
||||
|
||||
## links
|
||||
|
||||
- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514)
|
||||
- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67)
|
||||
- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68)
|
||||
|
||||
|
||||
## credit
|
||||
|
||||
The original issues in `bittorrent-dht`
|
||||
([disclosure](https://nodesecurity.io/advisories/68)) and
|
||||
`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by
|
||||
[Mathias Buus](https://github.com/mafintosh) and
|
||||
[Feross Aboukhadijeh](http://feross.org/).
|
||||
|
||||
Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues
|
||||
and for his work running the [Node Security Project](https://nodesecurity.io/).
|
||||
|
||||
Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and
|
||||
auditing the code.
|
||||
|
||||
|
||||
## license
|
||||
|
||||
MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { TSESTree } from '@typescript-eslint/types';
|
||||
import type { ScopeManager } from '../ScopeManager';
|
||||
import type { Scope } from './Scope';
|
||||
import { ScopeBase } from './ScopeBase';
|
||||
import { ScopeType } from './ScopeType';
|
||||
export declare class WithScope extends ScopeBase<ScopeType.with, TSESTree.WithStatement, Scope> {
|
||||
constructor(scopeManager: ScopeManager, upperScope: WithScope['upper'], block: WithScope['block']);
|
||||
close(scopeManager: ScopeManager): Scope | null;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../util");
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-array-delete',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow using the `delete` operator on array values',
|
||||
recommended: 'recommended',
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
hasSuggestions: true,
|
||||
messages: {
|
||||
noArrayDelete: 'Using the `delete` operator with an array expression is unsafe.',
|
||||
useSplice: 'Use `array.splice()` instead.',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const services = (0, util_1.getParserServices)(context);
|
||||
const checker = services.program.getTypeChecker();
|
||||
function isUnderlyingTypeArray(type) {
|
||||
const predicate = (t) => checker.isArrayType(t) || checker.isTupleType(t);
|
||||
if (type.isUnion()) {
|
||||
return type.types.every(predicate);
|
||||
}
|
||||
if (type.isIntersection()) {
|
||||
return type.types.some(predicate);
|
||||
}
|
||||
return predicate(type);
|
||||
}
|
||||
return {
|
||||
'UnaryExpression[operator="delete"]'(node) {
|
||||
const { argument } = node;
|
||||
if (argument.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
|
||||
return;
|
||||
}
|
||||
const type = (0, util_1.getConstrainedTypeAtLocation)(services, argument.object);
|
||||
if (!isUnderlyingTypeArray(type)) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noArrayDelete',
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'useSplice',
|
||||
fix(fixer) {
|
||||
const { object, property } = argument;
|
||||
const shouldHaveParentheses = property.type === utils_1.AST_NODE_TYPES.SequenceExpression;
|
||||
const nodeMap = services.esTreeNodeToTSNodeMap;
|
||||
const target = nodeMap.get(object).getText();
|
||||
const rawKey = nodeMap.get(property).getText();
|
||||
const key = shouldHaveParentheses ? `(${rawKey})` : rawKey;
|
||||
let suggestion = `${target}.splice(${key}, 1)`;
|
||||
const comments = context.sourceCode.getCommentsInside(node);
|
||||
if (comments.length > 0) {
|
||||
const indentationCount = node.loc.start.column;
|
||||
const indentation = ' '.repeat(indentationCount);
|
||||
const commentsText = comments
|
||||
.map(comment => {
|
||||
return comment.type === utils_1.AST_TOKEN_TYPES.Line
|
||||
? `//${comment.value}`
|
||||
: `/*${comment.value}*/`;
|
||||
})
|
||||
.join(`\n${indentation}`);
|
||||
suggestion = `${commentsText}\n${indentation}${suggestion}`;
|
||||
}
|
||||
return fixer.replaceText(node, suggestion);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
import type { $ZodStringFormats } from "../core/checks.js";
|
||||
import type * as errors from "../core/errors.js";
|
||||
import * as util from "../core/util.js";
|
||||
|
||||
const error: () => errors.$ZodErrorMap = () => {
|
||||
const Sizable: Record<string, { unit: string; verb: string }> = {
|
||||
string: { unit: "文字", verb: "である" },
|
||||
file: { unit: "バイト", verb: "である" },
|
||||
array: { unit: "要素", verb: "である" },
|
||||
set: { unit: "要素", verb: "である" },
|
||||
};
|
||||
|
||||
function getSizing(origin: string): { unit: string; verb: string } | null {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
|
||||
const FormatDictionary: {
|
||||
[k in $ZodStringFormats | (string & {})]?: string;
|
||||
} = {
|
||||
regex: "入力値",
|
||||
email: "メールアドレス",
|
||||
url: "URL",
|
||||
emoji: "絵文字",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ISO日時",
|
||||
date: "ISO日付",
|
||||
time: "ISO時刻",
|
||||
duration: "ISO期間",
|
||||
ipv4: "IPv4アドレス",
|
||||
ipv6: "IPv6アドレス",
|
||||
cidrv4: "IPv4範囲",
|
||||
cidrv6: "IPv6範囲",
|
||||
base64: "base64エンコード文字列",
|
||||
base64url: "base64urlエンコード文字列",
|
||||
json_string: "JSON文字列",
|
||||
e164: "E.164番号",
|
||||
jwt: "JWT",
|
||||
template_literal: "入力値",
|
||||
};
|
||||
|
||||
const TypeDictionary: {
|
||||
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
|
||||
} = {
|
||||
nan: "NaN",
|
||||
number: "数値",
|
||||
array: "配列",
|
||||
};
|
||||
|
||||
return (issue) => {
|
||||
switch (issue.code) {
|
||||
case "invalid_type": {
|
||||
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
||||
const receivedType = util.parsedType(issue.input);
|
||||
const received = TypeDictionary[receivedType] ?? receivedType;
|
||||
if (/^[A-Z]/.test(issue.expected)) {
|
||||
return `無効な入力: instanceof ${issue.expected}が期待されましたが、${received}が入力されました`;
|
||||
}
|
||||
return `無効な入力: ${expected}が期待されましたが、${received}が入力されました`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1) return `無効な入力: ${util.stringifyPrimitive(issue.values[0])}が期待されました`;
|
||||
return `無効な選択: ${util.joinValues(issue.values, "、")}のいずれかである必要があります`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "以下である" : "より小さい";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${sizing.unit ?? "要素"}${adj}必要があります`;
|
||||
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${adj}必要があります`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? "以上である" : "より大きい";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${sizing.unit}${adj}必要があります`;
|
||||
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${adj}必要があります`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue as errors.$ZodStringFormatIssues;
|
||||
if (_issue.format === "starts_with") return `無効な文字列: "${_issue.prefix}"で始まる必要があります`;
|
||||
if (_issue.format === "ends_with") return `無効な文字列: "${_issue.suffix}"で終わる必要があります`;
|
||||
if (_issue.format === "includes") return `無効な文字列: "${_issue.includes}"を含む必要があります`;
|
||||
if (_issue.format === "regex") return `無効な文字列: パターン${_issue.pattern}に一致する必要があります`;
|
||||
return `無効な${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `無効な数値: ${issue.divisor}の倍数である必要があります`;
|
||||
case "unrecognized_keys":
|
||||
return `認識されていないキー${issue.keys.length > 1 ? "群" : ""}: ${util.joinValues(issue.keys, "、")}`;
|
||||
case "invalid_key":
|
||||
return `${issue.origin}内の無効なキー`;
|
||||
case "invalid_union":
|
||||
return "無効な入力";
|
||||
case "invalid_element":
|
||||
return `${issue.origin}内の無効な値`;
|
||||
default:
|
||||
return `無効な入力`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default function (): { localeError: errors.$ZodErrorMap } {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
const SemVer = require('../classes/semver')
|
||||
const Range = require('../classes/range')
|
||||
const minSatisfying = (versions, range, options) => {
|
||||
let min = null
|
||||
let minSV = null
|
||||
let rangeObj = null
|
||||
try {
|
||||
rangeObj = new Range(range, options)
|
||||
} catch (er) {
|
||||
return null
|
||||
}
|
||||
versions.forEach((v) => {
|
||||
if (rangeObj.test(v)) {
|
||||
// satisfies(v, range, options)
|
||||
if (!min || minSV.compare(v) === 1) {
|
||||
// compare(min, v, true)
|
||||
min = v
|
||||
minSV = new SemVer(min, options)
|
||||
}
|
||||
}
|
||||
})
|
||||
return min
|
||||
}
|
||||
module.exports = minSatisfying
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"author": "Jake Luer <jake@alogicalparadox.com>",
|
||||
"name": "chai",
|
||||
"type": "module",
|
||||
"description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.",
|
||||
"keywords": [
|
||||
"test",
|
||||
"assertion",
|
||||
"assert",
|
||||
"testing",
|
||||
"chai"
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"register-*.js"
|
||||
],
|
||||
"homepage": "http://chaijs.com",
|
||||
"license": "MIT",
|
||||
"contributors": [
|
||||
"Jake Luer <jake@alogicalparadox.com>",
|
||||
"Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)",
|
||||
"Veselin Todorov <hi@vesln.com>",
|
||||
"John Firebaugh <john.firebaugh@gmail.com>"
|
||||
],
|
||||
"version": "6.2.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chaijs/chai"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/chaijs/chai/issues"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"build": "esbuild --bundle --format=esm --target=es2021 --keep-names --legal-comments=none --outfile=index.js lib/chai.js",
|
||||
"prebuild": "npm run clean",
|
||||
"format": "prettier --write lib",
|
||||
"pretest": "npm run lint",
|
||||
"test": "npm run test-node && npm run test-chrome",
|
||||
"test-node": "c8 --99 --check-coverage mocha --require ./test/bootstrap/index.js test/*.js",
|
||||
"test-chrome": "web-test-runner --playwright",
|
||||
"lint": "npm run lint:js && npm run lint:format",
|
||||
"lint:js": "eslint lib/",
|
||||
"lint:format": "prettier --check lib",
|
||||
"lint:types": "tsc",
|
||||
"clean": "rm -rf index.js coverage/"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@rollup/plugin-commonjs": "^29.0.0",
|
||||
"@web/dev-server-rollup": "^0.6.1",
|
||||
"@web/test-runner": "^0.20.0",
|
||||
"@web/test-runner-playwright": "^0.11.0",
|
||||
"assertion-error": "^2.0.1",
|
||||
"c8": "^10.1.3",
|
||||
"check-error": "^2.1.1",
|
||||
"deep-eql": "^5.0.1",
|
||||
"esbuild": "^0.27.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-plugin-jsdoc": "^61.0.0",
|
||||
"globals": "^16.3.0",
|
||||
"loupe": "^3.1.0",
|
||||
"mocha": "^11.0.0",
|
||||
"pathval": "^2.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"typescript": "~5.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import * as util from "../core/util.js";
|
||||
const error = () => {
|
||||
const Sizable = {
|
||||
string: { unit: "aksara", verb: "mempunyai" },
|
||||
file: { unit: "bait", verb: "mempunyai" },
|
||||
array: { unit: "elemen", verb: "mempunyai" },
|
||||
set: { unit: "elemen", verb: "mempunyai" },
|
||||
};
|
||||
function getSizing(origin) {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
const FormatDictionary = {
|
||||
regex: "input",
|
||||
email: "alamat e-mel",
|
||||
url: "URL",
|
||||
emoji: "emoji",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "tarikh masa ISO",
|
||||
date: "tarikh ISO",
|
||||
time: "masa ISO",
|
||||
duration: "tempoh ISO",
|
||||
ipv4: "alamat IPv4",
|
||||
ipv6: "alamat IPv6",
|
||||
cidrv4: "julat IPv4",
|
||||
cidrv6: "julat IPv6",
|
||||
base64: "string dikodkan base64",
|
||||
base64url: "string dikodkan base64url",
|
||||
json_string: "string JSON",
|
||||
e164: "nombor E.164",
|
||||
jwt: "JWT",
|
||||
template_literal: "input",
|
||||
};
|
||||
const TypeDictionary = {
|
||||
nan: "NaN",
|
||||
number: "nombor",
|
||||
};
|
||||
return (issue) => {
|
||||
switch (issue.code) {
|
||||
case "invalid_type": {
|
||||
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
||||
const receivedType = util.parsedType(issue.input);
|
||||
const received = TypeDictionary[receivedType] ?? receivedType;
|
||||
if (/^[A-Z]/.test(issue.expected)) {
|
||||
return `Input tidak sah: dijangka instanceof ${issue.expected}, diterima ${received}`;
|
||||
}
|
||||
return `Input tidak sah: dijangka ${expected}, diterima ${received}`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `Input tidak sah: dijangka ${util.stringifyPrimitive(issue.values[0])}`;
|
||||
return `Pilihan tidak sah: dijangka salah satu daripada ${util.joinValues(issue.values, "|")}`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `Terlalu besar: dijangka ${issue.origin ?? "nilai"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elemen"}`;
|
||||
return `Terlalu besar: dijangka ${issue.origin ?? "nilai"} adalah ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `Terlalu kecil: dijangka ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
return `Terlalu kecil: dijangka ${issue.origin} adalah ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue;
|
||||
if (_issue.format === "starts_with")
|
||||
return `String tidak sah: mesti bermula dengan "${_issue.prefix}"`;
|
||||
if (_issue.format === "ends_with")
|
||||
return `String tidak sah: mesti berakhir dengan "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes")
|
||||
return `String tidak sah: mesti mengandungi "${_issue.includes}"`;
|
||||
if (_issue.format === "regex")
|
||||
return `String tidak sah: mesti sepadan dengan corak ${_issue.pattern}`;
|
||||
return `${FormatDictionary[_issue.format] ?? issue.format} tidak sah`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Nombor tidak sah: perlu gandaan ${issue.divisor}`;
|
||||
case "unrecognized_keys":
|
||||
return `Kunci tidak dikenali: ${util.joinValues(issue.keys, ", ")}`;
|
||||
case "invalid_key":
|
||||
return `Kunci tidak sah dalam ${issue.origin}`;
|
||||
case "invalid_union":
|
||||
return "Input tidak sah";
|
||||
case "invalid_element":
|
||||
return `Nilai tidak sah dalam ${issue.origin}`;
|
||||
default:
|
||||
return `Input tidak sah`;
|
||||
}
|
||||
};
|
||||
};
|
||||
export default function () {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
//#region src/messages.ts
|
||||
const TYPE_REQUEST = "q";
|
||||
const TYPE_RESPONSE = "s";
|
||||
|
||||
//#endregion
|
||||
//#region src/utils.ts
|
||||
function createPromiseWithResolvers() {
|
||||
let resolve;
|
||||
let reject;
|
||||
return {
|
||||
promise: new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
}),
|
||||
resolve,
|
||||
reject
|
||||
};
|
||||
}
|
||||
const random = Math.random.bind(Math);
|
||||
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
||||
function nanoid(size = 21) {
|
||||
let id = "";
|
||||
let i = size;
|
||||
while (i--) id += urlAlphabet[random() * 64 | 0];
|
||||
return id;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/main.ts
|
||||
const DEFAULT_TIMEOUT = 6e4;
|
||||
const defaultSerialize = (i) => i;
|
||||
const defaultDeserialize = defaultSerialize;
|
||||
const { clearTimeout, setTimeout } = globalThis;
|
||||
function createBirpc($functions, options) {
|
||||
const { post, on, off = () => {}, eventNames = [], serialize = defaultSerialize, deserialize = defaultDeserialize, resolver, bind = "rpc", timeout = DEFAULT_TIMEOUT, proxify = true } = options;
|
||||
let $closed = false;
|
||||
const _rpcPromiseMap = /* @__PURE__ */ new Map();
|
||||
let _promiseInit;
|
||||
let rpc;
|
||||
async function _call(method, args, event, optional) {
|
||||
if ($closed) throw new Error(`[birpc] rpc is closed, cannot call "${method}"`);
|
||||
const req = {
|
||||
m: method,
|
||||
a: args,
|
||||
t: TYPE_REQUEST
|
||||
};
|
||||
if (optional) req.o = true;
|
||||
const send = async (_req) => post(serialize(_req));
|
||||
if (event) {
|
||||
await send(req);
|
||||
return;
|
||||
}
|
||||
if (_promiseInit) try {
|
||||
await _promiseInit;
|
||||
} finally {
|
||||
_promiseInit = void 0;
|
||||
}
|
||||
let { promise, resolve, reject } = createPromiseWithResolvers();
|
||||
const id = nanoid();
|
||||
req.i = id;
|
||||
let timeoutId;
|
||||
async function handler(newReq = req) {
|
||||
if (timeout >= 0) {
|
||||
timeoutId = setTimeout(() => {
|
||||
try {
|
||||
if (options.onTimeoutError?.call(rpc, method, args) !== true) throw new Error(`[birpc] timeout on calling "${method}"`);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
_rpcPromiseMap.delete(id);
|
||||
}, timeout);
|
||||
if (typeof timeoutId === "object") timeoutId = timeoutId.unref?.();
|
||||
}
|
||||
_rpcPromiseMap.set(id, {
|
||||
resolve,
|
||||
reject,
|
||||
timeoutId,
|
||||
method
|
||||
});
|
||||
await send(newReq);
|
||||
return promise;
|
||||
}
|
||||
try {
|
||||
if (options.onRequest) await options.onRequest.call(rpc, req, handler, resolve);
|
||||
else await handler();
|
||||
} catch (e) {
|
||||
if (options.onGeneralError?.call(rpc, e) !== true) throw e;
|
||||
return;
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
_rpcPromiseMap.delete(id);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
const builtinMethods = {
|
||||
$call: (method, ...args) => _call(method, args, false),
|
||||
$callOptional: (method, ...args) => _call(method, args, false, true),
|
||||
$callEvent: (method, ...args) => _call(method, args, true),
|
||||
$callRaw: (options$1) => _call(options$1.method, options$1.args, options$1.event, options$1.optional),
|
||||
$rejectPendingCalls,
|
||||
get $closed() {
|
||||
return $closed;
|
||||
},
|
||||
get $meta() {
|
||||
return options.meta;
|
||||
},
|
||||
$close,
|
||||
$functions
|
||||
};
|
||||
if (proxify) rpc = new Proxy({}, { get(_, method) {
|
||||
if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) return builtinMethods[method];
|
||||
if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) return void 0;
|
||||
const sendEvent = (...args) => _call(method, args, true);
|
||||
if (eventNames.includes(method)) {
|
||||
sendEvent.asEvent = sendEvent;
|
||||
return sendEvent;
|
||||
}
|
||||
const sendCall = (...args) => _call(method, args, false);
|
||||
sendCall.asEvent = sendEvent;
|
||||
return sendCall;
|
||||
} });
|
||||
else rpc = builtinMethods;
|
||||
function $close(customError) {
|
||||
$closed = true;
|
||||
_rpcPromiseMap.forEach(({ reject, method }) => {
|
||||
const error = /* @__PURE__ */ new Error(`[birpc] rpc is closed, cannot call "${method}"`);
|
||||
if (customError) {
|
||||
customError.cause ??= error;
|
||||
return reject(customError);
|
||||
}
|
||||
reject(error);
|
||||
});
|
||||
_rpcPromiseMap.clear();
|
||||
off(onMessage);
|
||||
}
|
||||
function $rejectPendingCalls(handler) {
|
||||
const handlerResults = Array.from(_rpcPromiseMap.values()).map(({ method, reject }) => {
|
||||
if (!handler) return reject(/* @__PURE__ */ new Error(`[birpc]: rejected pending call "${method}".`));
|
||||
return handler({
|
||||
method,
|
||||
reject
|
||||
});
|
||||
});
|
||||
_rpcPromiseMap.clear();
|
||||
return handlerResults;
|
||||
}
|
||||
async function onMessage(data, ...extra) {
|
||||
let msg;
|
||||
try {
|
||||
msg = deserialize(data);
|
||||
} catch (e) {
|
||||
if (options.onGeneralError?.call(rpc, e) !== true) throw e;
|
||||
return;
|
||||
}
|
||||
if (msg.t === TYPE_REQUEST) {
|
||||
const { m: method, a: args, o: optional } = msg;
|
||||
let result, error;
|
||||
let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]);
|
||||
if (optional) fn ||= () => void 0;
|
||||
if (!fn) error = /* @__PURE__ */ new Error(`[birpc] function "${method}" not found`);
|
||||
else try {
|
||||
result = await fn.apply(bind === "rpc" ? rpc : $functions, args);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (msg.i) {
|
||||
if (error && options.onFunctionError) {
|
||||
if (options.onFunctionError.call(rpc, error, method, args) === true) return;
|
||||
}
|
||||
if (!error) try {
|
||||
await post(serialize({
|
||||
t: TYPE_RESPONSE,
|
||||
i: msg.i,
|
||||
r: result
|
||||
}), ...extra);
|
||||
return;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
|
||||
}
|
||||
try {
|
||||
await post(serialize({
|
||||
t: TYPE_RESPONSE,
|
||||
i: msg.i,
|
||||
e: error
|
||||
}), ...extra);
|
||||
} catch (e) {
|
||||
if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const { i: ack, r: result, e: error } = msg;
|
||||
const promise = _rpcPromiseMap.get(ack);
|
||||
if (promise) {
|
||||
clearTimeout(promise.timeoutId);
|
||||
if (error) promise.reject(error);
|
||||
else promise.resolve(result);
|
||||
}
|
||||
_rpcPromiseMap.delete(ack);
|
||||
}
|
||||
}
|
||||
_promiseInit = on(onMessage);
|
||||
return rpc;
|
||||
}
|
||||
|
||||
export { createBirpc as c };
|
||||
@@ -0,0 +1,171 @@
|
||||
'use strict';
|
||||
|
||||
var traverse = require('../index');
|
||||
var assert = require('assert');
|
||||
|
||||
describe('json-schema-traverse', function() {
|
||||
var calls;
|
||||
|
||||
beforeEach(function() {
|
||||
calls = [];
|
||||
});
|
||||
|
||||
it('should traverse all keywords containing schemas recursively', function() {
|
||||
var schema = require('./fixtures/schema').schema;
|
||||
var expectedCalls = require('./fixtures/schema').expectedCalls;
|
||||
|
||||
traverse(schema, {cb: callback});
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
describe('Legacy v0.3.1 API', function() {
|
||||
it('should traverse all keywords containing schemas recursively', function() {
|
||||
var schema = require('./fixtures/schema').schema;
|
||||
var expectedCalls = require('./fixtures/schema').expectedCalls;
|
||||
|
||||
traverse(schema, callback);
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
it('should work when an options object is provided', function() {
|
||||
// schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex
|
||||
var schema = require('./fixtures/schema').schema;
|
||||
var expectedCalls = require('./fixtures/schema').expectedCalls;
|
||||
|
||||
traverse(schema, {}, callback);
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('allKeys option', function() {
|
||||
var schema = {
|
||||
someObject: {
|
||||
minimum: 1,
|
||||
maximum: 2
|
||||
}
|
||||
};
|
||||
|
||||
it('should traverse objects with allKeys: true option', function() {
|
||||
// schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex
|
||||
var expectedCalls = [
|
||||
[schema, '', schema, undefined, undefined, undefined, undefined],
|
||||
[schema.someObject, '/someObject', schema, '', 'someObject', schema, undefined]
|
||||
];
|
||||
|
||||
traverse(schema, {allKeys: true, cb: callback});
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
|
||||
it('should NOT traverse objects with allKeys: false option', function() {
|
||||
// schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex
|
||||
var expectedCalls = [
|
||||
[schema, '', schema, undefined, undefined, undefined, undefined]
|
||||
];
|
||||
|
||||
traverse(schema, {allKeys: false, cb: callback});
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
|
||||
it('should NOT traverse objects without allKeys option', function() {
|
||||
// schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex
|
||||
var expectedCalls = [
|
||||
[schema, '', schema, undefined, undefined, undefined, undefined]
|
||||
];
|
||||
|
||||
traverse(schema, {cb: callback});
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
|
||||
it('should NOT travers objects in standard keywords which value is not a schema', function() {
|
||||
var schema2 = {
|
||||
const: {foo: 'bar'},
|
||||
enum: ['a', 'b'],
|
||||
required: ['foo'],
|
||||
another: {
|
||||
|
||||
},
|
||||
patternProperties: {}, // will not traverse - no properties
|
||||
dependencies: true, // will not traverse - invalid
|
||||
properties: {
|
||||
smaller: {
|
||||
type: 'number'
|
||||
},
|
||||
larger: {
|
||||
type: 'number',
|
||||
minimum: {$data: '1/smaller'}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex
|
||||
var expectedCalls = [
|
||||
[schema2, '', schema2, undefined, undefined, undefined, undefined],
|
||||
[schema2.another, '/another', schema2, '', 'another', schema2, undefined],
|
||||
[schema2.properties.smaller, '/properties/smaller', schema2, '', 'properties', schema2, 'smaller'],
|
||||
[schema2.properties.larger, '/properties/larger', schema2, '', 'properties', schema2, 'larger'],
|
||||
];
|
||||
|
||||
traverse(schema2, {allKeys: true, cb: callback});
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pre and post', function() {
|
||||
var schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {type: 'string'},
|
||||
age: {type: 'number'}
|
||||
}
|
||||
};
|
||||
|
||||
it('should traverse schema in pre-order', function() {
|
||||
traverse(schema, {cb: {pre}});
|
||||
var expectedCalls = [
|
||||
['pre', schema, '', schema, undefined, undefined, undefined, undefined],
|
||||
['pre', schema.properties.name, '/properties/name', schema, '', 'properties', schema, 'name'],
|
||||
['pre', schema.properties.age, '/properties/age', schema, '', 'properties', schema, 'age'],
|
||||
];
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
it('should traverse schema in post-order', function() {
|
||||
traverse(schema, {cb: {post}});
|
||||
var expectedCalls = [
|
||||
['post', schema.properties.name, '/properties/name', schema, '', 'properties', schema, 'name'],
|
||||
['post', schema.properties.age, '/properties/age', schema, '', 'properties', schema, 'age'],
|
||||
['post', schema, '', schema, undefined, undefined, undefined, undefined],
|
||||
];
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
|
||||
it('should traverse schema in pre- and post-order at the same time', function() {
|
||||
traverse(schema, {cb: {pre, post}});
|
||||
var expectedCalls = [
|
||||
['pre', schema, '', schema, undefined, undefined, undefined, undefined],
|
||||
['pre', schema.properties.name, '/properties/name', schema, '', 'properties', schema, 'name'],
|
||||
['post', schema.properties.name, '/properties/name', schema, '', 'properties', schema, 'name'],
|
||||
['pre', schema.properties.age, '/properties/age', schema, '', 'properties', schema, 'age'],
|
||||
['post', schema.properties.age, '/properties/age', schema, '', 'properties', schema, 'age'],
|
||||
['post', schema, '', schema, undefined, undefined, undefined, undefined],
|
||||
];
|
||||
assert.deepStrictEqual(calls, expectedCalls);
|
||||
});
|
||||
});
|
||||
|
||||
function callback() {
|
||||
calls.push(Array.prototype.slice.call(arguments));
|
||||
}
|
||||
|
||||
function pre() {
|
||||
calls.push(['pre'].concat(Array.prototype.slice.call(arguments)));
|
||||
}
|
||||
|
||||
function post() {
|
||||
calls.push(['post'].concat(Array.prototype.slice.call(arguments)));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
declare module "node:trace_events" {
|
||||
/**
|
||||
* The `Tracing` object is used to enable or disable tracing for sets of
|
||||
* categories. Instances are created using the
|
||||
* `trace_events.createTracing()` method.
|
||||
*
|
||||
* When created, the `Tracing` object is disabled. Calling the
|
||||
* `tracing.enable()` method adds the categories to the set of enabled trace
|
||||
* event categories. Calling `tracing.disable()` will remove the categories
|
||||
* from the set of enabled trace event categories.
|
||||
*/
|
||||
interface Tracing {
|
||||
/**
|
||||
* A comma-separated list of the trace event categories covered by this
|
||||
* `Tracing` object.
|
||||
* @since v10.0.0
|
||||
*/
|
||||
readonly categories: string;
|
||||
/**
|
||||
* Disables this `Tracing` object.
|
||||
*
|
||||
* Only trace event categories _not_ covered by other enabled `Tracing`
|
||||
* objects and _not_ specified by the `--trace-event-categories` flag
|
||||
* will be disabled.
|
||||
*
|
||||
* ```js
|
||||
* import trace_events from 'node:trace_events';
|
||||
* const t1 = trace_events.createTracing({ categories: ['node', 'v8'] });
|
||||
* const t2 = trace_events.createTracing({ categories: ['node.perf', 'node'] });
|
||||
* t1.enable();
|
||||
* t2.enable();
|
||||
*
|
||||
* // Prints 'node,node.perf,v8'
|
||||
* console.log(trace_events.getEnabledCategories());
|
||||
*
|
||||
* t2.disable(); // Will only disable emission of the 'node.perf' category
|
||||
*
|
||||
* // Prints 'node,v8'
|
||||
* console.log(trace_events.getEnabledCategories());
|
||||
* ```
|
||||
* @since v10.0.0
|
||||
*/
|
||||
disable(): void;
|
||||
/**
|
||||
* Enables this `Tracing` object for the set of categories covered by
|
||||
* the `Tracing` object.
|
||||
* @since v10.0.0
|
||||
*/
|
||||
enable(): void;
|
||||
/**
|
||||
* `true` only if the `Tracing` object has been enabled.
|
||||
* @since v10.0.0
|
||||
*/
|
||||
readonly enabled: boolean;
|
||||
}
|
||||
interface CreateTracingOptions {
|
||||
/**
|
||||
* An array of trace category names. Values included in the array are
|
||||
* coerced to a string when possible. An error will be thrown if the
|
||||
* value cannot be coerced.
|
||||
*/
|
||||
categories: string[];
|
||||
}
|
||||
/**
|
||||
* Creates and returns a `Tracing` object for the given set of `categories`.
|
||||
*
|
||||
* ```js
|
||||
* import trace_events from 'node:trace_events';
|
||||
* const categories = ['node.perf', 'node.async_hooks'];
|
||||
* const tracing = trace_events.createTracing({ categories });
|
||||
* tracing.enable();
|
||||
* // do stuff
|
||||
* tracing.disable();
|
||||
* ```
|
||||
* @since v10.0.0
|
||||
*/
|
||||
function createTracing(options: CreateTracingOptions): Tracing;
|
||||
/**
|
||||
* Returns a comma-separated list of all currently-enabled trace event
|
||||
* categories. The current set of enabled trace event categories is determined
|
||||
* by the _union_ of all currently-enabled `Tracing` objects and any categories
|
||||
* enabled using the `--trace-event-categories` flag.
|
||||
*
|
||||
* Given the file `test.js` below, the command `node --trace-event-categories node.perf test.js` will print `'node.async_hooks,node.perf'` to the console.
|
||||
*
|
||||
* ```js
|
||||
* import trace_events from 'node:trace_events';
|
||||
* const t1 = trace_events.createTracing({ categories: ['node.async_hooks'] });
|
||||
* const t2 = trace_events.createTracing({ categories: ['node.perf'] });
|
||||
* const t3 = trace_events.createTracing({ categories: ['v8'] });
|
||||
*
|
||||
* t1.enable();
|
||||
* t2.enable();
|
||||
*
|
||||
* console.log(trace_events.getEnabledCategories());
|
||||
* ```
|
||||
* @since v10.0.0
|
||||
*/
|
||||
function getEnabledCategories(): string | undefined;
|
||||
}
|
||||
declare module "trace_events" {
|
||||
export * from "node:trace_events";
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
'use strict'
|
||||
|
||||
const bench = require('fastbench')
|
||||
const pino = require('../')
|
||||
const bunyan = require('bunyan')
|
||||
const bole = require('bole')('bench')
|
||||
const winston = require('winston')
|
||||
const fs = require('node:fs')
|
||||
const dest = fs.createWriteStream('/dev/null')
|
||||
const loglevel = require('./utils/wrap-log-level')(dest)
|
||||
const plogNodeStream = pino(dest)
|
||||
delete require.cache[require.resolve('../')]
|
||||
const plogMinLength = require('../')(pino.destination({ dest: '/dev/null', minLength: 4096 }))
|
||||
delete require.cache[require.resolve('../')]
|
||||
const plogDest = require('../')(pino.destination('/dev/null'))
|
||||
|
||||
process.env.DEBUG = 'dlog'
|
||||
const debug = require('debug')
|
||||
const dlog = debug('dlog')
|
||||
dlog.log = function (s) { dest.write(s) }
|
||||
|
||||
const max = 10
|
||||
const blog = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: [{
|
||||
level: 'trace',
|
||||
stream: dest
|
||||
}]
|
||||
})
|
||||
|
||||
require('bole').output({
|
||||
level: 'info',
|
||||
stream: dest
|
||||
}).setFastTime(true)
|
||||
|
||||
const chill = winston.createLogger({
|
||||
transports: [
|
||||
new winston.transports.Stream({
|
||||
stream: fs.createWriteStream('/dev/null')
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
const run = bench([
|
||||
function benchBunyan (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
blog.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchWinston (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
chill.log('info', 'hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchBole (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
bole.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchDebug (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
dlog('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchLogLevel (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
loglevel.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPino (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
plogDest.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPinoMinLength (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
plogMinLength.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchPinoNodeStream (cb) {
|
||||
for (var i = 0; i < max; i++) {
|
||||
plogNodeStream.info('hello world')
|
||||
}
|
||||
setImmediate(cb)
|
||||
}
|
||||
], 10000)
|
||||
|
||||
run(run)
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as types from '.';
|
||||
import { expectType } from 'tsd';
|
||||
|
||||
// builtins
|
||||
expectType<types.TypesBuiltins>(types.builtins);
|
||||
|
||||
// getTypeParser
|
||||
const noParse = types.getTypeParser(types.builtins.NUMERIC, 'text');
|
||||
const numericParser = types.getTypeParser(types.builtins.NUMERIC, 'binary');
|
||||
expectType<string>(noParse('noParse'));
|
||||
expectType<number>(numericParser([200, 1, 0, 15]));
|
||||
|
||||
// getArrayParser
|
||||
const value = types.arrayParser('{1,2,3}', (num) => parseInt(num));
|
||||
expectType<number[]>(value);
|
||||
|
||||
//setTypeParser
|
||||
types.setTypeParser(types.builtins.INT8, parseInt);
|
||||
types.setTypeParser(types.builtins.FLOAT8, parseFloat);
|
||||
types.setTypeParser(types.builtins.FLOAT8, 'binary', (data) => data[0]);
|
||||
types.setTypeParser(types.builtins.FLOAT8, 'text', parseFloat);
|
||||
@@ -0,0 +1,253 @@
|
||||
import { URL } from 'node:url'
|
||||
import { Duplex, Readable, Writable } from 'node:stream'
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { Blob } from 'node:buffer'
|
||||
import { IncomingHttpHeaders, OutgoingHttpHeaders } from './header'
|
||||
import BodyReadable from './readable'
|
||||
import { FormData } from './formdata'
|
||||
import Errors from './errors'
|
||||
import { Autocomplete } from './utility'
|
||||
|
||||
export default Dispatcher
|
||||
|
||||
export type UndiciHeaders = OutgoingHttpHeaders | string[] | Iterable<[string, string | string[] | undefined]> | null
|
||||
|
||||
/** Dispatcher is the core API used to dispatch requests. */
|
||||
declare class Dispatcher extends EventEmitter {
|
||||
/** Dispatches a request. This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. It is primarily intended for library developers who implement higher level APIs on top of this. */
|
||||
dispatch (options: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean
|
||||
/** Starts two-way communications with the requested resource. */
|
||||
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ConnectData<TOpaque>) => void): void
|
||||
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>): Promise<Dispatcher.ConnectData<TOpaque>>
|
||||
/** Compose a chain of dispatchers */
|
||||
compose (dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher
|
||||
compose (...dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher
|
||||
/** Performs an HTTP request. */
|
||||
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ResponseData<TOpaque>) => void): void
|
||||
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>): Promise<Dispatcher.ResponseData<TOpaque>>
|
||||
/** For easy use with `stream.pipeline`. */
|
||||
pipeline<TOpaque = null>(options: Dispatcher.PipelineOptions<TOpaque>, handler: Dispatcher.PipelineHandler<TOpaque>): Duplex
|
||||
/** A faster version of `Dispatcher.request`. */
|
||||
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>, callback: (err: Error | null, data: Dispatcher.StreamData<TOpaque>) => void): void
|
||||
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>): Promise<Dispatcher.StreamData<TOpaque>>
|
||||
/** Upgrade to a different protocol. */
|
||||
upgrade (options: Dispatcher.UpgradeOptions, callback: (err: Error | null, data: Dispatcher.UpgradeData) => void): void
|
||||
upgrade (options: Dispatcher.UpgradeOptions): Promise<Dispatcher.UpgradeData>
|
||||
/** Closes the client and gracefully waits for enqueued requests to complete before invoking the callback (or returning a promise if no callback is provided). */
|
||||
close (callback: () => void): void
|
||||
close (): Promise<void>
|
||||
/** Destroy the client abruptly with the given err. All the pending and running requests will be asynchronously aborted and error. Waits until socket is closed before invoking the callback (or returning a promise if no callback is provided). Since this operation is asynchronously dispatched there might still be some progress on dispatched requests. */
|
||||
destroy (err: Error | null, callback: () => void): void
|
||||
destroy (callback: () => void): void
|
||||
destroy (err: Error | null): Promise<void>
|
||||
destroy (): Promise<void>
|
||||
|
||||
on (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
on (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
on (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
on (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
once (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
once (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
once (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
once (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
off (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
off (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
off (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
off (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
addListener (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
addListener (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
addListener (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
addListener (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
removeListener (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
removeListener (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
removeListener (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
removeListener (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
prependListener (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
prependListener (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
prependListener (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
prependListener (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
prependOnceListener (eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this
|
||||
prependOnceListener (eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
prependOnceListener (eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this
|
||||
prependOnceListener (eventName: 'drain', callback: (origin: URL) => void): this
|
||||
|
||||
listeners (eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[]
|
||||
listeners (eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]
|
||||
listeners (eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]
|
||||
listeners (eventName: 'drain'): ((origin: URL) => void)[]
|
||||
|
||||
rawListeners (eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[]
|
||||
rawListeners (eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]
|
||||
rawListeners (eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]
|
||||
rawListeners (eventName: 'drain'): ((origin: URL) => void)[]
|
||||
|
||||
emit (eventName: 'connect', origin: URL, targets: readonly Dispatcher[]): boolean
|
||||
emit (eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean
|
||||
emit (eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean
|
||||
emit (eventName: 'drain', origin: URL): boolean
|
||||
}
|
||||
|
||||
declare namespace Dispatcher {
|
||||
export interface ComposedDispatcher extends Dispatcher { }
|
||||
export type Dispatch = Dispatcher['dispatch']
|
||||
export type DispatcherComposeInterceptor = (dispatch: Dispatch) => Dispatch
|
||||
export interface DispatchOptions {
|
||||
origin?: string | URL;
|
||||
path: string;
|
||||
method: HttpMethod;
|
||||
/** Default: `null` */
|
||||
body?: string | Buffer | Uint8Array | Readable | null | FormData;
|
||||
/** Default: `null` */
|
||||
headers?: UndiciHeaders;
|
||||
/** Query string params to be embedded in the request URL. Default: `null` */
|
||||
query?: Record<string, any>;
|
||||
/** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline have completed. Default: `true` if `method` is `HEAD` or `GET`. */
|
||||
idempotent?: boolean;
|
||||
/** Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received. Defaults to `method !== 'HEAD'`. */
|
||||
blocking?: boolean;
|
||||
/** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255. Default: `0` */
|
||||
typeOfService?: number | null;
|
||||
/** Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. Default: `method === 'CONNECT' || null`. */
|
||||
upgrade?: boolean | string | null;
|
||||
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. */
|
||||
headersTimeout?: number | null;
|
||||
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. */
|
||||
bodyTimeout?: number | null;
|
||||
/** Whether the request should stablish a keep-alive or not. Default `false` */
|
||||
reset?: boolean;
|
||||
/** For H2, it appends the expect: 100-continue header, and halts the request body until a 100-continue is received from the remote server */
|
||||
expectContinue?: boolean;
|
||||
}
|
||||
export interface ConnectOptions<TOpaque = null> {
|
||||
origin: string | URL;
|
||||
path: string;
|
||||
/** Default: `null` */
|
||||
headers?: UndiciHeaders;
|
||||
/** Default: `null` */
|
||||
signal?: AbortSignal | EventEmitter | null;
|
||||
/** This argument parameter is passed through to `ConnectData` */
|
||||
opaque?: TOpaque;
|
||||
/** Default: `null` */
|
||||
responseHeaders?: 'raw' | null;
|
||||
}
|
||||
export interface RequestOptions<TOpaque = null> extends DispatchOptions {
|
||||
/** Default: `null` */
|
||||
opaque?: TOpaque;
|
||||
/** Default: `null` */
|
||||
signal?: AbortSignal | EventEmitter | null;
|
||||
/** Default: `null` */
|
||||
onInfo?: (info: { statusCode: number, headers: Record<string, string | string[]> }) => void;
|
||||
/** Default: `null` */
|
||||
responseHeaders?: 'raw' | null;
|
||||
/** Default: `64 KiB` */
|
||||
highWaterMark?: number;
|
||||
}
|
||||
export interface PipelineOptions<TOpaque = null> extends RequestOptions<TOpaque> {
|
||||
/** `true` if the `handler` will return an object stream. Default: `false` */
|
||||
objectMode?: boolean;
|
||||
}
|
||||
export interface UpgradeOptions {
|
||||
path: string;
|
||||
/** Default: `'GET'` */
|
||||
method?: string;
|
||||
/** Default: `null` */
|
||||
headers?: UndiciHeaders;
|
||||
/** A string of comma separated protocols, in descending preference order. Default: `'Websocket'` */
|
||||
protocol?: string;
|
||||
/** Default: `null` */
|
||||
signal?: AbortSignal | EventEmitter | null;
|
||||
/** Default: `null` */
|
||||
responseHeaders?: 'raw' | null;
|
||||
}
|
||||
export interface ConnectData<TOpaque = null> {
|
||||
statusCode: number;
|
||||
headers: IncomingHttpHeaders;
|
||||
socket: Duplex;
|
||||
opaque: TOpaque;
|
||||
}
|
||||
export interface ResponseData<TOpaque = null> {
|
||||
statusCode: number;
|
||||
statusText: string;
|
||||
headers: IncomingHttpHeaders;
|
||||
body: BodyReadable & BodyMixin;
|
||||
trailers: Record<string, string>;
|
||||
opaque: TOpaque;
|
||||
context: object;
|
||||
}
|
||||
export interface PipelineHandlerData<TOpaque = null> {
|
||||
statusCode: number;
|
||||
headers: IncomingHttpHeaders;
|
||||
opaque: TOpaque;
|
||||
body: BodyReadable;
|
||||
context: object;
|
||||
}
|
||||
export interface StreamData<TOpaque = null> {
|
||||
opaque: TOpaque;
|
||||
trailers: Record<string, string>;
|
||||
}
|
||||
export interface UpgradeData<TOpaque = null> {
|
||||
headers: IncomingHttpHeaders;
|
||||
socket: Duplex;
|
||||
opaque: TOpaque;
|
||||
}
|
||||
export interface StreamFactoryData<TOpaque = null> {
|
||||
statusCode: number;
|
||||
headers: IncomingHttpHeaders;
|
||||
opaque: TOpaque;
|
||||
context: object;
|
||||
}
|
||||
export type StreamFactory<TOpaque = null> = (data: StreamFactoryData<TOpaque>) => Writable
|
||||
|
||||
export interface DispatchController {
|
||||
get aborted(): boolean
|
||||
get paused(): boolean
|
||||
get reason(): Error | null
|
||||
rawHeaders?: Buffer[] | string[] | IncomingHttpHeaders | null
|
||||
rawTrailers?: Buffer[] | string[] | IncomingHttpHeaders | null
|
||||
abort(reason: Error): void
|
||||
pause(): void
|
||||
resume(): void
|
||||
}
|
||||
|
||||
export interface DispatchHandler {
|
||||
onRequestStart?(controller: DispatchController, context: any): void;
|
||||
onRequestUpgrade?(controller: DispatchController, statusCode: number, headers: IncomingHttpHeaders, socket: Duplex): void;
|
||||
onResponseStart?(controller: DispatchController, statusCode: number, headers: IncomingHttpHeaders, statusMessage?: string): void;
|
||||
onResponseData?(controller: DispatchController, chunk: Buffer): void;
|
||||
onResponseEnd?(controller: DispatchController, trailers: IncomingHttpHeaders): void;
|
||||
onResponseError?(controller: DispatchController, error: Error): void;
|
||||
|
||||
/** Invoked when response is received, before headers have been read. **/
|
||||
onResponseStarted?(): void;
|
||||
/** Invoked when a body chunk is sent to the server. May be invoked multiple times for chunked requests */
|
||||
onBodySent?(chunk: Buffer): void;
|
||||
/** Invoked after the request body is fully sent. */
|
||||
onRequestSent?(): void;
|
||||
}
|
||||
export type PipelineHandler<TOpaque = null> = (data: PipelineHandlerData<TOpaque>) => Readable
|
||||
export type HttpMethod = Autocomplete<'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH'>
|
||||
|
||||
/**
|
||||
* @link https://fetch.spec.whatwg.org/#body-mixin
|
||||
*/
|
||||
interface BodyMixin {
|
||||
readonly body?: never;
|
||||
readonly bodyUsed: boolean;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
blob(): Promise<Blob>;
|
||||
bytes(): Promise<Uint8Array>;
|
||||
formData(): Promise<never>;
|
||||
json(): Promise<unknown>;
|
||||
text(): Promise<string>;
|
||||
}
|
||||
|
||||
export interface DispatchInterceptor {
|
||||
(dispatch: Dispatch): Dispatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "eslint-visitor-keys",
|
||||
"version": "3.4.3",
|
||||
"description": "Constants and utilities about visitor keys to traverse AST.",
|
||||
"type": "module",
|
||||
"main": "dist/eslint-visitor-keys.cjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"import": "./lib/index.js",
|
||||
"require": "./dist/eslint-visitor-keys.cjs"
|
||||
},
|
||||
"./dist/eslint-visitor-keys.cjs"
|
||||
],
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"dist/index.d.ts",
|
||||
"dist/visitor-keys.d.ts",
|
||||
"dist/eslint-visitor-keys.cjs",
|
||||
"dist/eslint-visitor-keys.d.cts",
|
||||
"lib"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/estree": "^0.0.51",
|
||||
"@types/estree-jsx": "^0.0.1",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"c8": "^7.11.0",
|
||||
"chai": "^4.3.6",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint-config-eslint": "^7.0.0",
|
||||
"eslint-plugin-jsdoc": "^35.4.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-release": "^3.2.0",
|
||||
"esquery": "^1.4.0",
|
||||
"json-diff": "^0.7.3",
|
||||
"mocha": "^9.2.1",
|
||||
"opener": "^1.5.2",
|
||||
"rollup": "^2.70.0",
|
||||
"rollup-plugin-dts": "^4.2.3",
|
||||
"tsd": "^0.19.1",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:cjs && npm run build:types",
|
||||
"build:cjs": "rollup -c",
|
||||
"build:debug": "npm run build:cjs -- -m && npm run build:types",
|
||||
"build:keys": "node tools/build-keys-from-ts",
|
||||
"build:types": "tsc",
|
||||
"lint": "eslint .",
|
||||
"prepare": "npm run build",
|
||||
"release:generate:latest": "eslint-generate-release",
|
||||
"release:generate:alpha": "eslint-generate-prerelease alpha",
|
||||
"release:generate:beta": "eslint-generate-prerelease beta",
|
||||
"release:generate:rc": "eslint-generate-prerelease rc",
|
||||
"release:publish": "eslint-publish-release",
|
||||
"test": "mocha tests/lib/**/*.cjs && c8 mocha tests/lib/**/*.js && npm run test:types",
|
||||
"test:open-coverage": "c8 report --reporter lcov && opener coverage/lcov-report/index.html",
|
||||
"test:types": "tsd"
|
||||
},
|
||||
"repository": "eslint/eslint-visitor-keys",
|
||||
"funding": "https://opencollective.com/eslint",
|
||||
"keywords": [],
|
||||
"author": "Toru Nagashima (https://github.com/mysticatea)",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/eslint/eslint-visitor-keys/issues"
|
||||
},
|
||||
"homepage": "https://github.com/eslint/eslint-visitor-keys#readme"
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"name": "typescript",
|
||||
"author": "Microsoft Corp.",
|
||||
"homepage": "https://www.typescriptlang.org/",
|
||||
"version": "5.5.4",
|
||||
"license": "Apache-2.0",
|
||||
"description": "TypeScript is a language for application scale JavaScript development",
|
||||
"keywords": [
|
||||
"TypeScript",
|
||||
"Microsoft",
|
||||
"compiler",
|
||||
"language",
|
||||
"javascript"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/TypeScript/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/TypeScript.git"
|
||||
},
|
||||
"main": "./lib/typescript.js",
|
||||
"typings": "./lib/typescript.d.ts",
|
||||
"bin": {
|
||||
"tsc": "./bin/tsc",
|
||||
"tsserver": "./bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"lib",
|
||||
"!lib/enu",
|
||||
"LICENSE.txt",
|
||||
"README.md",
|
||||
"SECURITY.md",
|
||||
"ThirdPartyNoticeText.txt",
|
||||
"!**/.gitattributes"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@dprint/formatter": "^0.3.0",
|
||||
"@dprint/typescript": "0.91.0",
|
||||
"@esfx/canceltoken": "^1.0.0",
|
||||
"@octokit/rest": "^20.1.1",
|
||||
"@types/chai": "^4.3.16",
|
||||
"@types/microsoft__typescript-etw": "^0.1.3",
|
||||
"@types/minimist": "^1.2.5",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/node": "latest",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/which": "^3.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||
"@typescript-eslint/parser": "^7.11.0",
|
||||
"@typescript-eslint/utils": "^7.11.0",
|
||||
"azure-devops-node-api": "^13.0.0",
|
||||
"c8": "^9.1.0",
|
||||
"chai": "^4.4.1",
|
||||
"chalk": "^4.1.2",
|
||||
"chokidar": "^3.6.0",
|
||||
"diff": "^5.2.0",
|
||||
"dprint": "^0.46.1",
|
||||
"esbuild": "^0.21.4",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-formatter-autolinkable-stylish": "^1.3.0",
|
||||
"eslint-plugin-local": "^4.2.2",
|
||||
"fast-xml-parser": "^4.4.0",
|
||||
"glob": "^10.4.1",
|
||||
"hereby": "^1.8.9",
|
||||
"jsonc-parser": "^3.2.1",
|
||||
"minimist": "^1.2.8",
|
||||
"mocha": "^10.4.0",
|
||||
"mocha-fivemat-progress-reporter": "^0.1.0",
|
||||
"ms": "^2.1.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"playwright": "^1.44.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.4.5",
|
||||
"which": "^3.0.1"
|
||||
},
|
||||
"overrides": {
|
||||
"typescript@*": "$typescript"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "hereby runtests-parallel --light=false",
|
||||
"test:eslint-rules": "hereby run-eslint-rules-tests",
|
||||
"build": "npm run build:compiler && npm run build:tests",
|
||||
"build:compiler": "hereby local",
|
||||
"build:tests": "hereby tests",
|
||||
"build:tests:notypecheck": "hereby tests --no-typecheck",
|
||||
"clean": "hereby clean",
|
||||
"gulp": "hereby",
|
||||
"lint": "hereby lint",
|
||||
"format": "dprint fmt",
|
||||
"setup-hooks": "node scripts/link-hooks.mjs"
|
||||
},
|
||||
"browser": {
|
||||
"fs": false,
|
||||
"os": false,
|
||||
"path": false,
|
||||
"crypto": false,
|
||||
"buffer": false,
|
||||
"@microsoft/typescript-etw": false,
|
||||
"source-map-support": false,
|
||||
"inspector": false,
|
||||
"perf_hooks": false
|
||||
},
|
||||
"packageManager": "npm@8.19.4",
|
||||
"volta": {
|
||||
"node": "20.1.0",
|
||||
"npm": "8.19.4"
|
||||
},
|
||||
"gitHead": "c8a7d589e647e19c94150d9892909f3aa93e48eb"
|
||||
}
|
||||
Reference in New Issue
Block a user