@miniflare/shared
Version:
Shared utility module for Miniflare: a fun, full-featured, fully-local simulator for Cloudflare Workers
719 lines (597 loc) • 26 kB
TypeScript
/// <reference types="node" />
import { Awaitable as Awaitable_2 } from '@miniflare/shared';
import { MockAgent } from 'undici';
import type { Database as SqliteDB } from 'better-sqlite3';
import type { Options as SqliteOptions } from 'better-sqlite3';
import { TransferListItem } from 'worker_threads';
export declare function addAll<T>(set: Set<T>, values: Iterable<T>): void;
export declare type AdditionalModules = {
[key: string]: Context;
};
export declare function arrayCompare<T extends any[] | NodeJS.TypedArray>(a: T, b: T): number;
export declare function assertInRequest(): void;
export declare type Awaitable<T> = T | Promise<T>;
export declare function base64Decode(encoded: string): string;
export declare function base64Encode(value: string): string;
export declare interface BeforeSetupResult {
watch?: string[];
}
export declare type Clock = () => number;
export declare class Compatibility {
#private;
private compatibilityDate;
private compatibilityFlags;
constructor(compatibilityDate?: string, compatibilityFlags?: CompatibilityFlag[]);
isEnabled(flag: CompatibilityEnableFlag): boolean;
update(compatibilityDate?: string, compatibilityFlags?: CompatibilityFlag[]): boolean;
get enabled(): CompatibilityEnableFlag[];
}
export declare type CompatibilityDisableFlag = "streams_disable_constructors" | "transformstream_disable_standard_constructor" | "export_commonjs_namespace" | "no_global_navigator" | "durable_object_fetch_allows_relative_url" | "fetch_treats_unknown_protocols_as_http" | "formdata_parser_converts_files_to_strings";
export declare type CompatibilityEnableFlag = "nodejs_compat" | "streams_enable_constructors" | "transformstream_enable_standard_constructor" | "export_commonjs_default" | "r2_list_honor_include" | "global_navigator" | "durable_object_fetch_requires_full_url" | "fetch_refuses_unknown_protocols" | "formdata_parser_supports_files" | "html_rewriter_treats_esi_include_as_void_tag" | "experimental";
export declare interface CompatibilityFeature {
defaultAsOf?: string;
enableFlag: CompatibilityEnableFlag;
disableFlag?: CompatibilityDisableFlag;
}
export declare type CompatibilityFlag = CompatibilityEnableFlag | CompatibilityDisableFlag;
export declare interface Consumer {
queueName: string;
maxBatchSize: number;
maxWaitMs: number;
maxRetries: number;
deadLetterQueue?: string;
dispatcher: QueueEventDispatcher;
}
export declare type Context = {
[key: string | symbol]: any;
};
export declare function createSQLiteDB(dbPath: string): Promise<SqliteDB>;
export declare interface DBConstructor {
new (filename: string | Buffer, options?: SqliteOptions): SqliteDB;
}
export declare const defaultClock: Clock;
export declare const EXTERNAL_SUBREQUEST_LIMIT_BUNDLED = 50;
export declare const EXTERNAL_SUBREQUEST_LIMIT_UNBOUND = 1000;
export declare type ExtractOptions<Instance> = Instance extends Plugin<infer Options> ? Options : never;
export declare function getRequestContext(): RequestContext | undefined;
export declare function getSQLiteNativeBindingLocation(sqliteResolvePath: string): string;
export declare function globsToMatcher(globs?: string[]): Matcher;
export declare class InputGate {
#private;
constructor(parent?: InputGate);
/** Waits for input gate to open, then runs closure under the input gate */
runWith<T>(closure: () => Awaitable<T>): Promise<T>;
/** Waits for input gate to be open (e.g. before returning from async I/O) */
waitForOpen(): Promise<void>;
/**
* Runs a closure with this input gate closed (e.g. performing Durable Object
* storage operation, blockConcurrencyWhile). Once complete, if the gate is
* now open, resolves some waiters.
*/
runWithClosed<T>(closure: () => Promise<T>): Promise<T>;
}
export declare class InputGatedEventTarget<EventMap extends Record<string, Event>> extends TypedEventTarget<EventMap> {
protected [kWrapListener]<Type extends keyof EventMap>(listener: (event: EventMap[Type]) => void): (event: EventMap[Type]) => void;
}
export declare const INTERNAL_SUBREQUEST_LIMIT = 1000;
export declare function kebabCase(s: string): string;
export declare const kGetConsumer: unique symbol;
export declare const kSetConsumer: unique symbol;
export declare const kWrapListener: unique symbol;
export declare function lexicographicCompare(x: string, y: string): number;
export declare class Log {
#private;
readonly level: LogLevel;
constructor(level?: LogLevel, opts?: LogOptions);
log(message: string): void;
logWithLevel(level: LogLevel, message: string): void;
error(message: Error): void;
warn(message: string): void;
info(message: string): void;
debug(message: string): void;
verbose(message: string): void;
}
export declare enum LogLevel {
NONE = 0,
ERROR = 1,
WARN = 2,
INFO = 3,
DEBUG = 4,
VERBOSE = 5
}
export declare interface LogOptions {
prefix?: string;
suffix?: string;
}
export declare function logOptions<Plugins extends PluginSignatures>(plugins: PluginEntries<Plugins>, log: Log, options: PluginOptions<Plugins>): void;
export declare interface Matcher {
test(string: string): boolean;
toString(): string;
}
export declare interface Message<Body = unknown> {
readonly id: string;
readonly timestamp: Date;
readonly body: Body;
retry(): void;
}
export declare interface MessageBatch<Body = unknown> {
readonly queue: string;
readonly messages: Message<Body>[];
retryAll(): void;
}
export declare type MessageSendOptions = {};
export declare type MessageSendRequest<Body = unknown> = {
body: Body;
} & MessageSendOptions;
export declare function millisToSeconds(millis: number): number;
export declare abstract class MiniflareError<Code extends string | number = string | number> extends Error {
readonly code: Code;
readonly cause?: Error | undefined;
constructor(code: Code, message?: string, cause?: Error | undefined);
}
export declare interface ModuleRule {
type: ModuleRuleType;
include: string[];
fallthrough?: boolean;
}
export declare type ModuleRuleType = "ESModule" | "CommonJS" | "Text" | "Data" | "CompiledWasm";
export declare interface Mount<Request = any, Response = any> {
moduleExports?: Context;
dispatchFetch?: (request: Request) => Promise<Response>;
usageModel?: UsageModel;
}
export declare class Mutex {
private locked;
private resolveQueue;
private lock;
private unlock;
get hasWaiting(): boolean;
runWith<T>(closure: () => Awaitable_2<T>): Promise<T>;
}
export declare function nonCircularClone<T>(value: T): T;
export declare class NoOpLog extends Log {
log(): void;
error(message: Error): void;
}
export declare const numericCompare: (x: string, y: string) => number;
export declare function Option(metadata: OptionMetadata): (prototype: typeof Plugin.prototype, key: string | symbol) => void;
export declare type OptionMetadata = OptionMetadataType<OptionType.NONE, any> | OptionMetadataType<OptionType.BOOLEAN, boolean> | OptionMetadataType<OptionType.NUMBER, number> | OptionMetadataType<OptionType.STRING, string> | OptionMetadataType<OptionType.STRING_POSITIONAL, string> | OptionMetadataType<OptionType.BOOLEAN_STRING, boolean | string> | OptionMetadataType<OptionType.BOOLEAN_NUMBER, boolean | number> | OptionMetadataType<OptionType.ARRAY, any[]> | OptionMetadataType<OptionType.OBJECT, any>;
export declare interface OptionMetadataType<Type extends OptionType, Value> {
type: Type;
typeFormat?: Type extends OptionType.OBJECT ? string : undefined;
name?: string;
alias?: string;
description?: string;
negatable?: Type extends OptionType.BOOLEAN | OptionType.BOOLEAN_STRING | OptionType.BOOLEAN_NUMBER ? boolean : undefined;
logName?: string;
logValue?: (value: Value) => string | undefined;
fromEntries?: Type extends OptionType.OBJECT ? (entries: [key: string, value: string][]) => Value : undefined;
fromWrangler?: (config: WranglerConfig, configDir: string, log: Log) => Value | undefined;
}
export declare type Options<Plugins extends PluginSignatures> = UnionToIntersection<PluginOptionsUnion<Plugins>>;
export declare enum OptionType {
NONE = 0,
BOOLEAN = 1,
NUMBER = 2,
STRING = 3,
STRING_POSITIONAL = 4,
BOOLEAN_STRING = 5,
BOOLEAN_NUMBER = 6,
ARRAY = 7,
OBJECT = 8
}
export declare class OutputGate {
#private;
/** Runs closure under the output gate, then waits for output gate to open */
runWith<T>(closure: () => Awaitable<T>): Promise<T>;
/** Waits for promises registered with this gate via waitUntil to resolve */
waitForOpen(): Promise<void>;
/**
* Registers a promise with this output gate. The gate won't open until this
* promise resolves.
*/
waitUntil(promise: Promise<any>): void;
}
export declare interface ParsedRange {
offset: number;
length: number;
}
export declare function parseRange({ offset, length, suffix }: Range, size: number): ParsedRange;
export declare abstract class Plugin<Options extends Context = never> {
#private;
protected readonly ctx: PluginContext;
opts?: Map<string | symbol, OptionMetadata>;
protected constructor(ctx: PluginContext);
protected assignOptions(options?: Options): void;
beforeSetup?(): Awaitable<BeforeSetupResult | void>;
setup?(storageFactory: StorageFactory): Awaitable<SetupResult | void>;
beforeReload?(): Awaitable<void>;
reload?(bindings: Context, moduleExports: Context, mounts: Map<string, Mount>): Awaitable<void>;
dispose?(): Awaitable<void>;
}
export declare interface PluginContext {
log: Log;
compat: Compatibility;
rootPath: string;
usageModel?: UsageModel;
globalAsyncIO?: boolean;
fetchMock?: MockAgent;
queueEventDispatcher: QueueEventDispatcher;
queueBroker: QueueBroker;
sharedCache: Map<string, unknown>;
}
export declare type PluginEntries<Plugins extends PluginSignatures> = [
name: keyof Plugins,
plugin: ValueOf<Plugins>
][];
export declare type PluginOptions<Plugins extends PluginSignatures> = {
[key in keyof Plugins]: ExtractOptions<InstanceType<Plugins[key]>>;
};
export declare type PluginOptionsUnion<Plugins extends PluginSignatures> = ValueOf<PluginOptions<Plugins>>;
export declare type PluginSignature = {
new (ctx: PluginContext, options?: Context): Plugin<Context>;
prototype: {
opts?: Map<string | symbol, OptionMetadata>;
};
};
export declare type PluginSignatures = {
[pluginName: string]: PluginSignature;
};
export declare function prefixError(prefix: string, e: any): Error;
export declare interface ProcessedModuleRule {
type: ModuleRuleType;
include: Matcher;
}
export declare interface Queue<Body = unknown> {
send(message: Body, options?: MessageSendOptions): Promise<void>;
sendBatch(batch: Iterable<MessageSendRequest<Body>>): Promise<void>;
[kSetConsumer](consumer?: Consumer): void;
[kGetConsumer](): Consumer | null;
}
export declare interface QueueBroker {
getOrCreateQueue(name: string): Queue;
setConsumer(queue: Queue, consumer: Consumer): void;
resetConsumers(): void;
}
export declare type QueueEventDispatcher = (batch: MessageBatch) => Promise<void>;
export declare function randomHex(digits?: number): string;
export declare interface Range {
offset?: number;
length?: number;
suffix?: number;
}
export declare interface RangeStoredMeta<Meta = unknown> extends StoredMeta<Meta> {
range: {
offset: number;
length: number;
};
}
export declare interface RangeStoredValue extends StoredValue {
range: {
offset: number;
length: number;
};
}
export declare type RangeStoredValueMeta<Meta = unknown> = RangeStoredValue & RangeStoredMeta<Meta>;
export declare class RequestContext {
#private;
readonly requestDepth: number;
readonly pipelineDepth: number;
readonly durableObject: boolean;
readonly externalSubrequestLimit: number | false;
readonly internalSubrequestLimit: number | false;
constructor({ requestDepth, pipelineDepth, durableObject, externalSubrequestLimit, internalSubrequestLimit, }?: RequestContextOptions);
runWith<T>(closure: () => T): T;
get externalSubrequests(): number;
get internalSubrequests(): number;
incrementExternalSubrequests(count?: number): void;
incrementInternalSubrequests(count?: number): void;
get currentTime(): number;
advanceCurrentTime(): void;
}
export declare interface RequestContextOptions {
/**
* In this context, a request is the initial entry fetch to a Worker
* (e.g. the incoming HTTP request), or fetch to a Durable Object stub.
* The depth starts at 1, and increments for each recursive request.
*/
requestDepth?: number;
/**
* The pipeline depth starts at 1, and increments for each recursive service
* binding fetch. The requestDepth should not be incremented in this case.
* The pipeline depth resets for each new request (as described above).
*/
pipelineDepth?: number;
/**
* Whether this context is for inside a Durable Object fetch. Affects
* WebSocket subrequest limits for incoming messages.
*/
durableObject?: boolean;
/** Maximum external subrequests (`fetch`, Cache API) allowed. */
externalSubrequestLimit?: number | false;
/** Maximum internal subrequests (KV, Durable Objects) allowed. */
internalSubrequestLimit?: number | false;
}
export declare function resolveStoragePersist(rootPath: string, persist?: boolean | string): boolean | string | undefined;
export declare type RouteType = string | {
pattern: string;
zone_id?: string;
zone_name?: string;
};
/**
* Runs closure with the context's input gate (if any) closed, unless
* allowConcurrency is true. Should be called when performing storage
* operations.
*/
export declare function runWithInputGateClosed<T>(closure: () => Promise<T>, allowConcurrency?: boolean): Promise<T>;
export declare function sanitisePath(unsafe: string): string;
export declare interface ScriptBlueprint {
readonly filePath: string;
readonly code: string;
}
export declare interface ScriptRunner {
run(globalScope: Context, blueprint: ScriptBlueprint, modulesRules?: ProcessedModuleRule[], additionalModules?: AdditionalModules, compat?: Compatibility): Promise<ScriptRunnerResult>;
}
export declare interface ScriptRunnerResult {
exports: Context;
bundleSize?: number;
watch?: string[];
}
export declare interface SetupResult extends BeforeSetupResult {
globals?: Context;
bindings?: Context;
script?: ScriptBlueprint;
requiresModuleExports?: boolean;
additionalModules?: AdditionalModules;
}
export declare const SITES_NO_CACHE_PREFIX = "$__MINIFLARE_SITES__$/";
export declare function spaceCase(s: string): string;
export { SqliteDB }
export { SqliteOptions }
/**
* Common class for key-value storage:
* - Methods should always return fresh copies of data (safe to mutate returned)
* - Methods shouldn't return expired keys
*/
export declare abstract class Storage {
abstract has(key: string): Awaitable<boolean>;
abstract head<Meta = unknown>(key: string): Awaitable<StoredMeta<Meta> | undefined>;
abstract get<Meta = unknown>(key: string, skipMetadata?: false): Awaitable<StoredValueMeta<Meta> | undefined>;
abstract get(key: string, skipMetadata: true): Awaitable<StoredValue | undefined>;
abstract getRange<Meta = unknown>(key: string, range?: Range, skipMetadata?: false): Awaitable<RangeStoredValueMeta<Meta> | undefined>;
abstract getRange(key: string, range: undefined | Range, skipMetadata: true): Awaitable<RangeStoredValue | undefined>;
abstract put<Meta = unknown>(key: string, value: StoredValueMeta<Meta>): Awaitable<void>;
abstract delete(key: string): Awaitable<boolean>;
abstract list<Meta = unknown>(options?: StorageListOptions, skipMetadata?: false): Awaitable<StorageListResult<StoredKeyMeta<Meta>>>;
abstract list(options: StorageListOptions, skipMetadata: true): Awaitable<StorageListResult<StoredKey>>;
getSqliteDatabase(): Promise<SqliteDB>;
hasMany(keys: string[]): Promise<number>;
getMany<Meta = unknown>(keys: string[], skipMetadata?: false): Promise<(StoredValueMeta<Meta> | undefined)[]>;
getMany(keys: string[], skipMetadata: true): Promise<(StoredValue | undefined)[]>;
putMany<Meta = unknown>(data: [key: string, value: StoredValueMeta<Meta>][]): Promise<void>;
deleteMany(keys: string[]): Promise<number>;
}
export declare interface StorageFactory {
storage(namespace: string, persist?: boolean | string): Storage;
dispose?(): Awaitable<void>;
}
export declare interface StorageListOptions {
/** Returned keys must start with this string if defined */
prefix?: string;
/** Returned keys must NOT start with this string if defined */
excludePrefix?: string;
/** Returned keys must be lexicographically >= this string if defined */
start?: string;
/** Returned keys must be lexicographically < this string if defined */
end?: string;
/** Return keys in reverse order, MUST be applied before the limit/cursor */
reverse?: boolean;
/** Cursor for pagination, undefined/empty-string means start at beginning */
cursor?: string;
/** Maximum number of keys to return if defined */
limit?: number;
/** If Delimiter, filter all keys containing delimiter and update cursor */
delimiter?: string;
}
export declare interface StorageListResult<Key extends StoredKey = StoredKeyMeta> {
keys: Key[];
/** Cursor for next page */
cursor: string;
/** DelimitedPrefixes if delimiter */
delimitedPrefixes?: string[];
}
export declare interface StoredKey {
name: string;
}
export declare type StoredKeyMeta<Meta = unknown> = StoredKey & StoredMeta<Meta>;
export declare interface StoredMeta<Meta = unknown> {
/** Unix timestamp in seconds when this key expires */
expiration?: number;
/** Arbitrary JSON-serializable object */
metadata?: Meta;
}
export declare interface StoredValue {
value: Uint8Array;
}
export declare type StoredValueMeta<Meta = unknown> = StoredValue & StoredMeta<Meta>;
export declare const STRING_SCRIPT_PATH = "<script>";
export declare function structuredCloneImpl<T>(value: T, options?: StructuredSerializeOptions): T;
export declare interface StructuredSerializeOptions {
transfer?: ReadonlyArray<TransferListItem>;
}
export declare class ThrowingEventTarget<EventMap extends Record<string, Event>> extends TypedEventTarget<EventMap> {
#private;
protected [kWrapListener]<Type extends keyof EventMap>(listener: (event: EventMap[Type]) => void): (event: EventMap[Type]) => void;
dispatchEvent(event: ValueOf<EventMap>): boolean;
}
export declare function titleCase(s: string): string;
export declare type TypedEventListener<E extends Event> = ((e: E) => void) | {
handleEvent(e: E): void;
};
export declare class TypedEventTarget<EventMap extends Record<string, Event>> extends EventTarget {
#private;
protected [kWrapListener]?<Type extends keyof EventMap>(listener: (event: EventMap[Type]) => void): (event: EventMap[Type]) => void;
addEventListener<Type extends keyof EventMap>(type: Type, listener: TypedEventListener<EventMap[Type]> | null, options?: AddEventListenerOptions | boolean): void;
removeEventListener<Type extends keyof EventMap>(type: Type, listener: TypedEventListener<EventMap[Type]> | null, options?: EventListenerOptions | boolean): void;
dispatchEvent(event: ValueOf<EventMap>): boolean;
}
export declare interface TypedMap<ValueMap extends Record<string, unknown>> {
clear(): void;
delete(key: keyof ValueMap): boolean;
forEach(callback: (value: ValueOf<ValueMap>, key: keyof ValueMap, map: this) => void, thisArg?: any): void;
get<Key extends keyof ValueMap>(key: Key): ValueMap[Key] | undefined;
has(key: keyof ValueMap): boolean;
set<Key extends keyof ValueMap>(key: Key, value: ValueMap[Key]): void;
keys(): IterableIterator<keyof ValueMap>;
values(): IterableIterator<ValueOf<ValueMap>>;
entries(): IterableIterator<[keyof ValueMap, ValueOf<ValueMap>]>;
[Symbol.iterator](): IterableIterator<[keyof ValueMap, ValueOf<ValueMap>]>;
}
export declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
export declare type UsageModel = "bundled" | "unbound";
export declare function usageModelExternalSubrequestLimit(model?: UsageModel): number;
export declare type ValueOf<T> = T[keyof T];
export declare function viewToArray(view: ArrayBufferView): Uint8Array;
export declare function viewToBuffer(view: ArrayBufferView): ArrayBuffer;
/**
* Waits for the context's input gate (if any) to be open before returning.
* Should be called before returning result of async I/O (e.g. setTimeout, KV).
*/
export declare function waitForOpenInputGate(): Awaitable<void>;
/**
* Waits for the context's output gate (if any) to be open before returning.
* Should be called before making async I/O requests (e.g. fetch, KV put)
* which may be using unconfirmed values.
*/
export declare function waitForOpenOutputGate(): Awaitable<void>;
/**
* Registers promise with context's output gate (if any) unless allowUnconfirmed
* is true. Should be called immediately (before any await) if returning a
* promise for a storage write operation.
*/
export declare function waitUntilOnOutputGate<T>(promise: Promise<any>, allowUnconfirmed?: boolean): Promise<T>;
export declare interface WranglerConfig extends WranglerEnvironmentConfig {
type?: "javascript" | "webpack" | "rust";
compatibility_date?: string;
compatibility_flags?: CompatibilityFlag[];
build?: {
command?: string;
cwd?: string;
watch_dir?: string | string[];
upload?: {
format?: "service-worker" | "modules";
dir?: string;
main?: string;
rules?: {
type: ModuleRuleType;
globs: string[];
fallthrough?: boolean;
}[];
};
};
env?: Record<string, WranglerEnvironmentConfig>;
}
export declare interface WranglerEnvironmentConfig {
name?: string;
zone_id?: string;
account_id?: string;
workers_dev?: boolean;
route?: RouteType;
routes?: RouteType[];
webpack_config?: string;
vars?: Record<string, any>;
kv_namespaces?: {
binding: string;
id?: string;
preview_id?: string;
}[];
d1_databases?: {
binding: string;
database_name: string;
database_id: string;
}[];
r2_buckets?: {
binding: string;
bucket_name?: string;
preview_bucket_name?: string;
}[];
site?: {
bucket: string;
"entry-point"?: string;
include?: string[];
exclude?: string[];
};
durable_objects?: {
bindings?: {
name: string;
class_name: string;
script_name?: string;
}[];
};
queues?: {
producers?: {
binding: string;
queue: string;
}[];
consumers?: {
queue: string;
batch_size?: number;
batch_timeout?: number;
message_retries?: number;
dead_letter_queue?: string;
}[];
};
triggers?: {
crons?: string[];
};
usage_model?: UsageModel;
wasm_modules?: Record<string, string>;
text_blobs?: Record<string, string>;
data_blobs?: Record<string, string>;
services?: WranglerServiceConfig[];
/** @deprecated Use `services` instead */
experimental_services?: WranglerServiceConfig[];
miniflare?: {
globals?: Record<string, any>;
upstream?: string;
watch?: boolean;
build_watch_dirs?: string[];
kv_persist?: boolean | string;
d1_persist?: boolean | string;
r2_persist?: boolean | string;
cache?: boolean;
cache_persist?: boolean | string;
durable_objects_persist?: boolean | string;
durable_objects_alarms?: boolean;
env_path?: string;
host?: string;
port?: number;
open?: boolean | string;
cf_fetch?: boolean | string;
https?: boolean | string | {
key?: string;
cert?: string;
ca?: string;
pfx?: string;
passphrase?: string;
};
live_reload?: boolean;
update_check?: boolean;
mounts?: Record<string, string>;
route?: RouteType;
routes?: RouteType[];
global_async_io?: boolean;
global_timers?: boolean;
global_random?: boolean;
actual_time?: boolean;
inaccurate_cpu?: boolean;
};
}
export declare interface WranglerServiceConfig {
/** @deprecated Use `binding` instead */
name?: string;
binding?: string;
service: string;
environment: string;
}
export { }